pax_global_header00006660000000000000000000000064142546752610014526gustar00rootroot0000000000000052 comment=e6e04d33b6a5143c9b1209057f60feefeefbb504 munge-munge-0.5.15/000077500000000000000000000000001425467526100140425ustar00rootroot00000000000000munge-munge-0.5.15/.gitarchive-date000066400000000000000000000000321425467526100170760ustar00rootroot000000000000002022-06-22 13:25:21 -0700 munge-munge-0.5.15/.gitarchive-hash000066400000000000000000000000111425467526100171010ustar00rootroot00000000000000e6e04d33 munge-munge-0.5.15/.gitattributes000066400000000000000000000000741425467526100167360ustar00rootroot00000000000000.gitarchive-date export-subst .gitarchive-hash export-subst munge-munge-0.5.15/.gitignore000066400000000000000000000016751425467526100160430ustar00rootroot00000000000000*.la *.lo *.log *.o *.trs .deps/ .libs/ /aclocal.m4 /autom4te.cache /build-aux/compile /build-aux/config.guess /build-aux/config.sub /build-aux/depcomp /build-aux/install-sh /build-aux/ltmain.sh /build-aux/missing /build-aux/tap-driver.sh /build-aux/test-driver /config.cache /config.h /config.h.in /config.h.in~ /config.log /config.status /configure /configure~ /libtool /m4/libtool.m4 /m4/ltoptions.m4 /m4/ltsugar.m4 /m4/ltversion.m4 /m4/lt~obsolete.m4 /munge-*.tar* /munge.spec /src/*/*.[1-9] /src/common/hkdf_api_test /src/common/hkdf_rfc_test /src/common/mac_test /src/etc/munge.logrotate.conf /src/etc/munge.pkgconfig.pc /src/etc/munge.systemd.service /src/etc/munge.systemd.sysconfig /src/etc/munge.sysvinit.init /src/etc/munge.sysvinit.sysconfig /src/etc/munge.tmpfiles.conf /src/munge/munge /src/munge/remunge /src/munge/unmunge /src/munged/base64_test /src/munged/munged /src/mungekey/mungekey /stamp-h1 /t/test-results/ Makefile Makefile.in TAGS munge-munge-0.5.15/AUTHORS000066400000000000000000000000401425467526100151040ustar00rootroot00000000000000Chris Dunlap munge-munge-0.5.15/COPYING000066400000000000000000001045131425467526100151010ustar00rootroot00000000000000 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 . munge-munge-0.5.15/COPYING.LESSER000066400000000000000000000167251425467526100161040ustar00rootroot00000000000000 GNU LESSER GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. This version of the GNU Lesser General Public License incorporates the terms and conditions of version 3 of the GNU General Public License, supplemented by the additional permissions listed below. 0. Additional Definitions. As used herein, "this License" refers to version 3 of the GNU Lesser General Public License, and the "GNU GPL" refers to version 3 of the GNU General Public License. "The Library" refers to a covered work governed by this License, other than an Application or a Combined Work as defined below. An "Application" is any work that makes use of an interface provided by the Library, but which is not otherwise based on the Library. Defining a subclass of a class defined by the Library is deemed a mode of using an interface provided by the Library. A "Combined Work" is a work produced by combining or linking an Application with the Library. The particular version of the Library with which the Combined Work was made is also called the "Linked Version". The "Minimal Corresponding Source" for a Combined Work means the Corresponding Source for the Combined Work, excluding any source code for portions of the Combined Work that, considered in isolation, are based on the Application, and not on the Linked Version. The "Corresponding Application Code" for a Combined Work means the object code and/or source code for the Application, including any data and utility programs needed for reproducing the Combined Work from the Application, but excluding the System Libraries of the Combined Work. 1. Exception to Section 3 of the GNU GPL. You may convey a covered work under sections 3 and 4 of this License without being bound by section 3 of the GNU GPL. 2. Conveying Modified Versions. If you modify a copy of the Library, and, in your modifications, a facility refers to a function or data to be supplied by an Application that uses the facility (other than as an argument passed when the facility is invoked), then you may convey a copy of the modified version: a) under this License, provided that you make a good faith effort to ensure that, in the event an Application does not supply the function or data, the facility still operates, and performs whatever part of its purpose remains meaningful, or b) under the GNU GPL, with none of the additional permissions of this License applicable to that copy. 3. Object Code Incorporating Material from Library Header Files. The object code form of an Application may incorporate material from a header file that is part of the Library. You may convey such object code under terms of your choice, provided that, if the incorporated material is not limited to numerical parameters, data structure layouts and accessors, or small macros, inline functions and templates (ten or fewer lines in length), you do both of the following: a) Give prominent notice with each copy of the object code that the Library is used in it and that the Library and its use are covered by this License. b) Accompany the object code with a copy of the GNU GPL and this license document. 4. Combined Works. You may convey a Combined Work under terms of your choice that, taken together, effectively do not restrict modification of the portions of the Library contained in the Combined Work and reverse engineering for debugging such modifications, if you also do each of the following: a) Give prominent notice with each copy of the Combined Work that the Library is used in it and that the Library and its use are covered by this License. b) Accompany the Combined Work with a copy of the GNU GPL and this license document. c) For a Combined Work that displays copyright notices during execution, include the copyright notice for the Library among these notices, as well as a reference directing the user to the copies of the GNU GPL and this license document. d) Do one of the following: 0) Convey the Minimal Corresponding Source under the terms of this License, and the Corresponding Application Code in a form suitable for, and under terms that permit, the user to recombine or relink the Application with a modified version of the Linked Version to produce a modified Combined Work, in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source. 1) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (a) uses at run time a copy of the Library already present on the user's computer system, and (b) will operate properly with a modified version of the Library that is interface-compatible with the Linked Version. e) Provide Installation Information, but only if you would otherwise be required to provide such information under section 6 of the GNU GPL, and only to the extent that such information is necessary to install and execute a modified version of the Combined Work produced by recombining or relinking the Application with a modified version of the Linked Version. (If you use option 4d0, the Installation Information must accompany the Minimal Corresponding Source and Corresponding Application Code. If you use option 4d1, you must provide the Installation Information in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source.) 5. Combined Libraries. You may place library facilities that are a work based on the Library side by side in a single library together with other library facilities that are not Applications and are not covered by this License, and convey such a combined library under terms of your choice, if you do both of the following: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities, conveyed under the terms of this License. b) Give prominent notice with the combined library that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 6. Revised Versions of the GNU Lesser General Public License. The Free Software Foundation may publish revised and/or new versions of the GNU Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library as you received it specifies that a certain numbered version of the GNU Lesser General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that published version or of any later version published by the Free Software Foundation. If the Library as you received it does not specify a version number of the GNU Lesser General Public License, you may choose any version of the GNU Lesser General Public License ever published by the Free Software Foundation. If the Library as you received it specifies that a proxy can decide whether future versions of the GNU Lesser General Public License shall apply, that proxy's public statement of acceptance of any version is permanent authorization for you to choose that version for the Library. munge-munge-0.5.15/DISCLAIMER.LLNS000066400000000000000000000025661425467526100161610ustar00rootroot00000000000000This work was produced at the Lawrence Livermore National Laboratory (LLNL) under Contract No. DE-AC52-07NA27344 (Contract 44) between the U.S. Department of Energy (DOE) and Lawrence Livermore National Security, LLC (LLNS) for the operation of LLNL. This work was prepared as an account of work sponsored by an agency of the United States Government. Neither the United States Government nor Lawrence Livermore National Security, LLC nor any of their employees, makes any warranty, express or implied, or assumes any liability or responsibility for the accuracy, completeness, or usefulness of any information, apparatus, product, or process disclosed, or represents that its use would not infringe privately-owned rights. Reference herein to any specific commercial products, process, or services by trade name, trademark, manufacturer or otherwise does not necessarily constitute or imply its endorsement, recommendation, or favoring by the United States Government or Lawrence Livermore National Security, LLC. The views and opinions of authors expressed herein do not necessarily state or reflect those of the Untied States Government or Lawrence Livermore National Security, LLC, and shall not be used for advertising or product endorsement purposes. The precise terms and conditions for copying, distribution, and modification are specified in the files "COPYING" and "COPYING.LESSER". munge-munge-0.5.15/DISCLAIMER.UC000066400000000000000000000023471425467526100157150ustar00rootroot00000000000000This notice is required to be provided under our contract with the U.S. Department of Energy (DOE). This work was produced at the University of California, Lawrence Livermore National Laboratory under Contract No. W-7405-ENG-48 with the DOE. Neither the United States Government nor the University of California nor any of their employees, makes any warranty, express or implied, or assumes any liability or responsibility for the accuracy, completeness, or usefulness of any information, apparatus, product, or process disclosed, or represents that its use would not infringe privately-owned rights. Also, reference herein to any specific commercial products, process, or services by trade name, trademark, manufacturer or otherwise does not necessarily constitute or imply its endorsement, recommendation, or favoring by the United States Government or the University of California. The views and opinions of authors expressed herein do not necessarily state or reflect those of the United States Government or the University of California, and shall not be used for advertising or product endorsement purposes. The precise terms and conditions for copying, distribution, and modification are specified in the files "COPYING" and "COPYING.LESSER". munge-munge-0.5.15/HISTORY000066400000000000000000000006221425467526100151260ustar00rootroot000000000000000.5.15 2022-06-22 0.5.14 2020-01-14 0.5.13 2017-09-26 0.5.12 2016-02-25 0.5.11 2013-08-27 0.5.10 2011-02-25 0.5.9 2010-03-23 0.5.8 2007-02-05 0.5.7 2006-12-23 0.5.6 2006-11-22 0.5.5 2006-11-14 0.5.4 2006-09-26 0.5.3 2006-05-17 0.5.2 2006-03-07 0.5.1 2006-02-28 0.5 2006-01-24 0.4.3 2005-10-31 0.4.2 2005-07-20 0.4.1 2004-12-21 0.4 2004-12-07 0.3 2004-04-30 0.2 2003-10-24 0.1 2003-04-30 0.0 2002-12-20 munge-munge-0.5.15/INSTALL000066400000000000000000000363321425467526100151020ustar00rootroot00000000000000Installation Instructions ************************* Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc. Copying and distribution of this file, with or without modification, are permitted in any medium without royalty provided the copyright notice and this notice are preserved. This file is offered as-is, without warranty of any kind. Basic Installation ================== Briefly, the shell commands `./configure; make; make install' should configure, build, and install this package. The following more-detailed instructions are generic; see the `README' file for instructions specific to this package. Some packages provide this `INSTALL' file but do not implement all of the features documented below. The lack of an optional feature in a given package is not necessarily a bug. More recommendations for GNU packages can be found in *note Makefile Conventions: (standards)Makefile Conventions. The `configure' shell script attempts to guess correct values for various system-dependent variables used during compilation. It uses those values to create a `Makefile' in each directory of the package. It may also create one or more `.h' files containing system-dependent definitions. Finally, it creates a shell script `config.status' that you can run in the future to recreate the current configuration, and a file `config.log' containing compiler output (useful mainly for debugging `configure'). It can also use an optional file (typically called `config.cache' and enabled with `--cache-file=config.cache' or simply `-C') that saves the results of its tests to speed up reconfiguring. Caching is disabled by default to prevent problems with accidental use of stale cache files. If you need to do unusual things to compile the package, please try to figure out how `configure' could check whether to do them, and mail diffs or instructions to the address given in the `README' so they can be considered for the next release. If you are using the cache, and at some point `config.cache' contains results you don't want to keep, you may remove or edit it. The file `configure.ac' (or `configure.in') is used to create `configure' by a program called `autoconf'. You need `configure.ac' if you want to change it or regenerate `configure' using a newer version of `autoconf'. The simplest way to compile this package is: 1. `cd' to the directory containing the package's source code and type `./configure' to configure the package for your system. Running `configure' might take a while. While running, it prints some messages telling which features it is checking for. 2. Type `make' to compile the package. 3. Optionally, type `make check' to run any self-tests that come with the package, generally using the just-built uninstalled binaries. 4. Type `make install' to install the programs and any data files and documentation. When installing into a prefix owned by root, it is recommended that the package be configured and built as a regular user, and only the `make install' phase executed with root privileges. 5. Optionally, type `make installcheck' to repeat any self-tests, but this time using the binaries in their final installed location. This target does not install anything. Running this target as a regular user, particularly if the prior `make install' required root privileges, verifies that the installation completed correctly. 6. You can remove the program binaries and object files from the source code directory by typing `make clean'. To also remove the files that `configure' created (so you can compile the package for a different kind of computer), type `make distclean'. There is also a `make maintainer-clean' target, but that is intended mainly for the package's developers. If you use it, you may have to get all sorts of other programs in order to regenerate files that came with the distribution. 7. Often, you can also type `make uninstall' to remove the installed files again. In practice, not all packages have tested that uninstallation works correctly, even though it is required by the GNU Coding Standards. 8. Some packages, particularly those that use Automake, provide `make distcheck', which can by used by developers to test that all other targets like `make install' and `make uninstall' work correctly. This target is generally not run by end users. Compilers and Options ===================== Some systems require unusual options for compilation or linking that the `configure' script does not know about. Run `./configure --help' for details on some of the pertinent environment variables. You can give `configure' initial values for configuration parameters by setting variables in the command line or in the environment. Here is an example: ./configure CC=c99 CFLAGS=-g LIBS=-lposix *Note Defining Variables::, for more details. Compiling For Multiple Architectures ==================================== You can compile the package for more than one kind of computer at the same time, by placing the object files for each architecture in their own directory. To do this, you can use GNU `make'. `cd' to the directory where you want the object files and executables to go and run the `configure' script. `configure' automatically checks for the source code in the directory that `configure' is in and in `..'. This is known as a "VPATH" build. With a non-GNU `make', it is safer to compile the package for one architecture at a time in the source code directory. After you have installed the package for one architecture, use `make distclean' before reconfiguring for another architecture. On MacOS X 10.5 and later systems, you can create libraries and executables that work on multiple system types--known as "fat" or "universal" binaries--by specifying multiple `-arch' options to the compiler but only a single `-arch' option to the preprocessor. Like this: ./configure CC="gcc -arch i386 -arch x86_64 -arch ppc -arch ppc64" \ CXX="g++ -arch i386 -arch x86_64 -arch ppc -arch ppc64" \ CPP="gcc -E" CXXCPP="g++ -E" This is not guaranteed to produce working output in all cases, you may have to build one architecture at a time and combine the results using the `lipo' tool if you have problems. Installation Names ================== By default, `make install' installs the package's commands under `/usr/local/bin', include files under `/usr/local/include', etc. You can specify an installation prefix other than `/usr/local' by giving `configure' the option `--prefix=PREFIX', where PREFIX must be an absolute file name. You can specify separate installation prefixes for architecture-specific files and architecture-independent files. If you pass the option `--exec-prefix=PREFIX' to `configure', the package uses PREFIX as the prefix for installing programs and libraries. Documentation and other data files still use the regular prefix. In addition, if you use an unusual directory layout you can give options like `--bindir=DIR' to specify different values for particular kinds of files. Run `configure --help' for a list of the directories you can set and what kinds of files go in them. In general, the default for these options is expressed in terms of `${prefix}', so that specifying just `--prefix' will affect all of the other directory specifications that were not explicitly provided. The most portable way to affect installation locations is to pass the correct locations to `configure'; however, many packages provide one or both of the following shortcuts of passing variable assignments to the `make install' command line to change installation locations without having to reconfigure or recompile. The first method involves providing an override variable for each affected directory. For example, `make install prefix=/alternate/directory' will choose an alternate location for all directory configuration variables that were expressed in terms of `${prefix}'. Any directories that were specified during `configure', but not in terms of `${prefix}', must each be overridden at install time for the entire installation to be relocated. The approach of makefile variable overrides for each directory variable is required by the GNU Coding Standards, and ideally causes no recompilation. However, some platforms have known limitations with the semantics of shared libraries that end up requiring recompilation when using this method, particularly noticeable in packages that use GNU Libtool. The second method involves providing the `DESTDIR' variable. For example, `make install DESTDIR=/alternate/directory' will prepend `/alternate/directory' before all installation names. The approach of `DESTDIR' overrides is not required by the GNU Coding Standards, and does not work on platforms that have drive letters. On the other hand, it does better at avoiding recompilation issues, and works well even when some directory options were not specified in terms of `${prefix}' at `configure' time. Optional Features ================= If the package supports it, you can cause programs to be installed with an extra prefix or suffix on their names by giving `configure' the option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. Some packages pay attention to `--enable-FEATURE' options to `configure', where FEATURE indicates an optional part of the package. They may also pay attention to `--with-PACKAGE' options, where PACKAGE is something like `gnu-as' or `x' (for the X Window System). The `README' should mention any `--enable-' and `--with-' options that the package recognizes. For packages that use the X Window System, `configure' can usually find the X include and library files automatically, but if it doesn't, you can use the `configure' options `--x-includes=DIR' and `--x-libraries=DIR' to specify their locations. Some packages offer the ability to configure how verbose the execution of `make' will be. For these packages, running `./configure --enable-silent-rules' sets the default to minimal output, which can be overridden with `make V=1'; while running `./configure --disable-silent-rules' sets the default to verbose, which can be overridden with `make V=0'. Particular systems ================== On HP-UX, the default C compiler is not ANSI C compatible. If GNU CC is not installed, it is recommended to use the following options in order to use an ANSI C compiler: ./configure CC="cc -Ae -D_XOPEN_SOURCE=500" and if that doesn't work, install pre-built binaries of GCC for HP-UX. On OSF/1 a.k.a. Tru64, some versions of the default C compiler cannot parse its `' header file. The option `-nodtk' can be used as a workaround. If GNU CC is not installed, it is therefore recommended to try ./configure CC="cc" and if that doesn't work, try ./configure CC="cc -nodtk" On Solaris, don't put `/usr/ucb' early in your `PATH'. This directory contains several dysfunctional programs; working variants of these programs are available in `/usr/bin'. So, if you need `/usr/ucb' in your `PATH', put it _after_ `/usr/bin'. On Haiku, software installed for all users goes in `/boot/common', not `/usr/local'. It is recommended to use the following options: ./configure --prefix=/boot/common Specifying the System Type ========================== There may be some features `configure' cannot figure out automatically, but needs to determine by the type of machine the package will run on. Usually, assuming the package is built to be run on the _same_ architectures, `configure' can figure that out, but if it prints a message saying it cannot guess the machine type, give it the `--build=TYPE' option. TYPE can either be a short name for the system type, such as `sun4', or a canonical name which has the form: CPU-COMPANY-SYSTEM where SYSTEM can have one of these forms: OS KERNEL-OS See the file `config.sub' for the possible values of each field. If `config.sub' isn't included in this package, then this package doesn't need to know the machine type. If you are _building_ compiler tools for cross-compiling, you should use the option `--target=TYPE' to select the type of system they will produce code for. If you want to _use_ a cross compiler, that generates code for a platform different from the build platform, you should specify the "host" platform (i.e., that on which the generated programs will eventually be run) with `--host=TYPE'. Sharing Defaults ================ If you want to set default values for `configure' scripts to share, you can create a site shell script called `config.site' that gives default values for variables like `CC', `cache_file', and `prefix'. `configure' looks for `PREFIX/share/config.site' if it exists, then `PREFIX/etc/config.site' if it exists. Or, you can set the `CONFIG_SITE' environment variable to the location of the site script. A warning: not all `configure' scripts look for a site script. Defining Variables ================== Variables not defined in a site shell script can be set in the environment passed to `configure'. However, some packages may run configure again during the build, and the customized values of these variables may be lost. In order to avoid this problem, you should set them in the `configure' command line, using `VAR=value'. For example: ./configure CC=/usr/local2/bin/gcc causes the specified `gcc' to be used as the C compiler (unless it is overridden in the site shell script). Unfortunately, this technique does not work for `CONFIG_SHELL' due to an Autoconf bug. Until the bug is fixed you can use this workaround: CONFIG_SHELL=/bin/bash /bin/bash ./configure CONFIG_SHELL=/bin/bash `configure' Invocation ====================== `configure' recognizes the following options to control how it operates. `--help' `-h' Print a summary of all of the options to `configure', and exit. `--help=short' `--help=recursive' Print a summary of the options unique to this package's `configure', and exit. The `short' variant lists options used only in the top level, while the `recursive' variant lists options also present in any nested packages. `--version' `-V' Print the version of Autoconf used to generate the `configure' script, and exit. `--cache-file=FILE' Enable the cache: use and save the results of the tests in FILE, traditionally `config.cache'. FILE defaults to `/dev/null' to disable caching. `--config-cache' `-C' Alias for `--cache-file=config.cache'. `--quiet' `--silent' `-q' Do not print messages saying which checks are being made. To suppress all normal output, redirect it to `/dev/null' (any error messages will still be shown). `--srcdir=DIR' Look for the package's source code in directory DIR. Usually `configure' can determine that directory automatically. `--prefix=DIR' Use DIR as the installation prefix. *note Installation Names:: for more details, including other options available for fine-tuning the installation locations. `--no-create' `-n' Run the configure checks, but stop before creating any output files. `configure' also accepts some other, not widely useful, options. Run `configure --help' for more details. munge-munge-0.5.15/JARGON000066400000000000000000000005171425467526100147500ustar00rootroot00000000000000munge /muhnj/ vt. 1. [derogatory] To imperfectly transform information. 2. A comprehensive rewrite of a routine, data structure or the whole program. 3. To modify data in some way the speaker doesn't need to go into right now or cannot describe succinctly (compare mumble). munge-munge-0.5.15/KEYS000066400000000000000000000117341425467526100145460ustar00rootroot00000000000000pub rsa4096/0x3B7ECB2B30DE0871 2011-10-01 [SC] Key fingerprint = A441 880C 3D4C 7C36 C5DD 41E1 3B7E CB2B 30DE 0871 uid [ultimate] Chris Dunlap uid [ultimate] Chris Dunlap uid [ultimate] Chris Dunlap sub rsa4096/0x48A5CADDECA74B8A 2011-10-01 [E] -----BEGIN PGP PUBLIC KEY BLOCK----- mQINBE6HRzwBEADIP0Sl4/O7f2OKrYit3/NaF8wCTgbByyYiE9f874HpHtyTnxt5 09vkd/dB/QgTuqnFZtCoIOR9QhWmJW8DuVBxd9Uq1twIOXUQ1b1aa2T66DjfMkF8 YAmWRIrJGfq1T7viEyLEc0jCvO6kB9danN60/BXt5gxJcvH53itacuymhHwtFyjx juuP9z8b8VMUY2kWziytxNRhc2S4WA9LxLrK5uodG+4eEE/qf3w7ViIOI8JU+4tx rzaIsfWLN3iQ3uv3Bdfa+Iq1nEXeLK0eDYO8DNGr/Qx849YYzK1Z+VPLZDNB7Y1s 5ahNFiUqBn+O+uL2qwqTY4czpqBB1oafkpXfth6B6LyySR2BaG/SoAm09fS7egjp +IG2ujixvb4JcN7p8LePZsn0Ir74h2QURF9yyOHFJHQwhwrNuyK34XCsiz1rVp54 eC2D1NaA2rS3ZH7gJE5toG4BXkOX26p9xUGZfO6DiDNFJd4Q7OJLctmmwdug5jIC OSRmU/JvRq5XjnsVTmlS6rKiiKXUNslND44uSQgZiUjTBAzNu8CsfImui0pozPvA I7Rbe4U8erg4kCpyo27JoLcEpz2xhk80GYwdMCllGlc2AezUEHXBiSoSNIGehiGM ZYXD1jnkU0IMQRk+sg9QnOCAeYQv1fXZYvIfOkqOJ33/3dHdJQGaTnljsQARAQAB tCdDaHJpcyBEdW5sYXAgPGNocmlzLm0uZHVubGFwQGdtYWlsLmNvbT6JAjoEEwEI ACQCGwMFCwkIBwMFFQoJCAsFFgIDAQACHgECF4AFAk6Hhh8CGQEACgkQO37LKzDe CHFDnRAAkiiYIv3fnttmdk7ENOPOLiJfHNLvDJBVY6QPs8BFkMUpsWhJ0PRmKESK 0JQh0pjAGx7NPXFzApNZHRsRkrD2eJmPAxZteiOYy9bwq110gEnpxf0lzV/KMMKi IAyPbL5x5pc56a0ym066BzYZZkspfGTc++eXQlGLkm8FkYyrg/PltzDxDmTVpCkS shMC1CbKiR5YLlbBF1g6WSdZWWdtSKQt7TipJr2+DkFR9C+GAwYn/YukizfHYSnm NzzSRVCSOaY9b+MoZ7pdnqCqFBVgbLtm2o0otJAHQjydpAqNn4A2ci1z5E7E1+Pe wCfC7d8DFtavikdvsYNyu8a9zgyIxfxdFZdNnwVXSl3NnkstNbSMiYQN2fqcoIGa 1mXpe+zTV90xghT9ESfI3WHH3c42igOQxACEDH2QyB4ze6E6UOboeL0ghbb82VW7 nV0waRwyP29jGILZi3PlOmSO2SX4SM+ivxaH/XXvXYcPUFI1vIcCDfN9fTNvwZE8 MK2UxQs1rdJVEO1fxH8ie8XLDMHA4g/f9QJ7NcYSWWDN/NQGT+rzcUVAYf2q0JC/ LUvugIudl/9sVNxo6uGzR73QvDVmzrR7n5J0ENckfDq/II0AbWiw1jNzeY49qv+C jlxnEDc1vQt93Xz4xSLtd/LYysSeOvUJ21Gk4WqTrHuEI8l/tIW0H0NocmlzIER1 bmxhcCA8Y2R1bmxhcEBsbG5sLmdvdj6JAjcEEwEIACEFAk6HhlICGwMFCwkIBwMF FQoJCAsFFgIDAQACHgECF4AACgkQO37LKzDeCHHFwg/9GjfrLKTSmOFW9XSYA53j ZtoUmQfA5l4nLH9FeOjDzkektQrBnPRFTtbi62MMCLaqt8jLfLTs0C5tELNGkUug 1Fmj/B4ycdGXAx2Yjo35kEefmiXVEmkCWMYl49EGg/cUA18uVSMIeJNwB8IvNtbk 7CApjM2h5z+0Jt37wiVZjpfkGIc+76hXaLdp09QxybAgUQBDy3bwk793SRzqb9+X vSeBdVukMklZdB8zsooyxq49nEx48zjym7uoWSpqU9097mOBHpUUHB/4b+L95cU6 OYMlzW3dZ7znPr+kgCUatoFOEMzawXU+eSJ/k1jpmkC8RuLitqb5di6ddKyJfYcU dBepD+f7CxGdo9yMtAh4+9PmCIwpRW1M6FmwaSs/X21P3gi3H4uQ5zdBrmwYoeYE ywLvQyKNbC8DcK/bjnpp2ymZ32x3ovK/QOd7b9OJYZSSzMN5fyboGtkSQWsxxwDJ vVLToMGmZ0A4Xsf65MZ9HhFzRvT/nvOIAb5yz/lzutVp7osnwsJiRboHrhCjfx23 d8/tvZ69JF5zy6/sT0D+QZLT0o6aryfPKFLCvpcoPBxY+J0p1fI5lVNvzIu6Eq14 tGQwJt4ErEm+HM5XwN/g3BKQF7liWatQOQN7DzCuVpgomoMfKkk41jYcOq83DfMT JZyycJ0/IgUUBo8tJm7rJJu0G0NocmlzIER1bmxhcCA8ZHVuQGltc2EuZWR1PokC NwQTAQgAIQUCToeGaQIbAwULCQgHAwUVCgkICwUWAgMBAAIeAQIXgAAKCRA7fssr MN4IcXTUD/48qwiJO2I7RYsjqOnSmoXDgGrCQzLH1pxQ9DEIkR+Zp129+egGcMvZ 9962fEGP1ObJQ3veHDSANCcvRGm2RcLHDWzXHO18RK0k9x1y6xsp3/In67cm3Q5T +FOL+axKw0GGfJgzYrTyNu3IZzeIb13nexnbFJc9bDeV0xcDvhH0QAci5kh90eH6 fX609jPhXWNj7YUKdT1wzNnOGo7YEZqk+IsSIMc1lRitnYQR4dkht7qq3Z/SjwJe 25wH/jr7cqvm+zKzDTH9r7LTSN9locCl/kcTdzsV+R9Bzo506asb1VT5oaYIhJzA UyVenC2Jxt/TlE5HeLxUjHW5oE5hFRs11jsNDmIlwME4FRYjrnbCU2an1VY1IXzw hSHT4LuZBlNs56JXVUFYBlYSr0foyXmf1d272gjNae0gGqCBee8ZJbk12ByYl6hz Wzd+DkgXszdKjZYtWDGpRmgs9AHyktMgRgLxF2iyT961T1BmiGDVo7oaIHjsnRTa akthpBhmtQN2bJnij+rGzKeMWGKNl0y2cwiyU03Zgc10bBfyqBt9xxE54gtk/s9V 3K/JcQK5wMcV1CSN57QRVv2h21C3qg36x3SC2eejoXPxyIxYJBSR8PIWfEA2uyW+ NyL8XqgI4AwwY1Sm2YjhMdIi8zTAZjWLUJRyJQXM05n5OXigElEZp7kCDQROh0c8 ARAA1k0191r/gRb7bizBxp1dT3iLotFIUJAfATwgGJLFQWX7KZS+h17ENgkAMMoL 9ZZc5j7h8f2pHobRq0kikPpv/FYwXMC0xHRhxDibr8SfW/5w9gn8xpsuEE7BQrBY OyvawuOChpWUkSfa78QgfsU/880FPlE4MR3Zkieq4xha/P6sUwBYvzH7aTb2sa7x CaFLrGTvZBhNLOqG+N6HOiIJZbyekhEDJHTfj3RZDEiIQtPIVBUIywXRgBww9Jtt RH6v+A7CmtG6H19gPt8GNVWVCdsd0SCUauXtL4d09Wdz1YFZ013PmqLTDIZcrWVa d9VZbLgeFJI8B+CE58x/imzq/TnUbI3/gamP8j3VlyBMcwWlTy5YwaC6ueN4aNyj 5QlRvoFTe98EQnReSnAbAPAyBuK2ezGuwhfyCECNYPBGou4P1TzN1cKQYGnARLoV CIzWIRmqmL9D7/BCbLqM28oRdzpMRILParsBMZJHIUvuXZGrua5yU1NOFRMdRVKi B8lMW2dd3WG89KyL/Bg8xk9HN4GxCUTvtAoeY/sCOR4P4N1a7Jq4VxvFQ8vakGgL 40RV/wwnZ4ZyDknkSPuDqsqTKD3PfXFDMBzPCoN436MGLeMtBwE2mBYPjsE2RANY pQHupPLStPOJ5fS0uIZHQa+b4/LiVueUBGjUtbm92duH0OcAEQEAAYkCHwQYAQgA CQUCTodHPAIbDAAKCRA7fssrMN4IcSeqEACApzYyIaIruviRG4xERbSSaj17d0xt sf4cjvC3jg5bQlDSZlR84aiRUwrtcBC0RBs9zHY40h+y5SMrhzv+dS4r/TxwmE+l hfP7bUOYCa2sBZZh6wvKxjMQPeCHwHqJ+pQiohhU4d5sYQdvhPRwJifd7mBSbFja 0kxfhGt6hTx2aBqv17WOhCVEp5mOkOtiwkacRmDqUOCKBkme2iT9wV4Bu3pbZ/Lz P1hwVqardPDtsq1PK7wueQREX0JVE7fJjMkWKnyIfGuLe/HKPhFOmnO6IODLuwcl jGH2MSWJbyQ46/Wvp39Ysk0TSiUgnjHPp11cn0FuK/BIQ9w36MCXhqDACHTO4Fcl rO27+ykaveAJ9i3kwGFx0W3Z5UhlyYkAc5FphJceCxyfgfyVuowb+BQTTAJm3jjB LFe5H4LNAhpIRIc/7fNeh1bZbFhlvMC7S6UAfOTIbwUC418DP/60n57yD77H9QCV nAd+Hkz3xTMfY3Wky00VQUWATFTTULGTX8UxUGonILvAqRk3ag/ZYtihbXmZ6yHu XtR23GEcDczykr1uYLXTGiHexU02/FO/cJCUx3/oR+iRLtGVEbm+YMKF44/Bh81k ms8Nanj2xRtGYHUQvPsvn/6brjdO+CXbQmk8SMRfdMf67zhj51lsaXgMZyKOjmzQ 1fi114xbZeLq0Q== =te3z -----END PGP PUBLIC KEY BLOCK----- munge-munge-0.5.15/Make-inc.mk000066400000000000000000000042721425467526100160240ustar00rootroot00000000000000# MUNGE Make-inc.mk # # This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE). # For details, see . # Dependencies to ensure libraries get rebuilt. # $(top_builddir)/src/libcommon/libcommon.la \ $(top_builddir)/src/libmissing/libmissing.la \ $(top_builddir)/src/libmunge/libmunge.la \ $(top_builddir)/src/libtap/libtap.la \ : force-dependency-check @cd `dirname $@` && $(MAKE) $(AM_MAKEFLAGS) `basename $@` force-dependency-check: # Generic 'distclean' hook. # # The double-colon allows this target to be defined multiple times, # thereby allowing a Makefile.am to include its own distclean-local hook. # distclean-local:: -rm -f *~ \#* .\#* cscope*.out core core.* tags TAGS # Perform autoconf-style variable substitution on stdin. # Fully expands autoconf variables that depend on other autoconf variables. # substitute = $(SED) \ -e 's|[@]bindir[@]|$(bindir)|g' \ -e 's|[@]datadir[@]|$(datadir)|g' \ -e 's|[@]datarootdir[@]|$(datarootdir)|g' \ -e 's|[@]docdir[@]|$(docdir)|g' \ -e 's|[@]dvidir[@]|$(dvidir)|g' \ -e 's|[@]exec_prefix[@]|$(exec_prefix)|g' \ -e 's|[@]htmldir[@]|$(htmldir)|g' \ -e 's|[@]includedir[@]|$(includedir)|g' \ -e 's|[@]infodir[@]|$(infodir)|g' \ -e 's|[@]libdir[@]|$(libdir)|g' \ -e 's|[@]libexecdir[@]|$(libexecdir)|g' \ -e 's|[@]localedir[@]|$(localedir)|g' \ -e 's|[@]localstatedir[@]|$(localstatedir)|g' \ -e 's|[@]mandir[@]|$(mandir)|g' \ -e 's|[@]oldincludedir[@]|$(oldincludedir)|g' \ -e 's|[@]pdfdir[@]|$(pdfdir)|g' \ -e 's|[@]pkgconfigdir[@]|$(pkgconfigdir)|g' \ -e 's|[@]pkgdatadir[@]|$(pkgdatadir)|g' \ -e 's|[@]pkgincludedir[@]|$(pkgincludedir)|g' \ -e 's|[@]pkglibdir[@]|$(pkglibdir)|g' \ -e 's|[@]pkglibexecdir[@]|$(pkglibexecdir)|g' \ -e 's|[@]prefix[@]|$(prefix)|g' \ -e 's|[@]psdir[@]|$(psdir)|g' \ -e 's|[@]runstatedir[@]|$(runstatedir)|g' \ -e 's|[@]sbindir[@]|$(sbindir)|g' \ -e 's|[@]sharedstatedir[@]|$(sharedstatedir)|g' \ -e 's|[@]sysconfdir[@]|$(sysconfdir)|g' \ -e 's|[@]sysconfigdir[@]|$(sysconfigdir)|g' \ -e 's|[@]systemdunitdir[@]|$(systemdunitdir)|g' \ -e 's|[@]sysvinitddir[@]|$(sysvinitddir)|g' \ -e 's|[@]DATE[@]|$(DATE)|g' \ -e 's|[@]PACKAGE[@]|$(PACKAGE)|g' \ -e 's|[@]VERSION[@]|$(VERSION)|g' munge-munge-0.5.15/Makefile.am000066400000000000000000000034711425467526100161030ustar00rootroot00000000000000# MUNGE top-level Makefile.am # # This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE). # For details, see . include $(top_srcdir)/Make-inc.mk ACLOCAL_AMFLAGS = -I m4 SUBDIRS = \ src \ t \ # End of SUBDIRS EXTRA_DIST = \ .gitignore \ AUTHORS \ COPYING \ COPYING.LESSER \ DISCLAIMER.LLNS \ DISCLAIMER.UC \ HISTORY \ INSTALL \ JARGON \ KEYS \ NEWS \ PLATFORMS \ QUICKSTART \ README \ README.AIX \ README.MULTILIB \ THANKS \ bootstrap \ build-aux/gen-date \ build-aux/gen-version \ build-aux/tap-driver.sh.bak \ doc \ $(TEMPLATE_FILES) \ # End of EXTRA_DIST DISTCLEANFILES = \ config/*~ \ $(PACKAGE)-*.tar* \ # End of DISTCLEANFILES MAINTAINERCLEANFILES = \ Makefile.in \ aclocal.m4 \ build-aux/compile \ build-aux/config.guess \ build-aux/config.sub \ build-aux/depcomp \ build-aux/install-sh \ build-aux/ltmain.sh \ build-aux/missing \ build-aux/tap-driver.sh \ build-aux/test-driver \ config.h.in \ configure \ m4/libtool.m4 \ m4/ltoptions.m4 \ m4/ltsugar.m4 \ m4/ltversion.m4 \ m4/lt~obsolete.m4 \ src/Makefile.in \ src/etc/Makefile.in \ src/libcommon/Makefile.in \ src/libmissing/Makefile.in \ src/libmunge/Makefile.in \ src/munge/Makefile.in \ src/munged/Makefile.in \ t/Makefile.in \ # End of MAINTAINERCLEANFILES TEMPLATE_FILES = \ munge.spec.in \ # End of TEMPLATE_FILES SUBSTITUTE_FILES = \ munge.spec \ # End of SUBSTITUTE_FILES CLEANFILES = \ $(SUBSTITUTE_FILES) \ # End of CLEANFILES $(SUBSTITUTE_FILES): Makefile $(AM_V_GEN)$(substitute) < '$(srcdir)/$@.in' > '$(builddir)/$@' munge.spec: munge.spec.in noinst_DATA = \ $(SUBSTITUTE_FILES) \ # End of noinst_DATA dist-hook: munge.spec $(INSTALL_DATA) munge.spec '$(distdir)/munge.spec' echo $(VERSION) > '$(distdir)/.dist-version' echo $(DATE) > '$(distdir)/.dist-date' munge-munge-0.5.15/NEWS000066400000000000000000000233111425467526100145410ustar00rootroot00000000000000munge-0.5.15 (2022-06-22): - Added support for OpenSSL 3.0. (#110) - Fixed "make install" conflict with systemd RuntimeDirectory. (#82) - Fixed big-endian bug causing failures on s390x. (#91) - Fixed systemd service unit conf to wait until network is online. (#93) - Fixed excessive logging of "suspended new connections". (#94) - Fixed test suite failure for origin addr on Debian kfreebsd-i386. (77ff682) - Fixed gcry_check_version(GCRYPT_VERSION) bug reported by Debian. (0c37cc0) - Fixed sending repeated SIGTERMs to signal stop. (dbe6dcc) - Fixed bugs where unlink() could be interrupted by signals on FreeBSD. (be183e2) - Fixed failure to clean up socket or create seedfile having relative path. (1245cd3) - Fixed test suite to clean up errant processes from failed tests. (7baed04) - Fixed rpm not creating "/run/munge" directory on CentOS 7. (5f3b1bf) munge-0.5.14 (2020-01-14): - Added mungekey command for key generation via HKDF. (5fc870e) - Added negative caching of user lookups for processing supplementary groups. (#26, d51fec8) - Added munged --origin cmdline opt. (#69, #23) - Added munged --stop cmdline opt. (06306b8) - Added unmunge --numeric cmdline opt. (171abe2) - Added configure --with-logrotateddir opt and logrotate config. (2d35713) - Added configure --with-munge-socket opt. (565db69) - Added configure --with-pkgconfigdir opt. (9abebcd) - Added configure --with-runstatedir opt. (25eef52) - Added configure --with-sysconfigdir opt. (9abebcd) - Added configure --with-systemdunitdir opt. (9abebcd) - Added configure --with-sysvinitddir opt. (9abebcd) - Added systemd EnvironmentFile to set sysconfig options. (#68, #64) - Added systemd RuntimeDirectory to replace tmpfiles.d conf. (3eed37e) - Added GPG verification of source to RPM specfile. (5bb8912, 24f18a1) - Added "make check" test suite. - Changed logging of non-existent users to only log once for a given user. (#26, 7b00d81) - Changed default name of munged seedfile. (df8c22a) - Fixed pidfile corruption when starting new daemon while socket still in use. (258b67e) - Fixed munged signal handlers to be async-signal-safe. (be39512) - Fixed "Logging stopped due to error" behavior for transient errors. (6176b42) - Fixed misleading "Lockfile not found" error message. (34fcdb6) - Fixed conversion-specifier / argument mismatch in error message. (0079630) - Fixed installation directory variable substitution. (2affe07) - Fixed manpage variable substitution. (a8ff2fe) - Removed autotools-generated files from version control. (46dd77b) munge-0.5.13 (2017-09-26): - Added support for OpenSSL 1.1.0. (#54) - Added support for UID/GID values >= 2^31. - Added support for getentropy() and getrandom(). - Added --trusted-group cmdline opt to munged. - Added --log-file and --seed-file cmdline opts to munged. (#57) - Changed default MAC algorithm to SHA-256. - Fixed autoconf installation directory variable substitution. (#47) - Fixed all gcc, clang, and valgrind warnings. - Improved resilience and unpredictability of PRNG. - Improved hash table performance. - Removed libmissing dependency from libmunge. (#49) munge-0.5.12 (2016-02-25): - Changed project homepage to . - Changed RPM specfile from sysvinit to systemd. (#33) - Added --max-ttl cmdline opt to munged. (#28) - Added --pid-file cmdline opt to munged. (#41) - Added support for "make dist" and "make distcheck". (#45) - Fixed group-writable permissions error for logfile on Ubuntu. (#31) - Fixed packaging with missing pkgconfig munge.pc file. (#25) - Fixed packaging with missing systemd service & tmpfiles.d config. (#34) - Fixed recursive make command in makefiles. (#40) munge-0.5.11 (2013-08-27): - Added --mlockall cmdline opt to munged. - Added --syslog cmdline opt to munged. - Added --uid and --gid cmdline opts to munge. - Added numeric timezone to unmunge timestamp output. - Added timer to munged for periodically stirring PRNG entropy pool. - Added support for pkg-config. - Added support for systemd. - Changed timer thread to better accommodate misbehaving system clocks. - Changed behavior of munge --string cmdline opt to not append newline. - Changed init script chkconfig priority levels to start after ntpd/ntpdate. - Changed init script so munged runs as munge user by default. - Fixed HMAC validation timing attack vulnerability. - Fixed bug with munged being unable to restart if daemon not cleanly shutdown. - Fixed bug with large groups triggering "numerical result out of range" error. - Fixed bug causing high CPU utilization on FreeBSD when processing group info. - Fixed bug causing IPv6-only hosts to exit due to failed hostname resolution. - Fixed autoconf check that was not portable across shells. - Fixed init script LSB Header on openSUSE. - Replaced perl build-time dependency with awk. munge-0.5.10 (2011-02-25): - Changed project homepage to . - Fixed bug where munged could deadlock if clients blocked. - Fixed bug where munged could crash while processing supplementary groups. - Fixed bug with CFLAGS at configure-time nullifying --enable-debug. - Fixed bug with VPATH builds failing to install init script. - Fixed RPM spec file for openSUSE & SLES. munge-0.5.9 (2010-03-23): - Changed license to GPLv3+/LGPLv3+. - Fixed bug with failed Linux builds under glibc-2.8+. - Fixed bug with failed daemon starts after clearing /var/run. - Moved selection of authentication method into configure script. - Added support for LOCAL_PEERCRED auth (Darwin, FreeBSD, GNU/kFreeBSD). - Added support for SHA-512 message digest. munge-0.5.8 (2007-02-05): - Fixed bug causing stack corruption on amd64 when using Libgcrypt. munge-0.5.7 (2006-12-23): - Improved performance of caching supplementary group info. - Added munged sighup handler to update supplementary group info. - Added --group-check-mtime and --group-update-time cmdline opts to munged. - Made errors at exit nonfatal to work around Debian libc6 bug #400960. munge-0.5.6 (2006-11-22): - Fixed bug causing build using Libgcrypt to fail without OpenSSL headers. munge-0.5.5 (2006-11-14): - Added support for Libgcrypt. - Added support for AES-256 cipher. - Added support for SHA-256 message digest. - Added check for minimum key length. - Reduced replay cache memory usage. munge-0.5.4 (2006-09-26): - Changed project homepage to . - Fixed bug leaking credential information on decode error. - Fixed bug preventing munged from terminating on various platforms. - Fixed bug building 32-bit & 64-bit libs on AIX with gcc. - Fixed RPM spec file so both shared & static libs are built on AIX. - Changed RPM spec file to create munge.key during install if not found. - Changed munged behavior to return fatal errors to shell if possible. - Changed init script so munged runs as daemon user instead of root. - Changed default paths to allow munged to own its directories. - Changed ownership & permissions of munged directories. - Added ownership & permission checks for files & directories. - Added compile-time defaults to munged help message. - Added support for SunOS 5.10 (getpeerucred). - Added support for Darwin (Mac OS X). - Improved security of file-descriptor-passing authentication mechanism. - Replaced --auth-pipe-dir with --auth-server-dir & --auth-client-dir opts. munge-0.5.3 (2006-05-17): - Added pidfile. - Improved multilib support for AIX. - Added support for AIX (32-bit, 64-bit, multiarch) to RPM spec file. - Added support for configure installation dir vars to alter defaults. - Added support for AIX, Debian, FreeBSD, and SunOS to init script. munge-0.5.2 (2006-03-07): - Fixed RPM spec file so munge-devel & munge-libs files are properly perm'd. munge-0.5.1 (2006-02-28): - Changed created logfile permissions to 640. munge-0.5 (2006-01-24): - Added multilib support. - Fixed bug with credential compression header not being protected by MAC. - Changed credential format to v3. - Changed client/server protocol (apps will need to relink). - Fixed miscellaneous bugs. - Changed default cipher to AES-128 if present. munge-0.4.3 (2005-10-31): - Fixed init script to work with RedHat's RHEL4-U1 chkconfig. munge-0.4.2 (2005-07-20): - Updated default paths to comply with the Filesystem Hierarchy Standard. - Fixed libtool bug causing libmunge to be incorrectly linked on AIX. - Fixed init script start behavior on RedHat. - Added munge-devel & munge-libs RPM subpackages. munge-0.4.1 (2004-12-21): - Fixed bug in init script preventing chkconfig from setting priorities. munge-0.4 (2004-12-07): - Added persistent pool of threads. - Added retry for failed requests. - Added libtool version-info. - Added --key-file, --num-threads, and --auth-pipe-dir cmdline opts to munged. - Added munge_ctx opt to limit maximum request length. - Added timer to periodically re-parse group info. - Added remunge benchmark/stress-test utility. - Added munge enums (munge_enum). - Added manpages. - Added support for configure to locate OpenSSL installation. - Added support for file-descriptor-passing over ramdisks. - Added support for SuSE/LSB to init script. - Added support for C++. - Improved support for AIX. - Optimized memory usage. - Optimized performance. - Changed libmunge.so to only export public symbols. - Changed client/server protocol (apps will need to relink). munge-0.3 (2004-04-30): - Added support for AIX, FreeBSD, and SunOS. - Added compression (bzlib, zlib). - Added replay detection/prevention. - Added ability to restrict decoding based on UID/GID. - Changed credential format to v2. - Changed client/server protocol. munge-0.2 (2003-10-24): - Added support for ia64. - Added TTL and origin IP address to credential header. munge-0.1 (2003-04-30): - Added full client/server support. - Added full cryptographic support. - Added munge contexts (munge_ctx). munge-0.0 (2002-12-20): - Initial support for munge_encode, munge_decode, and munge_strerror. munge-munge-0.5.15/PLATFORMS000066400000000000000000000015761425467526100153450ustar00rootroot00000000000000MUNGE 0.5.15 has been built and tested on the following systems: - AlmaLinux 9.0, 8.6 - Arch Linux - CentOS Linux Stream 9, Stream 8, 8.5.2111, 7.9.2009, 6.10 - Debian GNU/kFreeBSD bookworm/sid [amd64, i386] - Debian GNU/Linux sid, 11.3, 10.12, 9.13, 8.11, 7.11, 6.0.10, 5.0.10, 4.0 - Fedora Linux 36, 35, 34 - FreeBSD 13.1, 13.0, 12.3 - NetBSD 9.2, 9.1, 9.0 - OpenBSD 7.1, 7.0, 6.9 - openSUSE Leap 15.4, 15.3, 15.2, 15.1 - Raspbian GNU/Linux 10.12 [armv7l] - Ubuntu 22.04, 20.04.4, 18.04.6, 16.04.7, 14.04.6, 12.04.5 RPMs built directly from the dist tarball have been installed and tested on the following x86_64 systems: - AlmaLinux 9.0, 8.6 - CentOS Linux Stream 9, Stream 8, 8.5.2111, 7.9.2009 - Fedora Linux 36, 35, 34 This release is backwards-compatible to 0.5; however, credentials encoded with the current default of MUNGE_MAC_SHA256 cannot be decoded by releases prior to 0.5.5. munge-munge-0.5.15/QUICKSTART000066400000000000000000000451541425467526100154700ustar00rootroot00000000000000MUNGE Installation Guide 1. General recommendations A. Create a dedicated non-privileged user account for munged The munged daemon should be run as a dedicated non-privileged user, and its files and directories should be owned by this unique user. The recommended user/group name for this account is "munge". B. Maintain consistent UID/GID mappings for users across nodes Since authentication is based on UID and GID, all users authenticating with MUNGE within a security realm need to have consistent UID/GID mapping across all nodes. C. Keep system clocks in sync MUNGE credentials are valid for a limited time defined by their time-to-live (5 minutes by default). The fastest and slowest system clocks across all nodes within a security realm should be within this time interval. 2. Software dependencies A. Libgcrypt or OpenSSL Either the Libgcrypt or OpenSSL cryptographic library is required. Libgcrypt is distributed under LGPLv2.1+. For the 3.0.0 release, OpenSSL switched to the ASLv2 license which is compatible with the GPLv3+ license used by MUNGE, but all prior releases are covered by the dual OpenSSL and SSLeay license which, on some distributions, is incompatible with the GPL. B. bzip2 Support for bzip2 compression will be included if the library is found when the software is built. C. zlib Support for zlib compression will be included if the library is found when the software is built. D. pkgconf or pkg-config A .pc file will be installed if a suitable directory is found or specified when the software is built. 3. Building the latest release A. Installing from the release tarball The release tarball can be verified by its GPG signature or SHA-512 checksum. See . The typical commands "./configure; make; make install" should configure, build, and install the software. Adjust as needed for your environment. $ tar xJf munge-0.5.15.tar.xz $ cd munge-0.5.15 $ ./configure \ --prefix=/usr \ --sysconfdir=/etc \ --localstatedir=/var \ --runstatedir=/run $ make $ make check $ sudo make install Note that "configure" will not exist if you have instead downloaded a GitHub-generated source code asset (either .zip or .tar.gz). The configure script is generated by running "./bootstrap" which requires autoconf, automake, and libtool to be installed. The configure script has heuristics that attempt to guess the best options for the given system, but the following options allow further customization of the installation: --with-crypto-lib=(libgcrypt|openssl) cryptographic library selection --with-logrotateddir=DIR / --without-logrotateddir installation directory for logrotate config files --with-munge-socket=PATH socket pathname default for client/server communication --with-pkgconfigdir=DIR / --without-pkgconfigdir installation directory for pkg-config .pc files --with-runstatedir=DIR installation director for modifiable per-process data; overrides --runstatedir if both are specified --with-sysconfigdir=DIR / --without-sysconfigdir installation directory for systemd/sysvinit config files --with-systemdunitdir=DIR / --without-systemdunitdir installation directory for systemd service unit files --with-sysvinitddir=DIR / --without-sysvinitddir installation directory for SysV-style init scripts The configure "--runstatedir" option appears in autoconf-2.70, and was backported to Debian's autoconf-2.69-9. The "--with-runstatedir" option can also be used to specify this directory in case the configure script was built by an earlier version of autoconf. The "make check" command is optional; it runs the test suite. See . B. Installing from git $ git clone https://github.com/dun/munge.git $ cd munge $ ./bootstrap $ ./configure \ --prefix=/usr \ --sysconfdir=/etc \ --localstatedir=/var \ --runstatedir=/run $ make $ make check $ sudo make install While the release tarball contains an autoconf "configure" script, a git checkout does not since the autotools-derived products are not under version control. The configure script is generated by running "./bootstrap" which requires autoconf, automake, and libtool to be installed. C. Installing from RPMs on AlmaLinux/CentOS/Fedora RPMs for recent AlmaLinux/CentOS/Fedora can be built directly from the tarball. Build dependencies can be installed from an SRPM if necessary, and the SRPM can be built from the tarball: $ rpmbuild -ts munge-0.5.15.tar.xz Wrote: SRPMS/munge-0.5.15-1.el9.src.rpm $ sudo dnf builddep SRPMS/munge-0.5.15-1.el9.src.rpm Package bzip2-devel-1.0.8-8.el9.x86_64 is already installed. Package gcc-11.2.1-9.4.el9.alma.x86_64 is already installed. Package gnupg2-2.3.3-1.el9.x86_64 is already installed. Package make-1:4.3-7.el9.x86_64 is already installed. Package openssl-devel-1:3.0.1-23.el9_0.x86_64 is already installed. Package procps-ng-3.3.17-4.el9.x86_64 is already installed. Package systemd-250-6.el9_0.x86_64 is already installed. Package zlib-devel-1.2.11-31.el9_0.1.x86_64 is already installed. As of 0.5.14, GPG verification of the source can be enabled by specifying "--with verify" to rpmbuild. This requires the public key and corresponding detached GPG signature (munge-0.5.15.tar.xz.asc) to reside in the same directory as the release tarball (munge-0.5.15.tar.xz): $ ls dun.gpg munge-0.5.15.tar.xz munge-0.5.15.tar.xz.asc $ rpmbuild -tb --with verify munge-0.5.15.tar.xz The test suite can be run by specifying "--with check" to rpmbuild: $ rpmbuild -tb --with verify --with check munge-0.5.15.tar.xz Three or more binary RPMs will be generated: munge, munge-devel, munge-libs, and potentially a debugsource and a couple debuginfo RPMs. The munge RPM contains the munged daemon, mungekey executable, and client executables (munge, unmunge, and remunge). The munge-devel RPM contains the "munge.h" header file for developing applications using MUNGE. The munge-libs RPM contains a shared library for running applications that use MUNGE. The binary RPMs can be installed with rpm. For example: $ sudo rpm -ivh RPMS/x86_64/munge-0.5.15-1.el9.x86_64.rpm \ RPMS/x86_64/munge-debuginfo-0.5.15-1.el9.x86_64.rpm \ RPMS/x86_64/munge-debugsource-0.5.15-1.el9.x86_64.rpm \ RPMS/x86_64/munge-devel-0.5.15-1.el9.x86_64.rpm \ RPMS/x86_64/munge-libs-0.5.15-1.el9.x86_64.rpm \ RPMS/x86_64/munge-libs-debuginfo-0.5.15-1.el9.x86_64.rpm 4. Securing the installation The munged daemon does not generally require root privileges; see . If possible, munged should be run as a dedicated non-privileged user in accordance with the principle of least privilege. The munged daemon uses the following system directories (note that directories of the form ${somedir} refer to the configure script's installation directories and must be substituted accordingly). Typical values when configuring with "--prefix=/usr", "--sysconfdir=/etc", "--localstatedir=/var", and "--runstatedir=/run" are shown in brackets. A. ${sysconfdir}/munge [/etc/munge] This directory will contain the daemon's key. Its permissions should be set to 0700. B. ${localstatedir}/lib/munge [/var/lib/munge] This directory will contain the daemon's PRNG seed file. On systems where a file-descriptor-passing authentication method is used, this is also where the daemon creates pipes for authenticating clients. Its permissions should be set to 0711 if using file-descriptor-passing, or 0700 otherwise. C. ${localstatedir}/log/munge [/var/log/munge] This directory will contain the daemon's log file. Its permissions should be set to 0700. D. ${runstatedir}/munge [/run/munge] This directory will contain the Unix domain socket for clients to communicate with the local daemon. It will also contain the daemon's pid file. This directory must allow execute permissions for all. Its permissions should be set to 0755. These directories must be owned by the same user as the running daemon process. They cannot allow write permissions for group unless the sticky bit is set or the directory is owned by the trusted group (see the munged(8) manpage for details on the "--trusted-group" option), and they cannot allow write permissions for other unless the sticky bit is set. In addition, all of their parent directories in the path up to the root directory must be owned by either root or the same user as the daemon process. They cannot allow write permissions for group unless the sticky bit is set or the directory is owned by the trusted group, and they cannot allow write permissions for other unless the sticky bit is set. 5. Configuration and setup A. Creating a key All munged daemons within a security realm share a common key. This key is used to cryptographically protect the credential. Consequently, credentials are only valid within a given security realm. The "mungekey" executable is the key management utility. To ensure the key file maintains the correct ownership and permissions, it should be run by the same user ID that will run the munged daemon process. For example, to create a key: $ sudo -u munge ${sbindir}/mungekey --verbose The key resides in "${sysconfdir}/munge/munge.key". This file must be owned by the same user ID that will run the munged daemon process, and its permissions should be set to 0600. Additionally, this key file will need to be securely propagated (e.g., via ssh) to all hosts within the security realm. B. Setting command-line options When starting the daemon via systemd or the init script, command-line options to munged can be specified in the OPTIONS line of the sysconfig file (typically found in "${sysconfdir}/default/munge" or "${sysconfdir}/sysconfig/munge"). 6. Starting and stopping the daemon The key file "${sysconfdir}/munge/munge.key" must be created before starting the daemon. A. systemd Start the daemon automatically at boot: $ sudo systemctl enable munge Start the daemon now: $ sudo systemctl start munge Stop the daemon: $ sudo systemctl stop munge B. Init script Systems utilizing init scripts typically start the daemon by passing the "start" command to the script. The location of the script varies. For example: $ sudo ${sysconfdir}/init.d/munge start Stopping the daemon is done similarly: $ sudo ${sysconfdir}/init.d/munge stop C. Command-line Start the daemon from the command-line so it runs as a non-privileged user (e.g., "munge"): $ sudo -u munge ${sbindir}/munged Stop the daemon with the "--stop" command-line option: $ sudo -u munge ${sbindir}/munged --stop Or stop the daemon by sending a SIGTERM to the munged process: $ sudo -u munge kill $(cat ${runstatedir}/munge/munged.pid) Do not stop the daemon by sending a SIGKILL (i.e., kill -9). That prevents the daemon from cleaning up -- updating its seed file, removing its pid file, removing its socket, etc. 7. Troubleshooting A. Verify the installation The following steps can be performed to verify that the software is properly installed and functioning: 1. Encode a credential. This tests if the munge executable and libmunge library can be found, if munged is running, and if the client (munge/libmunge) can communicate with the server (munged). $ munge -n 2. Encode and decode a credential. This is similar to the previous test, but also tests that the credential has been properly encoded and successfully decoded. Additionally, it shows the metadata that has been encoded into the credential. $ munge -n | unmunge 3. Remotely decode a locally-encoded credential. This tests if local and remote munged daemons are running with the same key, if the two versions are compatible, if the local defaults for encoding the credential can be decoded by the remote daemon, and if the clocks between both hosts are within the time interval specified in seconds by the -t/--ttl option. $ munge -n -t 10 | ssh somehost unmunge 4. Locally decode a remotely-encoded credential. This tests if local and remote munged daemons are running with the same key, if the two versions are compatible, if the remote defaults for encoding the credential can be decoded by the local daemon, and if the clocks between both hosts are within the time interval specified in seconds by the -t/--ttl option. $ ssh somehost munge -n -t 10 | unmunge B. Check the default locations The default locations for the socket, key file, log file, pid file, and seed file are configured at build time. These defaults are shown in brackets in the munged "--help" output: $ ${sbindir}/munged --help C. Check the log The munged daemon logs descriptive error messages when possible. If munged fails to start, check the log for details. 1. For systemd, check runtime status information for the munge unit: $ sudo systemctl status --full munge 2. For systemd, check the systemd journal: $ sudo journalctl -xe | grep munged 3. For systemd, limit journal output to services run by the munge user: $ sudo journalctl _UID=$(id -u munge) 4. The munged daemon writes to "${localstatedir}/log/munge/munged.log" by default; but, the location of this file can be changed with the munged "--log-file" option. 5. If munged is started with the "--syslog" option, log messages are instead written to syslog using the "daemon" facility value. The name of the corresponding log file will vary depending on the syslog configuration. D. Run the daemon in the foreground If munged fails to start, try running it in the foreground. When run in this manner, log messages are written to stderr. But remember to start munged as the appropriate user: $ sudo -u munge ${sbindir}/munged --foreground E. "Force" the daemon to run (but use with caution!) Some error conditions can be overridden by "forcing" the daemon. Use the munged "--force" option to override errors for an existing socket, a lack of PRNG entropy, and insecure file/directory permissions. But use with caution as overriding these errors can affect security: $ sudo -u munge ${sbindir}/munged --force F. Common errors 1. munge: Error: Failed to access "/run/munge/munge.socket.2": No such file or directory The client was unable to connect to the munged daemon listening on the socket "/run/munge/munge.socket.2". The daemon is likely not running. Try starting it. If it fails to start, check the log for an error message. 2. unmunge: Error: Invalid credential The munged daemon decoding the credential is likely using a different key than the daemon that encoded it. First check the key files for both daemons. If they match, try restarting both daemons; since the key file is read when the daemon starts, a running daemon could be using a key that differs from the current contents of its key file. 3. unmunge: Error: Expired credential The current time (according to the local clock on the host decoding the credential) exceeds the creation time of the credential (according to the local clock on the host that encoded it) plus its embedded time-to-live value. Either the clocks are out of sync, or too much time has passed since the credential was created. 4. unmunge: Error: Rewound credential The current time (according to the local clock on the host decoding the credential) precedes the creation time of the credential (according to the local clock on the host that encoded it). Either the clocks are out of sync, or you've opened a rift in the space-time continuum. 5. unmunge: Error: Replayed credential The credential has previously been decoded by this munged daemon. 6. unmunge: Error: Unauthorized credential Either the UID of the client decoding the credential does not match the UID restriction with which the credential was encoded, or the GID of the client decoding the credential (or one of its supplementary group GIDs) does not match the GID restriction with which the credential was encoded. 7. munged: Error: Failed to check keyfile "/etc/munge/munge.key": No such file or directory A key has not been created. See mungekey(8). Note that this file will need to be securely propagated to all hosts within the security realm. 8. munged: Error: Found pid 1234 bound to socket "/run/munge/munge.socket.2" A munged daemon (pid 1234) is already listening on the socket "/run/munge/munge.socket.2". The munged daemon creates the socket when it starts, and removes it when it terminates. While multiple munged daemons can run concurrently on the same host, each daemon must use a different socket. 8. Using MUNGE Applications written in C/C++ can use the interface defined in . Compiler and linker flags can be obtained from pkg-config: $ cc $(pkg-config --cflags --libs munge) -o foo foo.c Scripts can invoke the "munge" and "unmunge" executables -- specify "--help" for usage information, or Read The Fantastic Manpages. munge-munge-0.5.15/README000066400000000000000000000106541425467526100147300ustar00rootroot00000000000000INTRODUCTION MUNGE (MUNGE Uid 'N' Gid Emporium) is an authentication service for creating and validating user credentials. It is designed to be highly scalable for use in an HPC cluster environment. It provides a portable API for encoding the user's identity into a tamper-proof credential that can be obtained by an untrusted client and forwarded by untrusted intermediaries within a security realm. Clients within this realm can create and validate credentials without the use of root privileges, reserved ports, or platform-specific methods. RATIONALE The need for MUNGE arose out of the HPC cluster environment. Consider the scenario in which a local daemon running on a login node receives a client request and forwards it on to remote daemons running on compute nodes within the cluster. Since the user has already logged on to the login node, the local daemon just needs a reliable means of ascertaining the UID and GID of the client process. Furthermore, the remote daemons need a mechanism to ensure the forwarded authentication data has not been subsequently altered. A common solution to this problem is to use Unix domain sockets to determine the identity of the local client, and then forward this information on to remote hosts via trusted rsh connections. But this presents several new problems. First, there is no portable API for determining the identity of a client over a Unix domain socket. Second, rsh connections must originate from a reserved port; the limited number of reserved ports available on a given host directly limits scalability. Third, root privileges are required in order to bind to a reserved port. Finally, the remote daemons have no means of determining whether the client identity is authentic. MUNGE solves all of these problems. USAGE A process creates a credential by requesting one from the local MUNGE service, either via the munge_encode() C library call or the munge executable. The encoded credential contains the UID and GID of the originating process. This process sends the credential to another process within the security realm as a means of proving its identity. The receiving process validates the credential with the use of its local MUNGE service, either via the munge_decode() C library call or the unmunge executable. The decoded credential provides the receiving process with a reliable means of ascertaining the UID and GID of the originating process. This information can be used for accounting or access control decisions. DETAILS The contents of the credential (including any optional payload data) are encrypted with a key shared by all munged daemons within the security realm. The integrity of the credential is ensured by a message authentication code (MAC). The credential is valid for a limited time defined by its time-to-live (TTL); this presumes clocks within a security realm are in sync. Unexpired credentials are tracked by the local munged daemon in order to prevent replay attacks on a given host. Decoding of a credential can be restricted to a particular user and/or group ID. The payload data can be used for purposes such as embedding the destination's address to ensure the credential is only valid on a specific host. The internal format of the credential is encoded in a platform-independent manner. And the credential itself is base64 encoded to allow it to be transmitted over virtually any transport. LICENSE MUNGE 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. Additionally for the MUNGE library (libmunge), you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. KEYS Releases are signed with the following GPG key: pub rsa4096/0x3B7ECB2B30DE0871 2011-10-01 [SC] Key fingerprint = A441 880C 3D4C 7C36 C5DD 41E1 3B7E CB2B 30DE 0871 uid [ultimate] Chris Dunlap uid [ultimate] Chris Dunlap uid [ultimate] Chris Dunlap sub rsa4096/0x48A5CADDECA74B8A 2011-10-01 [E] HOMEPAGE https://dun.github.io/munge/ munge-munge-0.5.15/README.AIX000066400000000000000000000071111425467526100153420ustar00rootroot00000000000000If you're building MUNGE from source on AIX, you need to export the OBJECT_MODE environment variable to your environment. It should be set to either "32" or "64" depending on whether you want code to be generated for a 32-bit or 64-bit architecture. If you are using gcc, you also need to set CFLAGS to either "-maix32" or "-maix64". Finally, you should set the "--enable-arch" option as well: $ CFLAGS="-maix32" OBJECT_MODE=32 ./configure --enable-arch=32 $ CFLAGS="-maix64" OBJECT_MODE=64 ./configure --enable-arch=64 In the configure script, AC_INIT is called before anything else and performs some basic compiler checks. The "-maix" gcc compiler flag must agree with the OBJECT_MODE environment variable recognized by the AIX linker. One alternative is to always set OBJECT_MODE=32. The gcc compiler will default to "-maix32" which allows the AC_INIT checks to succeed. The "--enable-arch" option can then be used to control whether code is generated for a 32-bit or 64-bit architecture. For example: $ export OBJECT_MODE=32 $ ./configure --enable-arch=64 This is the trick that is used in the RPM spec file. -- MUNGE supports two different types of client authentication under AIX. The getpeereid() method is supported by AIX 5.2 ML4 and later. The configure script tests for this when "checking for getpeereid". The recvfd-mknod file-descriptor-passing method is supported by earlier AIX versions. The configure script tests for this when "checking for /dev/spx" and "checking for struct strrecvfd". The getpeereid() method is substantially faster; if your system supports that, you can stop reading now. On the other hand, the file-descriptor-passing method on AIX is excruciatingly slow unless special steps are taken. This is due to the fact that a unique STREAMS-based pipe must be created in the filesystem for each client authentication attempt, and the journaling of the jfs filesystem makes this quite slow. To increase performance, the authentication pipe needs to be created in a ramdisk. The following steps create a 5MB ramdisk and mount it as "/tmp/munge". A small ramdisk will do just fine. You should then create two directories: /tmp/munge/client (permissioned 1733) & /tmp/munge/server (permissioned 0711). These directories can be named whatever you like, but these names will be used in the following example. # mkramdisk 10000 /dev/rramdisk0 # mkfs -V jfs /dev/ramdisk0 mkfs: destroy /dev/ramdisk0 (y)? y Device /dev/ramdisk0: Standard empty file system Size: 10000 512-byte (UBSIZE) blocks Initial Inodes: 1792 # mkdir /tmp/munge # mount -V jfs -o nointegrity /dev/ramdisk0 /tmp/munge # chmod 0755 /tmp/munge # mkdir /tmp/munge/client # chmod 1733 /tmp/munge/client # mkdir /tmp/munge/server # chmod 0711 /tmp/munge/server # mount node mounted mounted over vfs date options -------- --------------- --------------- ------ ------------ --------------- /dev/ramdisk0 /tmp/munge jfs Oct 01 10:01 rw,nointegrity The MUNGE_AUTH_SERVER_DIR and MUNGE_AUTH_CLIENT_DIR defines in src/libcommon/munge_defs.h need to be modified, and then the source needs to be recompiled. #define MUNGE_AUTH_SERVER_DIR "/tmp/munge/server" #define MUNGE_AUTH_CLIENT_DIR "/tmp/munge/client" Alternatively, you can override these settings with the munged "--auth-server-dir" and "--auth-client-dir" command-line options. munged --auth-server-dir /tmp/munge/server \ --auth-client-dir /tmp/munge/client These options will be moved into the configuration file once one exists. munge-munge-0.5.15/README.MULTILIB000066400000000000000000000056021425467526100161450ustar00rootroot00000000000000Multilib allows you to have both 32-bit and 64-bit versions of libmunge installed at the same time, capable of communicating with either a 32-bit or 64-bit version of munged. On Linux, at least, 32-bit libraries usually reside in /usr/lib, and 64-bit libraries usually reside in /usr/lib64. But on ia64, for example, 64-bit libraries reside in /usr/lib since everything is 64-bit there. If you are building from source, you can pass a command-line option to the configure script: $ ./configure --enable-arch=32 $ ./configure --enable-arch=64 If you are building RPMs, you can pass a command-line option to rpmbuild: $ rpmbuild -ta --clean --with arch32 munge-x.y.z.tar.bz2 $ rpmbuild -ta --clean --with arch64 munge-x.y.z.tar.bz2 You might also have to specify the --target command-line option: $ rpmbuild -ta --clean --with arch32 --target i386 munge-x.y.z.tar.bz2 $ rpmbuild -ta --clean --with arch64 --target x86_64 munge-x.y.z.tar.bz2 For each platform, you will have one source RPM and three binary RPMs (munge, munge-devel, and munge-libs). If you wanted to install both 32-bit and 64-bit MUNGE libraries on an RPM-based x86_64 system, for example, you would need to install either the 32-bit or 64-bit version of the main munge RPM (containing munged), and both 32-bit and 64-bit versions of the munge-devel and munge-libs RPMs: $ rpm -ivh RPMS/x86_64/munge-0.5-1.x86_64.rpm \ RPMS/x86_64/munge-devel-0.5-1.x86_64.rpm \ RPMS/x86_64/munge-libs-0.5-1.x86_64.rpm \ RPMS/i386/munge-devel-0.5-1.i386.rpm \ RPMS/i386/munge-libs-0.5-1.i386.rpm You can then link your application against either the 32-bit or 64-bit library: $ gcc -o foo foo.c -m32 -lmunge $ gcc -o foo foo.c -m64 -lmunge AIX uses RPM 3.x which does not recognize the "--with" command-line option. The 'arch 32_64' define builds a single multiarch library where both 32-bit and 64-bit objects reside in libmunge.a. Note that the 'arch 32_64' string must be quoted to appear as a single command-line argument. Export the OBJECT_MODE variable to the environment. The OS detection in RPM 3.x appends the OS version and release to the name (eg, "aix5.3"). Since I didn't want to pin the spec file to a particular set of AIX versions, I used the generic OS string "aix". Consequently, you must specify "--target ppc-aix" when building the RPM, and "--ignoreos" when installing the RPM. $ export OBJECT_MODE=32 $ rpm -ta --clean --define 'arch 32' --target ppc-aix munge-x.y.z.tar.bz2 $ export OBJECT_MODE=64 $ rpm -ta --clean --define 'arch 64' --target ppc-aix munge-x.y.z.tar.bz2 $ export OBJECT_MODE=32 $ rpm -ta --clean --define 'arch 32_64' --target ppc-aix munge-x.y.z.tar.bz2 You can then link your application against either the 32-bit or 64-bit library: $ export OBJECT_MODE=32 $ gcc -o foo foo.c -lmunge $ export OBJECT_MODE=64 $ gcc -o foo foo.c -lmunge munge-munge-0.5.15/README.md000066400000000000000000000022001425467526100153130ustar00rootroot00000000000000[![GitHub Release](https://img.shields.io/github/release/dun/munge.svg)](https://github.com/dun/munge/releases/latest) [![Packaging status](https://repology.org/badge/tiny-repos/munge.svg)](https://repology.org/metapackage/munge) [![Coverity Scan](https://scan.coverity.com/projects/dun-munge/badge.svg)](https://scan.coverity.com/projects/dun-munge) ### MUNGE Uid 'N' Gid Emporium MUNGE (_MUNGE Uid 'N' Gid Emporium_) is an authentication service for creating and validating user credentials. It is designed to be highly scalable for use in an HPC cluster environment. It provides a portable API for encoding the user's identity into a tamper-proof credential that can be obtained by an untrusted client and forwarded by untrusted intermediaries within a security realm. Clients within this realm can create and validate credentials without the use of root privileges, reserved ports, or platform-specific methods. - [Overview](../../wiki/Man-7-munge) - [Installation Guide](../../wiki/Installation-Guide) - [License Information](../../wiki/License-Info) - [Man Pages](../../wiki/Man-Pages) - [Verifying Releases](../../wiki/Verifying-Releases) munge-munge-0.5.15/THANKS000066400000000000000000000007531425467526100147620ustar00rootroot00000000000000While MUNGE has been primarily written by Chris Dunlap , the following people have contributed in its development: Aleksej Saushev Brendan Horan Cezary Sliwa Christopher Holmes Daniel Ahlin Gennaro Oliva Mark A. Grondona Michael Fenn Petter Reinholdtsen Ward Poelmans munge-munge-0.5.15/bootstrap000077500000000000000000000005171425467526100160100ustar00rootroot00000000000000#!/bin/sh set -e # automake < v1.12 does not install tap-driver.sh, so provide a TAP driver for # older versions which can be overridden with the "--force --install" flags. # test -f build-aux/tap-driver.sh.bak && \ cp -p build-aux/tap-driver.sh.bak build-aux/tap-driver.sh autoreconf --force --install --verbose --warnings=none munge-munge-0.5.15/build-aux/000077500000000000000000000000001425467526100157345ustar00rootroot00000000000000munge-munge-0.5.15/build-aux/gen-date000077500000000000000000000034721425467526100173540ustar00rootroot00000000000000#!/bin/sh # # MUNGE build-aux/gen-date # # This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE). # For details, see . # # Outputs the release date (YYYY-MM-DD). ## # Date string file written by git-archive via the export-subst attribute. ARCHIVE_DATE_FILE=".gitarchive-date" # Date string file written by Makefile dist-hook. DIST_DATE_FILE=".dist-date" # Release notes file. The most recent release is expected to be at the top of # the file in the format "PACKAGE-VERSION (YYYY-MM-DD)". This is used as a # fallback when release information cannot otherwise be ascertained. RELEASE_FILE="NEWS" # Initialize to prevent interference by environment variables. DATE= # Check the dist metadata. # This should be present in release tarballs created by "make dist". if test -f "${DIST_DATE_FILE}"; then DATE=$(cat "${DIST_DATE_FILE}") fi # Check the git commit metadata. # This should be present in git clones. if test "x${DATE}" = x && test -d "${GIT_DIR:-.git}"; then DATE=$(git show -s --pretty=format:%ci 2>/dev/null \ | sed -ne 's/^\([0-9-]*\).*/\1/p') fi # Check the git archive metadata. # This should be present in git archives & GitHub-generated source code assets. if test "x${DATE}" = x && test -f "${ARCHIVE_DATE_FILE}"; then DATE=$(sed -ne 's/^\([0-9-]*\).*/\1/p' "${ARCHIVE_DATE_FILE}") fi # Check the release notes. # The most recent release should be listed in the first line of the file. if test "x${DATE}" = x && test -f "${RELEASE_FILE}"; then DATE=$(head -1 "${RELEASE_FILE}" | sed -ne 's/.*(\([^)]*\)).*/\1/p') fi # Fall back to today's date. if test "x${DATE}" = x; then DATE=$(date +%F 2>/dev/null) fi # Omit the trailing newline so m4_esyscmd can use the result directly. test "x${DATE}" != x && printf %s "${DATE}" || printf %s "UNKNOWN" exit 0 munge-munge-0.5.15/build-aux/gen-version000077500000000000000000000074371425467526100201310ustar00rootroot00000000000000#!/bin/sh # # MUNGE build-aux/gen-version # # This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE). # For details, see . # # Outputs the version string based on the latest git commit. # # Snapshots (i.e., releases where the most recent git tag does not point to the # latest commit) will have the version string appended with the date and hash # of the latest commit in the form ".YYYYMMDD.H"; this format presumes there # will be at most one such release per day. ## # Date string file written by git-archive via the export-subst attribute. ARCHIVE_DATE_FILE=".gitarchive-date" # Git commit hash file written by git-archive via the export-subst attribute. ARCHIVE_HASH_FILE=".gitarchive-hash" # Version string file written by Makefile dist-hook. DIST_VERSION_FILE=".dist-version" # Release notes file. The most recent release is expected to be at the top of # the file in the format "PACKAGE-VERSION (YYYY-MM-DD)". This is used as a # fallback when release information cannot otherwise be ascertained. RELEASE_FILE="NEWS" # Git release tag prefix. TAG_PREFIX="munge-" # Initialize to prevent interference by environment variables. VERSION= # Check the dist metadata. # This should be present in release tarballs created by "make dist". if test -f "${DIST_VERSION_FILE}"; then VERSION=$(cat "${DIST_VERSION_FILE}") fi # Check the git commit metadata. # This should be present in git clones. if test "x${VERSION}" = x && test -d "${GIT_DIR:-.git}"; then DESC=$(git describe --match "${TAG_PREFIX}*" --tags 2>/dev/null) if test "x${DESC}" != x; then VERSION=$(echo "${DESC}" \ | sed -ne "s/^${TAG_PREFIX}\([^-]*\).*/\1/p") # Check the git-describe string for a commit hash to determine whether # this is a snapshot release. By default, git-describe will show # only the tag name if it points to the given commit. if test "x${VERSION}" != x; then COMMIT_HASH=$(echo "${DESC}" \ | sed -ne "s/^${TAG_PREFIX}.*-g\([0-9a-f]*\)$/\1/p") if test "x${COMMIT_HASH}" != x; then COMMIT_DATE=$(git show -s --pretty=format:%ci \ "${COMMIT_HASH}" 2>/dev/null \ | sed -e 's/-//g' -ne 's/^\([0-9]*\).*/\1/p') test "x${COMMIT_DATE}" != x \ && VERSION="${VERSION}.${COMMIT_DATE}.${COMMIT_HASH}" fi fi fi fi # Check the release notes for the latest version and release date. # The most recent release should be listed in the first line of the file. if test "x${VERSION}" = x && test -f "${RELEASE_FILE}"; then LATEST=$(head -1 "${RELEASE_FILE}") VERSION=$(echo "${LATEST}" | sed -ne 's/^[^0-9]*\([^ ]*\).*/\1/p') RELEASE_DATE=$(echo "${LATEST}" | sed -ne 's/.*(\([^)]*\)).*/\1/p') # Check the git archive metadata for both the archive date and commit hash. # These should be present in git archives & GitHub source code assets. # Presume snapshot if the release date does not match the archive date. if test "x${VERSION}" != x && test "x${RELEASE_DATE}" != x \ && test -f "${ARCHIVE_DATE_FILE}" \ && test -f "${ARCHIVE_HASH_FILE}"; then ARCHIVE_DATE=$(sed -ne 's/^\([0-9-]*\).*/\1/p' "${ARCHIVE_DATE_FILE}") ARCHIVE_HASH=$(sed -ne '/^[0-9a-f]*$/p' "${ARCHIVE_HASH_FILE}") test "x${RELEASE_DATE}" != "x${ARCHIVE_DATE}" \ && test "x${ARCHIVE_DATE}" != x \ && test "x${ARCHIVE_HASH}" != x \ && DATE=$(echo "${ARCHIVE_DATE}" | sed -e 's/-//g') \ && VERSION="${VERSION}.${DATE}.${ARCHIVE_HASH}" fi fi # Omit the trailing newline so m4_esyscmd can use the result directly. test "x${VERSION}" != x && printf %s "${VERSION}" || printf %s "UNKNOWN" exit 0 munge-munge-0.5.15/build-aux/tap-driver.sh.bak000077500000000000000000000460051425467526100211110ustar00rootroot00000000000000#! /bin/sh # Copyright (C) 2011-2020 Free Software Foundation, Inc. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, 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 . # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # This file is maintained in Automake, please report # bugs to or send patches to # . scriptversion=2013-12-23.17; # UTC # Make unconditional expansion of undefined variables an error. This # helps a lot in preventing typo-related bugs. set -u me=tap-driver.sh fatal () { echo "$me: fatal: $*" >&2 exit 1 } usage_error () { echo "$me: $*" >&2 print_usage >&2 exit 2 } print_usage () { cat < # trap : 1 3 2 13 15 if test $merge -gt 0; then exec 2>&1 else exec 2>&3 fi "$@" echo $? ) | LC_ALL=C ${AM_TAP_AWK-awk} \ -v me="$me" \ -v test_script_name="$test_name" \ -v log_file="$log_file" \ -v trs_file="$trs_file" \ -v expect_failure="$expect_failure" \ -v merge="$merge" \ -v ignore_exit="$ignore_exit" \ -v comments="$comments" \ -v diag_string="$diag_string" \ ' # TODO: the usages of "cat >&3" below could be optimized when using # GNU awk, and/on on systems that supports /dev/fd/. # Implementation note: in what follows, `result_obj` will be an # associative array that (partly) simulates a TAP result object # from the `TAP::Parser` perl module. ## ----------- ## ## FUNCTIONS ## ## ----------- ## function fatal(msg) { print me ": " msg | "cat >&2" exit 1 } function abort(where) { fatal("internal error " where) } # Convert a boolean to a "yes"/"no" string. function yn(bool) { return bool ? "yes" : "no"; } function add_test_result(result) { if (!test_results_index) test_results_index = 0 test_results_list[test_results_index] = result test_results_index += 1 test_results_seen[result] = 1; } # Whether the test script should be re-run by "make recheck". function must_recheck() { for (k in test_results_seen) if (k != "XFAIL" && k != "PASS" && k != "SKIP") return 1 return 0 } # Whether the content of the log file associated to this test should # be copied into the "global" test-suite.log. function copy_in_global_log() { for (k in test_results_seen) if (k != "PASS") return 1 return 0 } function get_global_test_result() { if ("ERROR" in test_results_seen) return "ERROR" if ("FAIL" in test_results_seen || "XPASS" in test_results_seen) return "FAIL" all_skipped = 1 for (k in test_results_seen) if (k != "SKIP") all_skipped = 0 if (all_skipped) return "SKIP" return "PASS"; } function stringify_result_obj(result_obj) { if (result_obj["is_unplanned"] || result_obj["number"] != testno) return "ERROR" if (plan_seen == LATE_PLAN) return "ERROR" if (result_obj["directive"] == "TODO") return result_obj["is_ok"] ? "XPASS" : "XFAIL" if (result_obj["directive"] == "SKIP") return result_obj["is_ok"] ? "SKIP" : COOKED_FAIL; if (length(result_obj["directive"])) abort("in function stringify_result_obj()") return result_obj["is_ok"] ? COOKED_PASS : COOKED_FAIL } function decorate_result(result) { color_name = color_for_result[result] if (color_name) return color_map[color_name] "" result "" color_map["std"] # If we are not using colorized output, or if we do not know how # to colorize the given result, we should return it unchanged. return result } function report(result, details) { if (result ~ /^(X?(PASS|FAIL)|SKIP|ERROR)/) { msg = ": " test_script_name add_test_result(result) } else if (result == "#") { msg = " " test_script_name ":" } else { abort("in function report()") } if (length(details)) msg = msg " " details # Output on console might be colorized. print decorate_result(result) msg # Log the result in the log file too, to help debugging (this is # especially true when said result is a TAP error or "Bail out!"). print result msg | "cat >&3"; } function testsuite_error(error_message) { report("ERROR", "- " error_message) } function handle_tap_result() { details = result_obj["number"]; if (length(result_obj["description"])) details = details " " result_obj["description"] if (plan_seen == LATE_PLAN) { details = details " # AFTER LATE PLAN"; } else if (result_obj["is_unplanned"]) { details = details " # UNPLANNED"; } else if (result_obj["number"] != testno) { details = sprintf("%s # OUT-OF-ORDER (expecting %d)", details, testno); } else if (result_obj["directive"]) { details = details " # " result_obj["directive"]; if (length(result_obj["explanation"])) details = details " " result_obj["explanation"] } report(stringify_result_obj(result_obj), details) } # `skip_reason` should be empty whenever planned > 0. function handle_tap_plan(planned, skip_reason) { planned += 0 # Avoid getting confused if, say, `planned` is "00" if (length(skip_reason) && planned > 0) abort("in function handle_tap_plan()") if (plan_seen) { # Error, only one plan per stream is acceptable. testsuite_error("multiple test plans") return; } planned_tests = planned # The TAP plan can come before or after *all* the TAP results; we speak # respectively of an "early" or a "late" plan. If we see the plan line # after at least one TAP result has been seen, assume we have a late # plan; in this case, any further test result seen after the plan will # be flagged as an error. plan_seen = (testno >= 1 ? LATE_PLAN : EARLY_PLAN) # If testno > 0, we have an error ("too many tests run") that will be # automatically dealt with later, so do not worry about it here. If # $plan_seen is true, we have an error due to a repeated plan, and that # has already been dealt with above. Otherwise, we have a valid "plan # with SKIP" specification, and should report it as a particular kind # of SKIP result. if (planned == 0 && testno == 0) { if (length(skip_reason)) skip_reason = "- " skip_reason; report("SKIP", skip_reason); } } function extract_tap_comment(line) { if (index(line, diag_string) == 1) { # Strip leading `diag_string` from `line`. line = substr(line, length(diag_string) + 1) # And strip any leading and trailing whitespace left. sub("^[ \t]*", "", line) sub("[ \t]*$", "", line) # Return what is left (if any). return line; } return ""; } # When this function is called, we know that line is a TAP result line, # so that it matches the (perl) RE "^(not )?ok\b". function setup_result_obj(line) { # Get the result, and remove it from the line. result_obj["is_ok"] = (substr(line, 1, 2) == "ok" ? 1 : 0) sub("^(not )?ok[ \t]*", "", line) # If the result has an explicit number, get it and strip it; otherwise, # automatically assign the next test number to it. if (line ~ /^[0-9]+$/ || line ~ /^[0-9]+[^a-zA-Z0-9_]/) { match(line, "^[0-9]+") # The final `+ 0` is to normalize numbers with leading zeros. result_obj["number"] = substr(line, 1, RLENGTH) + 0 line = substr(line, RLENGTH + 1) } else { result_obj["number"] = testno } if (plan_seen == LATE_PLAN) # No further test results are acceptable after a "late" TAP plan # has been seen. result_obj["is_unplanned"] = 1 else if (plan_seen && testno > planned_tests) result_obj["is_unplanned"] = 1 else result_obj["is_unplanned"] = 0 # Strip trailing and leading whitespace. sub("^[ \t]*", "", line) sub("[ \t]*$", "", line) # This will have to be corrected if we have a "TODO"/"SKIP" directive. result_obj["description"] = line result_obj["directive"] = "" result_obj["explanation"] = "" if (index(line, "#") == 0) return # No possible directive, nothing more to do. # Directives are case-insensitive. rx = "[ \t]*#[ \t]*([tT][oO][dD][oO]|[sS][kK][iI][pP])[ \t]*" # See whether we have the directive, and if yes, where. pos = match(line, rx "$") if (!pos) pos = match(line, rx "[^a-zA-Z0-9_]") # If there was no TAP directive, we have nothing more to do. if (!pos) return # Let`s now see if the TAP directive has been escaped. For example: # escaped: ok \# SKIP # not escaped: ok \\# SKIP # escaped: ok \\\\\# SKIP # not escaped: ok \ # SKIP if (substr(line, pos, 1) == "#") { bslash_count = 0 for (i = pos; i > 1 && substr(line, i - 1, 1) == "\\"; i--) bslash_count += 1 if (bslash_count % 2) return # Directive was escaped. } # Strip the directive and its explanation (if any) from the test # description. result_obj["description"] = substr(line, 1, pos - 1) # Now remove the test description from the line, that has been dealt # with already. line = substr(line, pos) # Strip the directive, and save its value (normalized to upper case). sub("^[ \t]*#[ \t]*", "", line) result_obj["directive"] = toupper(substr(line, 1, 4)) line = substr(line, 5) # Now get the explanation for the directive (if any), with leading # and trailing whitespace removed. sub("^[ \t]*", "", line) sub("[ \t]*$", "", line) result_obj["explanation"] = line } function get_test_exit_message(status) { if (status == 0) return "" if (status !~ /^[1-9][0-9]*$/) abort("getting exit status") if (status < 127) exit_details = "" else if (status == 127) exit_details = " (command not found?)" else if (status >= 128 && status <= 255) exit_details = sprintf(" (terminated by signal %d?)", status - 128) else if (status > 256 && status <= 384) # We used to report an "abnormal termination" here, but some Korn # shells, when a child process die due to signal number n, can leave # in $? an exit status of 256+n instead of the more standard 128+n. # Apparently, both behaviours are allowed by POSIX (2008), so be # prepared to handle them both. See also Austing Group report ID # 0000051 exit_details = sprintf(" (terminated by signal %d?)", status - 256) else # Never seen in practice. exit_details = " (abnormal termination)" return sprintf("exited with status %d%s", status, exit_details) } function write_test_results() { print ":global-test-result: " get_global_test_result() > trs_file print ":recheck: " yn(must_recheck()) > trs_file print ":copy-in-global-log: " yn(copy_in_global_log()) > trs_file for (i = 0; i < test_results_index; i += 1) print ":test-result: " test_results_list[i] > trs_file close(trs_file); } BEGIN { ## ------- ## ## SETUP ## ## ------- ## '"$init_colors"' # Properly initialized once the TAP plan is seen. planned_tests = 0 COOKED_PASS = expect_failure ? "XPASS": "PASS"; COOKED_FAIL = expect_failure ? "XFAIL": "FAIL"; # Enumeration-like constants to remember which kind of plan (if any) # has been seen. It is important that NO_PLAN evaluates "false" as # a boolean. NO_PLAN = 0 EARLY_PLAN = 1 LATE_PLAN = 2 testno = 0 # Number of test results seen so far. bailed_out = 0 # Whether a "Bail out!" directive has been seen. # Whether the TAP plan has been seen or not, and if yes, which kind # it is ("early" is seen before any test result, "late" otherwise). plan_seen = NO_PLAN ## --------- ## ## PARSING ## ## --------- ## is_first_read = 1 while (1) { # Involutions required so that we are able to read the exit status # from the last input line. st = getline if (st < 0) # I/O error. fatal("I/O error while reading from input stream") else if (st == 0) # End-of-input { if (is_first_read) abort("in input loop: only one input line") break } if (is_first_read) { is_first_read = 0 nextline = $0 continue } else { curline = nextline nextline = $0 $0 = curline } # Copy any input line verbatim into the log file. print | "cat >&3" # Parsing of TAP input should stop after a "Bail out!" directive. if (bailed_out) continue # TAP test result. if ($0 ~ /^(not )?ok$/ || $0 ~ /^(not )?ok[^a-zA-Z0-9_]/) { testno += 1 setup_result_obj($0) handle_tap_result() } # TAP plan (normal or "SKIP" without explanation). else if ($0 ~ /^1\.\.[0-9]+[ \t]*$/) { # The next two lines will put the number of planned tests in $0. sub("^1\\.\\.", "") sub("[^0-9]*$", "") handle_tap_plan($0, "") continue } # TAP "SKIP" plan, with an explanation. else if ($0 ~ /^1\.\.0+[ \t]*#/) { # The next lines will put the skip explanation in $0, stripping # any leading and trailing whitespace. This is a little more # tricky in truth, since we want to also strip a potential leading # "SKIP" string from the message. sub("^[^#]*#[ \t]*(SKIP[: \t][ \t]*)?", "") sub("[ \t]*$", ""); handle_tap_plan(0, $0) } # "Bail out!" magic. # Older versions of prove and TAP::Harness (e.g., 3.17) did not # recognize a "Bail out!" directive when preceded by leading # whitespace, but more modern versions (e.g., 3.23) do. So we # emulate the latter, "more modern" behaviour. else if ($0 ~ /^[ \t]*Bail out!/) { bailed_out = 1 # Get the bailout message (if any), with leading and trailing # whitespace stripped. The message remains stored in `$0`. sub("^[ \t]*Bail out![ \t]*", ""); sub("[ \t]*$", ""); # Format the error message for the bailout_message = "Bail out!" if (length($0)) bailout_message = bailout_message " " $0 testsuite_error(bailout_message) } # Maybe we have too look for dianogtic comments too. else if (comments != 0) { comment = extract_tap_comment($0); if (length(comment)) report("#", comment); } } ## -------- ## ## FINISH ## ## -------- ## # A "Bail out!" directive should cause us to ignore any following TAP # error, as well as a non-zero exit status from the TAP producer. if (!bailed_out) { if (!plan_seen) { testsuite_error("missing test plan") } else if (planned_tests != testno) { bad_amount = testno > planned_tests ? "many" : "few" testsuite_error(sprintf("too %s tests run (expected %d, got %d)", bad_amount, planned_tests, testno)) } if (!ignore_exit) { # Fetch exit status from the last line. exit_message = get_test_exit_message(nextline) if (exit_message) testsuite_error(exit_message) } } write_test_results() exit 0 } # End of "BEGIN" block. ' # TODO: document that we consume the file descriptor 3 :-( } 3>"$log_file" test $? -eq 0 || fatal "I/O or internal error" # Local Variables: # mode: shell-script # sh-indentation: 2 # eval: (add-hook 'before-save-hook 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC0" # time-stamp-end: "; # UTC" # End: munge-munge-0.5.15/configure.ac000066400000000000000000000045601425467526100163350ustar00rootroot00000000000000# MUNGE configure.ac # # This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE). # For details, see . ## # Prologue. ## AC_PREREQ([2.61]) AC_INIT([MUNGE], m4_esyscmd([build-aux/gen-version])) AC_SUBST([DATE], m4_esyscmd([build-aux/gen-date])) AC_CONFIG_AUX_DIR([build-aux]) AC_CONFIG_HEADERS([config.h]) AC_CONFIG_MACRO_DIR([m4]) AC_CONFIG_SRCDIR([src/libmunge/munge.h]) AC_REQUIRE_AUX_FILE([tap-driver.sh]) X_AC_WITH_MUNGE_SOCKET X_AC_WITH_RUNSTATEDIR X_AC_WITH_SYSTEMDUNITDIR X_AC_WITH_SYSVINITDDIR X_AC_WITH_SYSCONFIGDIR X_AC_WITH_LOGROTATEDDIR X_AC_WITH_PKGCONFIGDIR X_AC_HUMOR AM_INIT_AUTOMAKE([1.11 foreign dist-xz no-dist-gzip]) AM_MAINTAINER_MODE m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) AC_USE_SYSTEM_EXTENSIONS m4_ifdef([LT_INIT], [LT_INIT], [AC_PROG_LIBTOOL]) ## # Checks for programs. ## X_AC_ARCH AC_PROG_AWK AC_PROG_CC AC_PROG_INSTALL AC_PROG_LN_S AC_PROG_MAKE_SET AC_PROG_MKDIR_P AC_PROG_SED AM_PROG_CC_C_O X_AC_DEBUG ## # Checks for libraries. ## X_AC_CHECK_PTHREADS X_AC_CHECK_COND_LIB(bz2, BZ2_bzBuffToBuffCompress) X_AC_CHECK_COND_LIB(rt, clock_gettime) X_AC_CHECK_COND_LIB(z, compress) AC_SEARCH_LIBS(gethostbyname, nsl) AC_SEARCH_LIBS(socket, socket) m4_ifdef([AM_PATH_LIBGCRYPT], [AM_PATH_LIBGCRYPT]) X_AC_PATH_OPENSSL X_AC_SELECT_CRYPTO_LIB if test "${CRYPTO_PKG}" = "openssl"; then X_AC_CHECK_OPENSSL fi ## # Checks for header files. ## AC_CHECK_HEADERS( \ bzlib.h \ ifaddrs.h \ standards.h \ sys/random.h \ zlib.h \ ) ## # Checks for typedefs, structures, and compiler characteristics. ## AC_C_CONST AC_TYPE_UID_T AC_CHECK_TYPES(socklen_t, [], [], [#include #include ]) ## # Checks for library functions. ## AC_CHECK_FUNCS( \ clock_nanosleep \ getentropy \ getifaddrs \ getrandom \ localtime_r \ mlockall \ sysconf \ ) AC_REPLACE_FUNCS( \ inet_ntop \ strlcat \ strlcpy \ ) X_AC_GETGRENT X_AC_GETGRNAM X_AC_GETPWNAM ## # Checks for platform-specific issues. ## X_AC_AIX X_AC_DARWIN ## # Checks for client authentication method. ## X_AC_SELECT_AUTH_METHOD ## # Epilogue. ## AC_CONFIG_FILES( \ Makefile \ src/Makefile \ src/common/Makefile \ src/etc/Makefile \ src/libcommon/Makefile \ src/libmissing/Makefile \ src/libmunge/Makefile \ src/libtap/Makefile \ src/munge/Makefile \ src/munged/Makefile \ src/mungekey/Makefile \ t/Makefile \ ) AC_OUTPUT munge-munge-0.5.15/doc/000077500000000000000000000000001425467526100146075ustar00rootroot00000000000000munge-munge-0.5.15/doc/credential_v1_format.txt000066400000000000000000000045121425467526100214420ustar00rootroot00000000000000------------------------------------------------------------------------------- MUNGE Credential v1 Format ------------------------------------------------------------------------------- +---+------------------------------------------------------------+---+ | | 08b : version number (1) | | | O | 08b : cipher type (munge_cipher_t) | O | | U | 08b : compression type (munge_zip_t) | U | | T | 08b : message authentication code type (munge_mac_t) | T | | E | 08b : length (in bytes) of security realm string | E | | R | var : security realm string (w/o terminating NUL) | R | | | var : cipher IV (initialization vector) | | +---+------------------------------------------------------------+---+ | M | var : MAC (message authentication code) | M | +---+------------------------------------------------------------+---+ | | 64b : salt | | | | 08b : length (in bytes) of the origin IP address | | | I | var : origin IP address (where the credential was encoded) | I | | N | 32b : time at which the credential was encoded (time_t) | N | | N | 32b : time to live (in seconds) once encoded | N | | E | 32b : UID of the process requesting the credential | E | | R | 32b : GID of the process requesting the credential | R | | | 32b : length (in bytes) of payload data | | | | var : payload data being munged into the credential | | +---+------------------------------------------------------------+---+ 1. Field lengths are expressed in bits, or 'var' for variable length. 2. All 32b integers are in network byte order (ie, big endian). 3. The length of the cipher IV is dependent on munge_cipher_t. 4. The length of the MAC is dependent on munge_mac_t. 5. The MAC is first computed over the entire message (ie, OUTER + INNER). 6. The INNER layer is then compressed according to munge_zip_t. 7. The INNER layer is then encrypted according to munge_cipher_t. 8. The entire message (ie, OUTER + MAC + INNER) is then base64 encoded. 9. The base64 encoding is prepended with "MUNGE:" and appended with ":". munge-munge-0.5.15/doc/credential_v2_format.txt000066400000000000000000000047401425467526100214460ustar00rootroot00000000000000------------------------------------------------------------------------------- MUNGE Credential v2 Format ------------------------------------------------------------------------------- +---+------------------------------------------------------------+---+ | | 08b : version number (2) | | | O | 08b : cipher type (munge_cipher_t) | O | | U | 08b : compression type (munge_zip_t) | U | | T | 08b : message authentication code type (munge_mac_t) | T | | E | 08b : length (in bytes) of security realm string | E | | R | var : security realm string (w/o terminating NUL) | R | | | var : cipher IV (initialization vector) | | +---+------------------------------------------------------------+---+ | M | var : MAC (message authentication code) | M | +---+------------------------------------------------------------+---+ | | 64b : salt | | | | 08b : length (in bytes) of the origin IP address | | | | var : origin IP address (where the credential was encoded) | | | I | 32b : time at which the credential was encoded (time_t) | I | | N | 32b : time to live (in seconds) once encoded | N | | N | 32b : UID of the client that requested the credential | N | | E | 32b : GID of the client that requested the credential | E | | R | 32b : UID of the client allowed to decode the credential | R | | | 32b : GID of the client allowed to decode the credential | | | | 32b : length (in bytes) of payload data | | | | var : payload data being munged into the credential | | +---+------------------------------------------------------------+---+ 1. Field lengths are expressed in bits, or 'var' for variable length. 2. All 32b integers are in network byte order (ie, big endian). 3. The length of the cipher IV is dependent on munge_cipher_t. 4. The length of the MAC is dependent on munge_mac_t. 5. The MAC is first computed over the entire message (ie, OUTER + INNER). 6. The INNER layer is then compressed according to munge_zip_t. 7. The INNER layer is then encrypted according to munge_cipher_t. 8. The entire message (ie, OUTER + MAC + INNER) is then base64 encoded. 9. The base64 encoding is prepended with "MUNGE:" and appended with ":". munge-munge-0.5.15/doc/credential_v3_format.txt000066400000000000000000000066641425467526100214560ustar00rootroot00000000000000------------------------------------------------------------------------------- MUNGE Credential v3 Format ------------------------------------------------------------------------------- +---+------------------------------------------------------------+---+ | | 08b : version number (3) | | | O | 08b : cipher type (munge_cipher_t) | O | | U | 08b : message authentication code type (munge_mac_t) | U | | T | 08b : compression type (munge_zip_t) | T | | E | 08b : length (in bytes) of security realm string | E | | R | var : security realm string (w/o terminating null) | R | | | var : cipher IV (initialization vector) | | +---+------------------------------------------------------------+---+ | M | var : MAC (message authentication code) | M | +---+------------------------------------------------------------+---+ | | 64b : salt | | | | 08b : length (in bytes) of the origin IP address | | | | var : origin IP address (where the credential was encoded) | | | I | 32b : time at which the credential was encoded (time_t) | I | | N | 32b : time to live (in seconds) once encoded | N | | N | 32b : UID of the client that requested the credential | N | | E | 32b : GID of the client that requested the credential | E | | R | 32b : UID of the client allowed to decode the credential | R | | | 32b : GID of the client allowed to decode the credential | | | | 32b : length (in bytes) of payload data | | | | var : payload data being munged into the credential | | +---+------------------------------------------------------------+---+ - Field lengths are expressed in bits, or "var" for variable length. - All 32b integers are in network byte order (ie, big endian / MSBF). - The length of the cipher IV is dependent upon the munge_cipher_t. - The length of the MAC is dependent upon the munge_mac_t. For encoding, the following rules determine the order of operations: a. Compression must occur before encryption since the resulting ciphertext should appear statistically random and therefore be incompressible. b. The MAC must be computed after compression because it must protect the validity of the 64b compression header that encodes the original length of the uncompressed data. c. The MAC must be computed before encryption because the MAC is used to compute the data encryption key (DEK) for the symmetric cipher. d. Base64 encoding must occur last. Consequently, credentials are encoded in the following steps: 1. The INNER layer is compressed according to the munge_zip_t. 2. The MAC is computed over the entire message (ie, OUTER + INNER) using an HMAC specified by the munge_mac_t in combination with the MAC subkey. 3. The INNER layer is encrypted in cipher block chaining mode with PKCS #5 padding according to the munge_cipher_t. The DEK used for symmetric encryption is computed from the credential's MAC using an HMAC specified by the munge_mac_t in combination with the DEK subkey. 4. The entire message (ie, OUTER + MAC + INNER) is base64 encoded. 5. The base64 encoding is prepended with "MUNGE:" and appended with ":". munge-munge-0.5.15/m4/000077500000000000000000000000001425467526100143625ustar00rootroot00000000000000munge-munge-0.5.15/m4/x_ac_aix.m4000066400000000000000000000007141425467526100164010ustar00rootroot00000000000000#****************************************************************************** # AUTHOR: # Chris Dunlap # # SYNOPSIS: # X_AC_AIX # # DESCRIPTION: # Check for AIX platform-specific issues. #****************************************************************************** AC_DEFUN([X_AC_AIX], [ case "$host" in *-*-aix*) LDFLAGS="$LDFLAGS -Wl,-brtl" # enable run-time linking ;; *) ;; esac ] ) munge-munge-0.5.15/m4/x_ac_arch.m4000066400000000000000000000053401425467526100165350ustar00rootroot00000000000000#****************************************************************************** # AUTHOR: # Chris Dunlap # # SYNOPSIS: # X_AC_ARCH # # DESCRIPTION: # Add support for the "--enable-arch=n" configure script option. # This option can be set to either 32 or 64 in order to specify whether # code should be generated for a 32-bit or 64-bit architecture. # # WARNINGS: # This macro must be placed after AC_CANONICAL_HOST and before # AC_PROG_CC or equivalent. # # LIMITATIONS: # This macro doesn't begin to handle all of the various multiarch # permutations found in the wild. So far, it's only been tested # on AIX & x86-64 Linux. #****************************************************************************** AC_DEFUN([X_AC_ARCH], [ AC_MSG_CHECKING([for specified code architecture]) AC_ARG_ENABLE( [arch], AS_HELP_STRING([--enable-arch=n], [specify either a 32 or 64 bit arch]), [ case "$enableval" in 32) x_ac_arch=$enableval ;; 64) x_ac_arch=$enableval ;; *) AC_MSG_RESULT([specify either 32 or 64]) AC_MSG_ERROR([bad value "$enableval" for --enable-arch]) ;; esac ] ) AC_MSG_RESULT([${x_ac_arch=no}]) if test "$x_ac_arch" != "no"; then AC_MSG_CHECKING([whether $CC accepts -m${x_ac_arch}]) _x_ac_arch_cflags_save="$CFLAGS" CFLAGS="$CFLAGS -m${x_ac_arch}" AC_COMPILE_IFELSE([AC_LANG_PROGRAM()], [AS_VAR_SET(x_ac_arch_prog_cc_m, yes)], [AS_VAR_SET(x_ac_arch_prog_cc_m, no); CFLAGS="$_x_ac_arch_cflags_save"]) AC_MSG_RESULT([${x_ac_arch_prog_cc_m=no}]) if expr X"$host_os" : "Xaix" >/dev/null 2>&1; then AC_MSG_CHECKING([whether $CC accepts -maix${x_ac_arch}]) _x_ac_arch_cflags_save="$CFLAGS" CFLAGS="$CFLAGS -maix${x_ac_arch}" AC_COMPILE_IFELSE([AC_LANG_PROGRAM()], [AS_VAR_SET(x_ac_arch_prog_cc_maix, yes)], [AS_VAR_SET(x_ac_arch_prog_cc_maix, no); CFLAGS="$_x_ac_arch_cflags_save"]) AC_MSG_RESULT([${x_ac_arch_prog_cc_maix=no}]) fi fi if test "$x_ac_arch" = "32"; then if expr X"$host_os" : "Xaix" >/dev/null 2>&1; then test -z "$OBJECT_MODE" && AC_MSG_ERROR( [The OBJECT_MODE variable must be exported to the shell.]) OBJECT_MODE=32 AC_SUBST([OBJECT_MODE]) else test -d /lib -o -d /usr/lib \ && LDFLAGS="-L/lib -L/usr/lib $LDFLAGS" fi elif test "$x_ac_arch" = "64"; then if expr X"$host_os" : "Xaix" >/dev/null 2>&1; then test -z "$OBJECT_MODE" && AC_MSG_ERROR( [The OBJECT_MODE variable must be exported to the shell.]) OBJECT_MODE=64 AC_SUBST([OBJECT_MODE]) else test -d /lib64 -o -d /usr/lib64 \ && LDFLAGS="-L/lib64 -L/usr/lib64 $LDFLAGS" fi fi ] ) munge-munge-0.5.15/m4/x_ac_check_cond_lib.m4000066400000000000000000000027061425467526100205310ustar00rootroot00000000000000#****************************************************************************** # AUTHOR: # Chris Dunlap # # SYNOPSIS: # X_AC_CHECK_COND_LIB(library, function) # # DESCRIPTION: # Check whether a program can be linked with to get . # Like AC_CHECK_LIB(), except that if the check succeeds, HAVE_LIB # will be defined and a shell variable LIB containing "-l" # will be substituted via AC_SUBST(). # # In other words, this is just like the default action of AC_CHECK_LIB(), # except that instead of modifying LIBS (which will affect the linking of # all executables), the shell variable LIB is defined so it can be # added to the linking of just those executables needing this library. # Also note that this checks to see if the library is even needed at all. #****************************************************************************** AC_DEFUN([X_AC_CHECK_COND_LIB], [ AC_CACHE_CHECK( [for $2 in default libs], [x_ac_cv_lib_none_$2], [ AC_LINK_IFELSE( [AC_LANG_CALL([], [$2])], AS_VAR_SET(x_ac_cv_lib_none_$2, yes), AS_VAR_SET(x_ac_cv_lib_none_$2, no) )] ) AS_IF([test AS_VAR_GET(x_ac_cv_lib_none_$2) = no], AC_CHECK_LIB( [$1], [$2], [ AH_CHECK_LIB([$1]) AS_TR_CPP([LIB$1])="-l$1"; AC_SUBST(AS_TR_CPP([LIB$1])) AC_DEFINE_UNQUOTED(AS_TR_CPP([HAVE_LIB$1])) ] ) )] ) munge-munge-0.5.15/m4/x_ac_check_fifo_recvfd.m4000066400000000000000000000032301425467526100212250ustar00rootroot00000000000000#****************************************************************************** # AUTHOR: # Chris Dunlap # # SYNOPSIS: # X_AC_CHECK_FIFO_RECVFD # # DESCRIPTION: # Check to see if a fifo (constructed via mkfifo) can be used to pass # file descriptors using a struct strrecvfd and the I_RECVFD ioctl. #****************************************************************************** AC_DEFUN([X_AC_CHECK_FIFO_RECVFD], [ AC_CACHE_CHECK( [if file descriptors can be passed over a fifo], [x_ac_cv_check_fifo_recvfd], [ AS_VAR_SET(x_ac_cv_check_fifo_recvfd, no) AC_RUN_IFELSE([ AC_LANG_PROGRAM([[ #include #include #include #include #include #include #include #include #include #include #ifndef PATH_MAX #define PATH_MAX 4096 #endif /* !PATH_MAX */ ]], [[ char name[PATH_MAX]; char *tmpdir; char *basename = "fifo"; int fd; struct strrecvfd recvfd; int rc = 1; if (!(tmpdir = getenv ("TMPDIR"))) tmpdir = "/tmp"; snprintf (name, sizeof (name), "%s/.%s.%d", tmpdir, basename, getpid ()); unlink (name); if ( ( mkfifo (name, S_IWUSR | S_IRUSR) == 0) && ((fd = open (name, O_RDONLY | O_NONBLOCK)) >= 0) && ((ioctl (fd, I_RECVFD, &recvfd) == -1) && (errno == EAGAIN)) ) { rc = 0; } unlink (name); return (rc); ]] )], AS_VAR_SET(x_ac_cv_check_fifo_recvfd, yes), AS_VAR_SET(x_ac_cv_check_fifo_recvfd, no) )] ) AS_IF([test AS_VAR_GET(x_ac_cv_check_fifo_recvfd) = yes], AC_DEFINE([HAVE_FIFO_RECVFD], [1], [Define to 1 if file descriptors can be passed over a fifo.] ) )] ) munge-munge-0.5.15/m4/x_ac_check_local_peercred.m4000066400000000000000000000016631425467526100217240ustar00rootroot00000000000000#****************************************************************************** # AUTHOR: # Chris Dunlap # # SYNOPSIS: # X_AC_CHECK_LOCAL_PEERCRED # # DESCRIPTION: # Check to see if the LOCAL_PEERCRED socket option is supported. #****************************************************************************** AC_DEFUN([X_AC_CHECK_LOCAL_PEERCRED], [ AC_CACHE_CHECK( [for LOCAL_PEERCRED sockopt], [x_ac_cv_check_local_peercred], [ AC_COMPILE_IFELSE([ AC_LANG_PROGRAM([[ #include #include #include ]], [[ getsockopt (0, 0, LOCAL_PEERCRED, 0, 0); ]] )], AS_VAR_SET(x_ac_cv_check_local_peercred, yes), AS_VAR_SET(x_ac_cv_check_local_peercred, no) )] ) AS_IF([test AS_VAR_GET(x_ac_cv_check_local_peercred) = yes], AC_DEFINE([HAVE_LOCAL_PEERCRED], [1], [Define to 1 if you have the LOCAL_PEERCRED socket option.] ) )] ) munge-munge-0.5.15/m4/x_ac_check_openssl.m4000066400000000000000000000101321425467526100204330ustar00rootroot00000000000000#****************************************************************************** # AUTHOR: # Chris Dunlap # # SYNOPSIS: # X_AC_CHECK_OPENSSL # # DESCRIPTION: # Check for OpenSSL behavior. # # NOTES: # This must be called after X_AC_PATH_OPENSSL since it depends on the # makefile variables OPENSSL_CFLAGS and OPENSSL_LIBS. #****************************************************************************** AC_DEFUN([X_AC_CHECK_OPENSSL], [ ac_save_CFLAGS="${CFLAGS}" ac_save_LIBS="${LIBS}" CFLAGS="${CFLAGS} ${OPENSSL_CFLAGS}" LIBS="${LIBS} ${OPENSSL_LIBS}" AC_CHECK_FUNCS( \ CRYPTO_THREADID_set_callback \ CRYPTO_num_locks \ CRYPTO_set_id_callback \ CRYPTO_set_locking_callback \ ERR_free_strings \ ERR_load_crypto_strings \ EVP_CIPHER_CTX_cleanup \ EVP_CIPHER_CTX_free \ EVP_CIPHER_CTX_init \ EVP_CIPHER_CTX_new \ EVP_CipherFinal \ EVP_CipherFinal_ex \ EVP_CipherInit \ EVP_CipherInit_ex \ EVP_CipherUpdate \ EVP_DigestFinal \ EVP_DigestFinal_ex \ EVP_DigestInit \ EVP_DigestInit_ex \ EVP_DigestUpdate \ EVP_MAC_CTX_free \ EVP_MAC_CTX_new \ EVP_MAC_fetch \ EVP_MAC_final \ EVP_MAC_init \ EVP_MAC_update \ EVP_MD_CTX_cleanup \ EVP_MD_CTX_copy \ EVP_MD_CTX_copy_ex \ EVP_MD_CTX_create \ EVP_MD_CTX_destroy \ EVP_MD_CTX_free \ EVP_MD_CTX_init \ EVP_MD_CTX_new \ EVP_Q_mac \ EVP_aes_128_cbc \ EVP_aes_256_cbc \ EVP_sha256 \ EVP_sha512 \ HMAC \ HMAC_CTX_cleanup \ HMAC_CTX_free \ HMAC_CTX_init \ HMAC_CTX_new \ HMAC_Final \ HMAC_Init \ HMAC_Init_ex \ HMAC_Update \ HMAC_cleanup \ RAND_cleanup \ RAND_pseudo_bytes \ ) _X_AC_CHECK_OPENSSL_FUNC_RETURNS_INT( [EVP_CIPHER_CTX_cleanup], [NULL], [#include ] ) _X_AC_CHECK_OPENSSL_FUNC_RETURNS_INT( [EVP_CipherInit], [NULL, NULL, NULL, NULL, 0], [#include ] ) _X_AC_CHECK_OPENSSL_FUNC_RETURNS_INT( [EVP_CipherUpdate], [NULL, NULL, NULL, NULL, 0], [#include ] ) _X_AC_CHECK_OPENSSL_FUNC_RETURNS_INT( [EVP_DigestUpdate], [NULL, NULL, 0], [#include ] ) _X_AC_CHECK_OPENSSL_FUNC_RETURNS_INT( [HMAC_Final], [NULL, NULL, NULL], [#include ] ) _X_AC_CHECK_OPENSSL_FUNC_RETURNS_INT( [HMAC_Init_ex], [NULL, NULL, 0, NULL, NULL], [#include ] ) _X_AC_CHECK_OPENSSL_FUNC_RETURNS_INT( [HMAC_Update], [NULL, NULL, 0], [#include ] ) AC_CHECK_HEADERS( \ openssl/core.h \ openssl/core_names.h \ openssl/hmac.h \ openssl/provider.h \ ) AC_CHECK_TYPES([CRYPTO_dynlock], [], [], [#include ]) AC_CHECK_TYPES([EVP_MAC *, EVP_MAC_CTX *], [], [], [#include ]) AC_CHECK_TYPES([OSSL_PARAM *], [], [], [#include ]) AC_CHECK_TYPES([OSSL_PROVIDER *], [], [], [#include ]) CFLAGS="${ac_save_CFLAGS}" LIBS="${ac_save_LIBS}" ] ) # _X_AC_CHECK_OPENSSL_FUNC_RETURNS_INT (name, args, includes) # # Checks whether function returns an integer result, and defines # the C preprocessor macro for HAVE__RETURN_INT accordingly. # The are the argument list for the test function , # and the are the prologue of the test source to be linked. # The AC_LANG_PROGRAM #undef in the preamble is needed to thwart #define # macros used for backwards-compatibility of deprecated functions. # AC_DEFUN([_X_AC_CHECK_OPENSSL_FUNC_RETURNS_INT], [ AC_CACHE_CHECK( [if $1 returns int], [ac_cv_func_$1_returns_int], [ AS_VAR_SET([ac_cv_func_$1_returns_int], no) AC_LINK_IFELSE([ AC_LANG_PROGRAM( [[ $3 #undef $1 ]], [[int rv = $1 ($2);]] )], AS_VAR_SET([ac_cv_func_$1_returns_int], yes), AS_VAR_SET([ac_cv_func_$1_returns_int], no) )] ) AS_IF( [test AS_VAR_GET([ac_cv_func_$1_returns_int]) = yes], AC_DEFINE(AS_TR_CPP([HAVE_$1_RETURN_INT]), [1], [Define to 1 if the `$1' function returns int.] ) )] ) munge-munge-0.5.15/m4/x_ac_check_pthreads.m4000066400000000000000000000031111425467526100205610ustar00rootroot00000000000000#****************************************************************************** # AUTHOR: # Chris Dunlap # # SYNOPSIS: # X_AC_CHECK_PTHREADS # # DESCRIPTION: # Check how to link against Pthreads. # # Also define both _REENTRANT and _THREAD_SAFE which may be needed when # linking against multithreaded code. By defining them here, the define # goes into "config.h" which is the first include (in my code, at least). # For more information wrt _REENTRANT, refer to the LinuxThreads FAQ: # . #****************************************************************************** AC_DEFUN([X_AC_CHECK_PTHREADS], [ AC_CACHE_CHECK( [how to link against pthreads], [x_ac_cv_check_pthreads], [ LIBPTHREAD="" _x_ac_check_pthreads_libs_save="$LIBS" for flag in -lpthread -pthread; do LIBS="$flag" AC_LINK_IFELSE([ AC_LANG_PROGRAM( [[#include ]], [[pthread_join (0, 0);]] )], [x_ac_cv_check_pthreads="$flag"; break], [x_ac_cv_check_pthreads=FAILED] ) done LIBS="$_x_ac_check_pthreads_libs_save" ] ) if test "$x_ac_cv_check_pthreads" = "FAILED"; then AC_MSG_FAILURE([cannot link against pthreads]) fi LIBPTHREAD="$x_ac_cv_check_pthreads" AC_SUBST(LIBPTHREAD) AC_DEFINE([_REENTRANT], [1], [Define to 1 if you plan to link against multithreaded code.] ) AC_DEFINE([_THREAD_SAFE], [1], [Define to 1 if you plan to link against multithreaded code.] )] ) munge-munge-0.5.15/m4/x_ac_check_so_peercred.m4000066400000000000000000000016061425467526100212500ustar00rootroot00000000000000#****************************************************************************** # AUTHOR: # Chris Dunlap # # SYNOPSIS: # X_AC_CHECK_SO_PEERCRED # # DESCRIPTION: # Check to see if the SO_PEERCRED socket option is supported. #****************************************************************************** AC_DEFUN([X_AC_CHECK_SO_PEERCRED], [ AC_CACHE_CHECK( [for SO_PEERCRED sockopt], [x_ac_cv_check_so_peercred], [ AC_COMPILE_IFELSE([ AC_LANG_PROGRAM([[ #include #include ]], [[ getsockopt (0, SOL_SOCKET, SO_PEERCRED, 0, 0);]] )], AS_VAR_SET(x_ac_cv_check_so_peercred, yes), AS_VAR_SET(x_ac_cv_check_so_peercred, no) )] ) AS_IF([test AS_VAR_GET(x_ac_cv_check_so_peercred) = yes], AC_DEFINE([HAVE_SO_PEERCRED], [1], [Define to 1 if you have the SO_PEERCRED socket option.] ) )] ) munge-munge-0.5.15/m4/x_ac_darwin.m4000066400000000000000000000012741425467526100171060ustar00rootroot00000000000000#****************************************************************************** # AUTHOR: # Chris Dunlap # # SYNOPSIS: # X_AC_DARWIN # # DESCRIPTION: # Check for Darwin platform-specific issues. # # A different version of certain pthread routines is used when # _APPLE_C_SOURCE is defined. Without it, pthread_cond_wait() is not # recognized as a cancellation point. #****************************************************************************** AC_DEFUN([X_AC_DARWIN], [ case "$host" in *-*-darwin*) AC_DEFINE([_APPLE_C_SOURCE], [1], [Define to 1 if you are building on Darwin (Mac OS X).] ) ;; *) ;; esac ] ) munge-munge-0.5.15/m4/x_ac_debug.m4000066400000000000000000000033171425467526100167100ustar00rootroot00000000000000#****************************************************************************** # AUTHOR: # Chris Dunlap # # SYNOPSIS: # X_AC_DEBUG # # DESCRIPTION: # Add support for the "--enable-debug" configure script option. If enabled, # DEBUGCFLAGS will be set to debugging flags and appended to AM_CFLAGS. # The NDEBUG macro (used by assert) will also be set accordingly. # # NOTES: # This macro must be placed after AC_PROG_CC or equivalent. #****************************************************************************** AC_DEFUN([X_AC_DEBUG], [ AC_MSG_CHECKING([whether debugging is enabled]) AC_ARG_ENABLE( [debug], AS_HELP_STRING([--enable-debug], [enable debugging for code development]), [ case "$enableval" in yes) x_ac_debug=yes ;; no) x_ac_debug=no ;; *) AC_MSG_RESULT([failed]) AC_MSG_ERROR([bad value "$enableval" for --enable-debug]) ;; esac ] ) AS_IF( [test "AS_VAR_GET(x_ac_debug)" = yes], [ AC_REQUIRE([AC_PROG_CC]) # Clear configure's default CFLAGS when not explicitly set by user. AS_IF( [test -z "AS_VAR_GET(ac_env_CFLAGS_set)"], [CFLAGS=] ) [DEBUGCFLAGS="$DEBUGCFLAGS -O0"] AS_IF( [test "AS_VAR_GET(ac_cv_prog_cc_g)" = yes], [DEBUGCFLAGS="$DEBUGCFLAGS -g"] ) AS_IF( [test "AS_VAR_GET(GCC)" = yes], [DEBUGCFLAGS="$DEBUGCFLAGS -Wall -pedantic -std=c99"] ) AM_CFLAGS="$AM_CFLAGS \$(DEBUGCFLAGS)" AC_SUBST([AM_CFLAGS]) AC_SUBST([DEBUGCFLAGS]) ], AC_DEFINE([NDEBUG], [1], [Define to 1 if you are building a production release.] ) ) AC_MSG_RESULT([${x_ac_debug=no}]) ] ) munge-munge-0.5.15/m4/x_ac_getgrent.m4000066400000000000000000000062571425467526100174470ustar00rootroot00000000000000#****************************************************************************** # AUTHOR: # Chris Dunlap # # SYNOPSIS: # X_AC_GETGRENT # # DESCRIPTION: # Check what forms of getgrent() & getgrent_r() are supported. # # NOTES: # The C "Werror" flag is enabled to treat compiler warnings as errors. # This is needed since the getgrent_r() prototypes for AIX and GNU differ # only in the pointer type of the 4th argument (which is reported as a # compiler warning). # # AC_LINK_IFELSE is used instead of AC_COMPILE_IFELSE since these tests # compile successfully on BSD systems without getgrent_r() implementations. # The missing getgrent_r() is detected when linking. #****************************************************************************** AC_DEFUN([X_AC_GETGRENT], [ AC_CHECK_FUNCS(getgrent) _X_AC_GETGRENT_R_AIX _X_AC_GETGRENT_R_GNU _X_AC_GETGRENT_R_SUN ]) AC_DEFUN([_X_AC_GETGRENT_R_AIX], [ AC_CACHE_CHECK( [for getgrent_r (AIX)], [x_ac_cv_have_getgrent_r_aix], [ _x_ac_getgrent_r_aix_c_werror_flag="$ac_c_werror_flag" ac_c_werror_flag=yes AC_LINK_IFELSE([ AC_LANG_PROGRAM([[ #define _THREAD_SAFE 1 #include #include ]], [[ int rv; struct group gr; char gr_buf [1024]; FILE *gr_fp; rv = getgrent_r (&gr, gr_buf, sizeof (gr_buf), &gr_fp); ]] )], AS_VAR_SET(x_ac_cv_have_getgrent_r_aix, yes), AS_VAR_SET(x_ac_cv_have_getgrent_r_aix, no) ) ac_c_werror_flag="$_x_ac_getgrent_r_aix_c_werror_flag"] ) AS_IF([test AS_VAR_GET(x_ac_cv_have_getgrent_r_aix) = yes], AC_DEFINE([HAVE_GETGRENT_R_AIX], [1], [Define to 1 if you have the `getgrent_r' function from AIX.] ) )] ) AC_DEFUN([_X_AC_GETGRENT_R_GNU], [ AC_CACHE_CHECK( [for getgrent_r (GNU)], [x_ac_cv_have_getgrent_r_gnu], [ _x_ac_getgrent_r_gnu_c_werror_flag="$ac_c_werror_flag" ac_c_werror_flag=yes AC_LINK_IFELSE([ AC_LANG_PROGRAM([[ #define _GNU_SOURCE 1 #include ]], [[ int rv; struct group gr, *gr_ptr; char gr_buf [1024]; rv = getgrent_r (&gr, gr_buf, sizeof (gr_buf), &gr_ptr); ]] )], AS_VAR_SET(x_ac_cv_have_getgrent_r_gnu, yes), AS_VAR_SET(x_ac_cv_have_getgrent_r_gnu, no) ) ac_c_werror_flag="$_x_ac_getgrent_r_gnu_c_werror_flag"] ) AS_IF([test AS_VAR_GET(x_ac_cv_have_getgrent_r_gnu) = yes], AC_DEFINE([HAVE_GETGRENT_R_GNU], [1], [Define to 1 if you have the `getgrent_r' function from GNU.] ) )] ) AC_DEFUN([_X_AC_GETGRENT_R_SUN], [ AC_CACHE_CHECK( [for getgrent_r (SunOS)], [x_ac_cv_have_getgrent_r_sun], [ _x_ac_getgrent_r_sun_c_werror_flag="$ac_c_werror_flag" ac_c_werror_flag=yes AC_LINK_IFELSE([ AC_LANG_PROGRAM([[ #include ]], [[ struct group gr, *gr_ptr; char gr_buf [1024]; gr_ptr = getgrent_r (&gr, gr_buf, sizeof (gr_buf)); ]] )], AS_VAR_SET(x_ac_cv_have_getgrent_r_sun, yes), AS_VAR_SET(x_ac_cv_have_getgrent_r_sun, no) ) ac_c_werror_flag="$_x_ac_getgrent_r_sun_c_werror_flag"] ) AS_IF([test AS_VAR_GET(x_ac_cv_have_getgrent_r_sun) = yes], AC_DEFINE([HAVE_GETGRENT_R_SUN], [1], [Define to 1 if you have the `getgrent_r' function from SunOS.] ) )] ) munge-munge-0.5.15/m4/x_ac_getgrnam.m4000066400000000000000000000035101425467526100174210ustar00rootroot00000000000000#****************************************************************************** # AUTHOR: # Chris Dunlap # # SYNOPSIS: # X_AC_GETGRNAM # # DESCRIPTION: # Check what forms of getgrnam() & getgrnam_r() are supported. # Based on x_ac_getpwnam.m4. #****************************************************************************** AC_DEFUN([X_AC_GETGRNAM], [ AC_CHECK_FUNCS(getgrnam) _X_AC_GETGRNAM_R_POSIX _X_AC_GETGRNAM_R_SUN ]) AC_DEFUN([_X_AC_GETGRNAM_R_POSIX], [ AC_CACHE_CHECK( [for getgrnam_r (POSIX)], [x_ac_cv_have_getgrnam_r_posix], [ AC_LINK_IFELSE([ AC_LANG_PROGRAM([[ #define _POSIX_PTHREAD_SEMANTICS 1 /* for SunOS */ #include ]], [[ int rv; char *name; struct group gr, *gr_ptr; char gr_buf [1024]; rv = getgrnam_r (name, &gr, gr_buf, sizeof (gr_buf), &gr_ptr); ]] )], AS_VAR_SET(x_ac_cv_have_getgrnam_r_posix, yes), AS_VAR_SET(x_ac_cv_have_getgrnam_r_posix, no) )] ) AS_IF([test AS_VAR_GET(x_ac_cv_have_getgrnam_r_posix) = yes], AC_DEFINE([HAVE_GETGRNAM_R_POSIX], [1], [Define to 1 if you have the `getgrnam_r' function from POSIX.] ) )] ) AC_DEFUN([_X_AC_GETGRNAM_R_SUN], [ AC_CACHE_CHECK( [for getgrnam_r (SunOS)], [x_ac_cv_have_getgrnam_r_sun], [ AC_LINK_IFELSE([ AC_LANG_PROGRAM([[ #undef _POSIX_PTHREAD_SEMANTICS /* for overriding POSIX getgrnam_r */ #include ]], [[ char *name; struct group gr, *gr_ptr; char gr_buf [1024]; gr_ptr = getgrnam_r (name, &gr, gr_buf, sizeof (gr_buf)); ]] )], AS_VAR_SET(x_ac_cv_have_getgrnam_r_sun, yes), AS_VAR_SET(x_ac_cv_have_getgrnam_r_sun, no) )] ) AS_IF([test AS_VAR_GET(x_ac_cv_have_getgrnam_r_sun) = yes], AC_DEFINE([HAVE_GETGRNAM_R_SUN], [1], [Define to 1 if you have the `getgrnam_r' function from SunOS.] ) )] ) munge-munge-0.5.15/m4/x_ac_getpwnam.m4000066400000000000000000000060711425467526100174440ustar00rootroot00000000000000#****************************************************************************** # AUTHOR: # Chris Dunlap # # SYNOPSIS: # X_AC_GETPWNAM # # DESCRIPTION: # Check what forms of getpwnam() & getpwnam_r() are supported. #****************************************************************************** AC_DEFUN([X_AC_GETPWNAM], [ AC_CHECK_FUNCS(getpwnam) _X_AC_GETPWNAM_R_AIX _X_AC_GETPWNAM_R_POSIX _X_AC_GETPWNAM_R_SUN ]) AC_DEFUN([_X_AC_GETPWNAM_R_AIX], [ AC_CACHE_CHECK( [for getpwnam_r (AIX)], [x_ac_cv_have_getpwnam_r_aix], [ AC_LINK_IFELSE([ AC_LANG_PROGRAM([[ #undef _ALL_SOURCE /* for overriding POSIX getpwnam_r */ #define _THREAD_SAFE 1 #define _UNIX95 1 #define _XOPEN_SOURCE_EXTENDED 1 #include ]], [[ int rv; char *user; struct passwd pw; char pw_buf [1024]; rv = getpwnam_r (user, &pw, pw_buf, sizeof (pw_buf)); ]] )], AS_VAR_SET(x_ac_cv_have_getpwnam_r_aix, yes), AS_VAR_SET(x_ac_cv_have_getpwnam_r_aix, no) )] ) AS_IF([test AS_VAR_GET(x_ac_cv_have_getpwnam_r_aix) = yes], AC_DEFINE([HAVE_GETPWNAM_R_AIX], [1], [Define to 1 if you have the `getpwnam_r' function from AIX.] ) )] ) AC_DEFUN([_X_AC_GETPWNAM_R_POSIX], [ AC_CACHE_CHECK( [for getpwnam_r (POSIX)], [x_ac_cv_have_getpwnam_r_posix], [ AC_LINK_IFELSE([ AC_LANG_PROGRAM([[ #define _POSIX_PTHREAD_SEMANTICS 1 /* for SunOS */ #include ]], [[ int rv; char *user; struct passwd pw, *pw_ptr; char pw_buf [1024]; rv = getpwnam_r (user, &pw, pw_buf, sizeof (pw_buf), &pw_ptr); ]] )], AC_RUN_IFELSE([ AC_LANG_PROGRAM([[ #define _POSIX_PTHREAD_SEMANTICS 1 /* for SunOS */ #include #include #include ]], [[ int rv; char *user = "root"; struct passwd pw, *pw_ptr; char pw_buf; rv = getpwnam_r (user, &pw, &pw_buf, sizeof (pw_buf), &pw_ptr); return ((rv == ERANGE || errno == ERANGE) ? EXIT_SUCCESS : EXIT_FAILURE); ]] )], AS_VAR_SET(x_ac_cv_have_getpwnam_r_posix, yes), AS_VAR_SET(x_ac_cv_have_getpwnam_r_posix, broken), AS_VAR_SET(x_ac_cv_have_getpwnam_r_posix, yes)), AS_VAR_SET(x_ac_cv_have_getpwnam_r_posix, no) )] ) AS_IF([test AS_VAR_GET(x_ac_cv_have_getpwnam_r_posix) = yes], AC_DEFINE([HAVE_GETPWNAM_R_POSIX], [1], [Define to 1 if you have the `getpwnam_r' function from POSIX.] ) )] ) AC_DEFUN([_X_AC_GETPWNAM_R_SUN], [ AC_CACHE_CHECK( [for getpwnam_r (SunOS)], [x_ac_cv_have_getpwnam_r_sun], [ AC_LINK_IFELSE([ AC_LANG_PROGRAM([[ #undef _POSIX_PTHREAD_SEMANTICS /* for overriding POSIX getpwnam_r */ #include ]], [[ char *user; struct passwd pw, *pw_ptr; char pw_buf [1024]; pw_ptr = getpwnam_r (user, &pw, pw_buf, sizeof (pw_buf)); ]] )], AS_VAR_SET(x_ac_cv_have_getpwnam_r_sun, yes), AS_VAR_SET(x_ac_cv_have_getpwnam_r_sun, no) )] ) AS_IF([test AS_VAR_GET(x_ac_cv_have_getpwnam_r_sun) = yes], AC_DEFINE([HAVE_GETPWNAM_R_SUN], [1], [Define to 1 if you have the `getpwnam_r' function from SunOS.] ) )] ) munge-munge-0.5.15/m4/x_ac_humor.m4000066400000000000000000000024161425467526100167530ustar00rootroot00000000000000############################################################################### # SYNOPSIS: # X_AC_HUMOR # # DESCRIPTION: # Check for random silliness. ############################################################################### AC_DEFUN([X_AC_HUMOR], [ AC_MSG_CHECKING([for a sense of humor]) [n=$(expr $$ % 16)] AS_IF( [test "${n}" -eq 0], [x_ac_humor="no"], [test "${n}" -eq 1], [x_ac_humor="yes"], [test "${n}" -eq 2], [x_ac_humor="meh"], [test "${n}" -eq 3], [x_ac_humor="narf"], [test "${n}" -eq 4], [x_ac_humor="try again"], [test "${n}" -eq 5], [x_ac_humor="that tickles"], [test "${n}" -eq 6], [x_ac_humor="inconceivable"], [test "${n}" -eq 7], [x_ac_humor="good news, everyone"], [test "${n}" -eq 8], [x_ac_humor="where's the kaboom?"], [test "${n}" -eq 9], [x_ac_humor="missed it by that much"], [test "${n}" -eq 10], [x_ac_humor="roll for ability check"], [test "${n}" -eq 11], [x_ac_humor="it goes to eleven"], [test "${n}" -eq 12], [x_ac_humor="a hollow voice says 'PLUGH'"], [test "${n}" -eq 13], [x_ac_humor="no boom today... boom tomorrow"], [test "${n}" -eq 14], [x_ac_humor="and now for something completely different"], [x_ac_humor="don't panic"]) AC_MSG_RESULT([$x_ac_humor]) ]) munge-munge-0.5.15/m4/x_ac_path_openssl.m4000066400000000000000000000041551425467526100203220ustar00rootroot00000000000000#****************************************************************************** # AUTHOR: # Chris Dunlap # # SYNOPSIS: # X_AC_PATH_OPENSSL # # DESCRIPTION: # Search the usual suspects for an OpenSSL installation. # If found, set the makefile variables OPENSSL_CFLAGS and OPENSSL_LIBS. # # NOTES: # The $x_ac_path_openssl_prefix result is not cached since the selected # OpenSSL installation should be based on the specified 32-bit or 64-bit # architecture. # # WARNINGS: # This macro must be placed after AC_PROG_CC. #****************************************************************************** AC_DEFUN([X_AC_PATH_OPENSSL], [ AC_MSG_CHECKING([for OpenSSL installation]) _x_ac_path_openssl_dirs="/usr /usr/local /usr/local/openssl* /usr/sfw /opt /opt/openssl* /opt/freeware /opt/freeware/openssl*" AC_ARG_WITH( [openssl-prefix], AS_HELP_STRING( [--with-openssl-prefix=PATH], [specify path to OpenSSL installation]), [ test "$withval" = "no" \ && x_ac_path_openssl_prefix="no" \ || _x_ac_path_openssl_dirs="$withval $_x_ac_path_openssl_dirs" ]) if test "$x_ac_path_openssl_prefix" != "no"; then x_ac_path_openssl_prefix="no" for d in $_x_ac_path_openssl_dirs; do test -d "$d" || continue test -d "$d/include" || continue test -f "$d/include/openssl/evp.h" || continue test -d "$d/lib" || continue _x_ac_path_openssl_libs_save="$LIBS" LIBS="-L$d/lib -lcrypto $LIBS" AC_LINK_IFELSE( [AC_LANG_CALL([], RAND_status)], x_ac_path_openssl_prefix="$d") LIBS="$_x_ac_path_openssl_libs_save" test "$x_ac_path_openssl_prefix" != "no" && break done fi if test "$x_ac_path_openssl_prefix" != "no"; then OPENSSL_CFLAGS="" OPENSSL_LIBS="-lcrypto" if test "$x_ac_path_openssl_prefix" != "/usr"; then OPENSSL_CFLAGS="-I$x_ac_path_openssl_prefix/include $OPENSSL_CFLAGS" OPENSSL_LIBS="-L$x_ac_path_openssl_prefix/lib $OPENSSL_LIBS" fi AC_SUBST([OPENSSL_CFLAGS]) AC_SUBST([OPENSSL_LIBS]) fi AC_MSG_RESULT([$x_ac_path_openssl_prefix]) ]) munge-munge-0.5.15/m4/x_ac_select_auth_method.m4000066400000000000000000000115311425467526100214570ustar00rootroot00000000000000#****************************************************************************** # AUTHOR: # Chris Dunlap # # SYNOPSIS: # X_AC_SELECT_AUTH_METHOD # # DESCRIPTION: # Select the client authentication method used by MUNGE. # # NOTES: # MUNGE supports the following methods for authenticating the UID and GID # of a client: # # AUTH_METHOD_GETPEEREID # (AIX 5.2-ML4, Darwin, FreeBSD 4.6, NetBSD 5.0, OpenBSD 3.0) # The server uses getpeereid() to determine the identity of the client # connected across the Unix domain socket. # # AUTH_METHOD_GETPEERUCRED # (SunOS 5.10) # The server uses getpeerucred() to determine the identity of the client # connected across the Unix domain socket. The client's UID and GID are # then obtained via ucred_geteuid() and ucred_getegid(). # # AUTH_METHOD_SO_PEERCRED # (Linux) # The server uses the SO_PEERCRED socket option to determine the identity # of the client connected across the Unix domain socket. The client's UID # and GID are then obtained from the ucred struct returned by # getsockopt(). # # AUTH_METHOD_LOCAL_PEERCRED # (Darwin, FreeBSD, GNU/kFreeBSD) # The server uses the LOCAL_PEERCRED socket option to determine the # identity of the client connected across the Unix domain socket. The # client's UID and GID are then obtained from the xucred struct returned # by getsockopt(). # # AUTH_METHOD_RECVFD_MKFIFO # (Irix, SunOS) # The server creates a unique FIFO special file via mkfifo() and sends a # request to the client for it to pass an open file descriptor back across # this FIFO. The client creates a unique file and sends the open # descriptor using the I_SENDFD ioctl(), whereby the server receives it # using the I_RECVFD ioctl(). The identity of the client is then obtained # from the strrecvfd struct used to receive the file descriptor. # # AUTH_METHOD_RECVFD_MKNOD # (AIX) # The server creates a unique STREAMS-based pipe via mknod() and sends a # request to the client for it to pass an open file descriptor back across # this pipe. The client creates a unique file and sends the open # descriptor using the I_SENDFD ioctl(), whereby the server receives it # using the I_RECVFD ioctl(). The identity of the client is then obtained # from the strrecvfd struct used to receive the file descriptor. The # server requires root privileges in order to create this pipe. #****************************************************************************** AC_DEFUN([X_AC_SELECT_AUTH_METHOD], [ AC_MSG_NOTICE([checking authentication support]) AC_CHECK_FUNCS(getpeereid) AC_CHECK_FUNCS(getpeerucred) AC_CHECK_HEADERS(ucred.h) AC_CHECK_TYPES(struct ucred, [], [], [#include ]) X_AC_CHECK_SO_PEERCRED AC_CHECK_TYPES(struct xucred, [], [], [#include #include #include ]) X_AC_CHECK_LOCAL_PEERCRED AC_CHECK_TYPES(struct strrecvfd, [], [], [#include ]) X_AC_CHECK_FIFO_RECVFD AC_CHECK_FILES(/dev/spx) AC_MSG_CHECKING([for authentication method]) if test AS_VAR_GET(ac_cv_func_getpeereid) = yes ; then AUTH_METHOD=AUTH_METHOD_GETPEEREID AC_DEFINE([AUTH_METHOD_GETPEEREID], [1], [Define to 1 if authenticating via AUTH_METHOD_GETPEEREID] ) elif test AS_VAR_GET(ac_cv_func_getpeerucred) = yes \ -a AS_VAR_GET(ac_cv_header_ucred_h) = yes ; then AUTH_METHOD=AUTH_METHOD_GETPEERUCRED AC_DEFINE([AUTH_METHOD_GETPEERUCRED], [1], [Define to 1 if authenticating via AUTH_METHOD_GETPEERUCRED] ) elif test AS_VAR_GET(ac_cv_type_struct_ucred) = yes \ -a AS_VAR_GET(x_ac_cv_check_so_peercred) = yes ; then AUTH_METHOD=AUTH_METHOD_SO_PEERCRED AC_DEFINE([AUTH_METHOD_SO_PEERCRED], [1], [Define to 1 if authenticating via AUTH_METHOD_SO_PEERCRED] ) elif test AS_VAR_GET(ac_cv_type_struct_xucred) = yes \ -a AS_VAR_GET(x_ac_cv_check_local_peercred) = yes ; then AUTH_METHOD=AUTH_METHOD_LOCAL_PEERCRED AC_DEFINE([AUTH_METHOD_LOCAL_PEERCRED], [1], [Define to 1 if authenticating via AUTH_METHOD_LOCAL_PEERCRED] ) elif test AS_VAR_GET(ac_cv_type_struct_strrecvfd) = yes \ -a AS_VAR_GET(x_ac_cv_check_fifo_recvfd) = yes ; then AUTH_METHOD=AUTH_METHOD_RECVFD_MKFIFO AC_DEFINE([AUTH_METHOD_RECVFD_MKFIFO], [1], [Define to 1 if authenticating via AUTH_METHOD_RECVFD_MKFIFO] ) elif test AS_VAR_GET(ac_cv_type_struct_strrecvfd) = yes \ -a AS_VAR_GET(ac_cv_file__dev_spx) = yes ; then AUTH_METHOD=AUTH_METHOD_RECVFD_MKNOD AC_DEFINE([AUTH_METHOD_RECVFD_MKNOD], [1], [Define to 1 if authenticating via AUTH_METHOD_RECVFD_MKNOD] ) else AC_MSG_RESULT([failed]) AC_MSG_ERROR([cannot determine authentication method]) fi AC_MSG_RESULT([$AUTH_METHOD]) ]) munge-munge-0.5.15/m4/x_ac_select_crypto_lib.m4000066400000000000000000000037561425467526100213360ustar00rootroot00000000000000#****************************************************************************** # AUTHOR: # Chris Dunlap # # SYNOPSIS: # X_AC_SELECT_CRYPTO_LIB # # DESCRIPTION: # Select either the Libgcrypt or OpenSSL cryptographic library, # or throw a fatal error. # Define either HAVE_LIBGCRYPT or HAVE_OPENSSL. # Set the makefile variables CRYPTO_CFLAGS, CRYPTO_LIBS, and CRYPTO_PKG. # # NOTES: # The HAVE_LIBGCRYPT and HAVE_OPENSSL defs are mutually-exclusive. # # WARNINGS: # This macro must be placed after AM_PATH_LIBGCRYPT and X_AC_PATH_OPENSSL. #****************************************************************************** AC_DEFUN([X_AC_SELECT_CRYPTO_LIB], [ AC_MSG_CHECKING([which cryptographic library to use]) AC_ARG_WITH( [crypto-lib], AS_HELP_STRING( [--with-crypto-lib=(libgcrypt|openssl)], [specify which cryptographic library to use]), [ case "$withval" in libgcrypt) CRYPTO_PKG="libgcrypt" ;; openssl) CRYPTO_PKG="openssl" ;; *) AC_MSG_RESULT([specify either "libgcrypt" or "openssl"]) AC_MSG_ERROR([bad value "$withval" for --with-crypto-lib]) ;; esac ]) if test -n "$OPENSSL_LIBS" -a \ \( "$CRYPTO_PKG" = "openssl" -o -z "$CRYPTO_PKG" \) ; then CRYPTO_CFLAGS="$OPENSSL_CFLAGS" CRYPTO_LIBS="$OPENSSL_LIBS" CRYPTO_PKG="openssl" AC_DEFINE([HAVE_OPENSSL], [1], [Define to 1 if you want to use the OpenSSL cryptographic library.]) elif test -n "$LIBGCRYPT_LIBS" -a \ \( "$CRYPTO_PKG" = "libgcrypt" -o -z "$CRYPTO_PKG" \) ; then CRYPTO_CFLAGS="$LIBGCRYPT_CFLAGS" CRYPTO_LIBS="$LIBGCRYPT_LIBS" CRYPTO_PKG="libgcrypt" AC_DEFINE([HAVE_LIBGCRYPT], [1], [Define to 1 if you want to use the Libgcrypt cryptographic library.]) else AC_MSG_RESULT([failed]) AC_MSG_ERROR([unable to locate cryptographic library]) fi AC_SUBST([CRYPTO_CFLAGS]) AC_SUBST([CRYPTO_LIBS]) AC_SUBST([CRYPTO_PKG]) AC_MSG_RESULT([$CRYPTO_PKG]) ]) munge-munge-0.5.15/m4/x_ac_with_logrotateddir.m4000066400000000000000000000027671425467526100215300ustar00rootroot00000000000000############################################################################### # SYNOPSIS: # X_AC_WITH_LOGROTATEDDIR # # DESCRIPTION: # The "--with-logrotateddir" option sets "logrotateddir", the installation # directory for logrotate config files. # # By default (or if this option is specified without a directory name), # logrotateddir will be set to "${sysconfdir}/logrotate.d" (if the # /etc/logrotate.d directory exists on the build system). ############################################################################### AC_DEFUN([X_AC_WITH_LOGROTATEDDIR], [ AC_MSG_CHECKING([for logrotateddir]) AC_ARG_WITH( [logrotateddir], [AS_HELP_STRING( [--with-logrotateddir@<:@=DIR@:>@], [logrotate config file installation directory])]) AS_IF( [test "x${with_logrotateddir}" = xyes \ || test "x${with_logrotateddir}" = x], [AS_IF( [test -d /etc/logrotate.d], [logrotateddir='${sysconfdir}/logrotate.d'])], [expr "x${with_logrotateddir}" : "x\/" >/dev/null 2>&1], [logrotateddir=${with_logrotateddir}], [test "x${with_logrotateddir}" != xno], [AC_MSG_RESULT([failed]) AC_MSG_ERROR( [expected an absolute directory name for --with-logrotateddir=${with_logrotateddir}])]) AS_IF( [test "x${logrotateddir}" = x && test "x${with_logrotateddir}" = xyes], [AC_MSG_RESULT([failed]) AC_MSG_ERROR([logrotateddir requested but not found])]) AC_SUBST([logrotateddir]) AC_MSG_RESULT([${logrotateddir:-disabled}]) ]) munge-munge-0.5.15/m4/x_ac_with_munge_socket.m4000066400000000000000000000026421425467526100213400ustar00rootroot00000000000000############################################################################### # SYNOPSIS: # X_AC_WITH_MUNGE_SOCKET # # DESCRIPTION: # The "--with-munge-socket" option overrides MUNGE_SOCKET_NAME, the default # pathname of the MUNGE UNIX domain socket for communications between # client (libmunge) and server (munged). ############################################################################### AC_DEFUN([X_AC_WITH_MUNGE_SOCKET], [ AC_MSG_CHECKING([for MUNGE socket pathname]) AC_ARG_WITH( [munge-socket], [AS_HELP_STRING( [--with-munge-socket=PATH], [MUNGE socket pathname default])]) AS_IF( [test "x${with_munge_socket}" = xyes], [AC_MSG_RESULT([failed]) AC_MSG_ERROR([missing argument to --with-munge-socket])], [test "x${with_munge_socket}" = xno], [AC_MSG_RESULT([failed]) AC_MSG_ERROR([invalid option --without-munge-socket])], [expr "x${with_munge_socket}" : "x\/" >/dev/null 2>&1], [x_ac_with_munge_socket="${with_munge_socket}"], [test "x${with_munge_socket}" != x], [AC_MSG_RESULT([failed]) AC_MSG_ERROR( [expected an absolute pathname for --with-munge-socket=${with_munge_socket}])]) AS_IF( [test "x${x_ac_with_munge_socket}" != x], [AC_DEFINE_UNQUOTED( [MUNGE_SOCKET_NAME], ["${x_ac_with_munge_socket}"], [Define the MUNGE socket pathname default.])]) AC_MSG_RESULT([${x_ac_with_munge_socket:-default}]) ]) munge-munge-0.5.15/m4/x_ac_with_pkgconfigdir.m4000066400000000000000000000027551425467526100213300ustar00rootroot00000000000000############################################################################### # SYNOPSIS: # X_AC_WITH_PKGCONFIGDIR # # DESCRIPTION: # The "--with-pkgconfigdir" option sets "pkgconfigdir", the installation # directory for pkg-config .pc files. # # By default (or if this option is specified without a directory name), # pkgconfigdir will be set to "${libdir}/pkgconfig" (if some # /usr/lib*/pkgconfig directory exists on the build system). ############################################################################### AC_DEFUN([X_AC_WITH_PKGCONFIGDIR], [ AC_MSG_CHECKING([for pkgconfigdir]) AC_ARG_WITH( [pkgconfigdir], [AS_HELP_STRING( [--with-pkgconfigdir@<:@=DIR@:>@], [pkg-config .pc file installation directory])]) AS_IF( [test "x${with_pkgconfigdir}" = xyes \ || test "x${with_pkgconfigdir}" = x], [AS_IF( [find /usr/lib*/pkgconfig -type d >/dev/null 2>&1], [pkgconfigdir='${libdir}/pkgconfig'])], [expr "x${with_pkgconfigdir}" : "x\/" >/dev/null 2>&1], [pkgconfigdir=${with_pkgconfigdir}], [test "x${with_pkgconfigdir}" != xno], [AC_MSG_RESULT([failed]) AC_MSG_ERROR( [expected an absolute directory name for --with-pkgconfigdir=${with_pkgconfigdir}])]) AS_IF( [test "x${pkgconfigdir}" = x && test "x${with_pkgconfigdir}" = xyes], [AC_MSG_RESULT([failed]) AC_MSG_ERROR([pkgconfigdir requested but not found])]) AC_SUBST([pkgconfigdir]) AC_MSG_RESULT([${pkgconfigdir:-disabled}]) ]) munge-munge-0.5.15/m4/x_ac_with_runstatedir.m4000066400000000000000000000032531425467526100212200ustar00rootroot00000000000000############################################################################### # SYNOPSIS: # X_AC_WITH_RUNSTATEDIR # # DESCRIPTION: # The "--with-runstatedir" option sets "runstatedir", the installation # directory for modifiable per-process data. It is functionally equivalent # to the "--runstatedir" option (slated to appear in autoconf 2.70, and # backported to Debian's and Ubuntu's autoconf 2.69-9). However, # "--with-runstatedir" will override "--runstatedir" if both are specified. # # This option requires an absolute pathname for its directory argument. # # If this option is not specified, runstatedir will default to # "${localstatedir}/run". ############################################################################### AC_DEFUN([X_AC_WITH_RUNSTATEDIR], [ AC_MSG_CHECKING([for runstatedir]) AC_ARG_WITH( [runstatedir], [AS_HELP_STRING( [--with-runstatedir=DIR], [modifiable per-process data installation directory @<:@LOCALSTATEDIR/run@:>@])]) AS_IF( [test "x${with_runstatedir}" = xyes], [AC_MSG_RESULT([failed]) AC_MSG_ERROR([missing argument to --with-runstatedir])], [test "x${with_runstatedir}" = xno], [AC_MSG_RESULT([failed]) AC_MSG_ERROR([illegal option --without-runstatedir])], [expr "x${with_runstatedir}" : "x\/" >/dev/null 2>&1], [runstatedir="${with_runstatedir}"], [test "x${with_runstatedir}" != x], [AC_MSG_RESULT([failed]) AC_MSG_ERROR( [expected an absolute directory name for --with-runstatedir=${with_runstatedir}])]) AS_IF( [test "x${runstatedir}" = x], [AC_SUBST([runstatedir], ['${localstatedir}/run'])]) AC_MSG_RESULT([${runstatedir}]) ]) munge-munge-0.5.15/m4/x_ac_with_sysconfigdir.m4000066400000000000000000000031441425467526100213560ustar00rootroot00000000000000############################################################################### # SYNOPSIS: # X_AC_WITH_SYSCONFIGDIR # # DESCRIPTION: # The "--with-sysconfigdir" option sets "sysconfigdir", the installation # directory for systemd/sysvinit system configuration files. # # By default (or if this option is specified without a directory name), # sysconfigdir will be set to either "${sysconfdir}/sysconfig" or # "${sysconfdir}/default" if the corresponding subdirectory exists in /etc # on the build system. ############################################################################### AC_DEFUN([X_AC_WITH_SYSCONFIGDIR], [ AC_MSG_CHECKING([for sysconfigdir]) AC_ARG_WITH( [sysconfigdir], [AS_HELP_STRING( [--with-sysconfigdir@<:@=DIR@:>@], [systemd/sysvinit config file installation directory])]) AS_IF( [test "x${with_sysconfigdir}" = xyes \ || test "x${with_sysconfigdir}" = x], [AS_IF( [test -d /etc/sysconfig], [sysconfigdir='${sysconfdir}/sysconfig'], [test -d /etc/default], [sysconfigdir='${sysconfdir}/default'])], [expr "x${with_sysconfigdir}" : "x\/" >/dev/null 2>&1], [sysconfigdir=${with_sysconfigdir}], [test "x${with_sysconfigdir}" != xno], [AC_MSG_RESULT([failed]) AC_MSG_ERROR( [expected an absolute directory name for --with-sysconfigdir=${with_sysconfigdir}])]) AS_IF( [test "x${sysconfigdir}" = x && test "x${with_sysconfigdir}" = xyes], [AC_MSG_RESULT([failed]) AC_MSG_ERROR([sysconfigdir requested but not found])]) AC_SUBST([sysconfigdir]) AC_MSG_RESULT([${sysconfigdir:-disabled}]) ]) munge-munge-0.5.15/m4/x_ac_with_systemdunitdir.m4000066400000000000000000000030241425467526100217370ustar00rootroot00000000000000############################################################################### # SYNOPSIS: # X_AC_WITH_SYSTEMDUNITDIR # # DESCRIPTION: # The "--with-systemdunitdir" option sets "systemdunitdir", the installation # directory for systemd service files. # # By default (or if this option is specified without a directory name), # systemdunitdir will be set to "${prefix}/lib/systemd/system" if systemd # appears to be installed on the build system. ############################################################################### AC_DEFUN([X_AC_WITH_SYSTEMDUNITDIR], [ AC_MSG_CHECKING([for systemdunitdir]) AC_ARG_WITH( [systemdunitdir], [AS_HELP_STRING( [--with-systemdunitdir@<:@=DIR@:>@], [systemd service file installation directory])]) AS_IF( [test "x${with_systemdunitdir}" = xyes \ || test "x${with_systemdunitdir}" = x], [AS_IF( [systemctl --version >/dev/null 2>&1], [systemdunitdir='${prefix}/lib/systemd/system'])], [expr "x${with_systemdunitdir}" : "x\/" >/dev/null 2>&1], [systemdunitdir=${with_systemdunitdir}], [test "x${with_systemdunitdir}" != xno], [AC_MSG_RESULT([failed]) AC_MSG_ERROR( [expected an absolute directory name for --with-systemdunitdir=${with_systemdunitdir}])]) AS_IF( [test "x${systemdunitdir}" = x && test "x${with_systemdunitdir}" = xyes], [AC_MSG_RESULT([failed]) AC_MSG_ERROR([systemdunitdir requested but not found])]) AC_SUBST([systemdunitdir]) AC_MSG_RESULT([${systemdunitdir:-disabled}]) ]) munge-munge-0.5.15/m4/x_ac_with_sysvinitddir.m4000066400000000000000000000032451425467526100214100ustar00rootroot00000000000000############################################################################### # SYNOPSIS: # X_AC_WITH_SYSVINITDDIR # # DESCRIPTION: # The "--with-sysvinitddir" option sets "sysvinitddir", the installation # directory for SysV init scripts. # # By default, sysvinitddir will be disabled/unset if systemdunitdir is set. # Otherwise, sysvinitddir will default to either "${sysconfdir}/rc.d/init.d" # or "${sysconfdir}/init.d" if that directory exists on the build system. ############################################################################### AC_DEFUN([X_AC_WITH_SYSVINITDDIR], [ AC_REQUIRE([X_AC_WITH_SYSTEMDUNITDIR]) AC_MSG_CHECKING([for sysvinitddir]) AC_ARG_WITH( [sysvinitddir], [AS_HELP_STRING( [--with-sysvinitddir@<:@=DIR@:>@], [SysV init script installation directory])]) AS_IF( [test "x${with_sysvinitddir}" = xyes \ || (test "x${with_sysvinitddir}" = x && test "x${systemdunitdir}" = x)], [AS_IF( [test -d /etc/rc.d/init.d], [sysvinitddir='${sysconfdir}/rc.d/init.d'], [test -d /etc/init.d], [sysvinitddir='${sysconfdir}/init.d'])], [expr "x${with_sysvinitddir}" : "x\/" >/dev/null 2>&1], [sysvinitddir=${with_sysvinitddir}], [test "x${with_sysvinitddir}" != xno && test "x${with_sysvinitddir}" != x], [AC_MSG_RESULT([failed]) AC_MSG_ERROR( [expected an absolute directory name for --with-sysvinitddir=${with_sysvinitddir}])]) AS_IF( [test "x${sysvinitddir}" = x && test "x${with_sysvinitddir}" = xyes], [AC_MSG_RESULT([failed]) AC_MSG_ERROR([sysvinitddir requested but not found])]) AC_SUBST([sysvinitddir]) AC_MSG_RESULT([${sysvinitddir:-disabled}]) ]) munge-munge-0.5.15/munge.spec.in000066400000000000000000000123761425467526100164470ustar00rootroot00000000000000Name: munge Version: @VERSION@ Release: 1%{?dist} # Disable test suite by default; add "--with check" to enable. %bcond_with check # Disable source file verification by default; add "--with verify" to enable. # Requires a detached signature (Source1) and gpg public key (Source2). %bcond_with verify # Enable hardened build since munged is a long-running daemon. %global _hardened_build 1 Summary: MUNGE authentication service License: GPLv3+ URL: https://dun.github.io/munge/ Source0: https://github.com/dun/munge/releases/download/%{name}-%{version}/%{name}-%{version}.tar.xz %if %{with verify} Source1: https://github.com/dun/munge/releases/download/%{name}-%{version}/%{name}-%{version}.tar.xz.asc Source2: https://github.com/dun.gpg %endif BuildRequires: gnupg2 BuildRequires: make BuildRequires: gcc BuildRequires: bzip2-devel BuildRequires: openssl-devel BuildRequires: zlib-devel BuildRequires: systemd BuildRequires: procps Requires: %{name}-libs%{?_isa} = %{version}-%{release} Requires: logrotate Requires(pre): shadow-utils %{?systemd_requires} %description MUNGE (MUNGE Uid 'N' Gid Emporium) is an authentication service for creating and validating user credentials. It is designed to be highly scalable for use in an HPC cluster environment. It provides a portable API for encoding the user's identity into a tamper-proof credential that can be obtained by an untrusted client and forwarded by untrusted intermediaries within a security realm. Clients within this realm can create and validate credentials without the use of root privileges, reserved ports, or platform-specific methods. %package devel Summary: MUNGE authentication service development files License: LGPLv3+ Requires: pkgconfig Requires: %{name}-libs%{?_isa} = %{version}-%{release} %description devel Development files for building applications that use libmunge. %package libs Summary: MUNGE authentication service shared library License: LGPLv3+ Requires: %{name} = %{version}-%{release} %description libs The shared library (libmunge) for running applications that use MUNGE. %prep %if %{with verify} %if %{defined gpgverify} %{gpgverify} --keyring='%{SOURCE2}' --signature='%{SOURCE1}' --data='%{SOURCE0}' %else gpg2 --import --import-options import-minimal --no-default-keyring \ --keyring ./keyring.gpg '%{SOURCE2}' gpgv2 --keyring ./keyring.gpg '%{SOURCE1}' '%{SOURCE0}' %endif %endif %setup -q %build %configure --disable-static \ --with-crypto-lib=openssl \ --with-logrotateddir=%{_sysconfdir}/logrotate.d \ --with-pkgconfigdir=%{_libdir}/pkgconfig \ --with-runstatedir=%{_rundir} \ --with-systemdunitdir=%{_unitdir} sed -i 's|^hardcode_libdir_flag_spec=.*|hardcode_libdir_flag_spec=""|g' libtool sed -i 's|^runpath_var=LD_RUN_PATH|runpath_var=DIE_RPATH_DIE|g' libtool %make_build %check %if %{with check} %make_build check \ LD_LIBRARY_PATH=%{buildroot}%{_libdir} \ root=/tmp/munge-test-$$ verbose=t VERBOSE=t %endif %install %make_install touch %{buildroot}%{_sysconfdir}/munge/munge.key touch %{buildroot}%{_localstatedir}/lib/munge/munged.seed touch %{buildroot}%{_localstatedir}/log/munge/munged.log mkdir -p %{buildroot}%{_rundir}/munge touch %{buildroot}%{_rundir}/munge/munged.pid # %if 0%{?rhel} == 7 sed -i '/^RuntimeDirectory/ s/^/#/' %{buildroot}%{_unitdir}/munge.service mkdir -p %{buildroot}%{_tmpfilesdir} install -m 0644 src/etc/munge.tmpfiles.conf %{buildroot}%{_tmpfilesdir}/munge.conf %endif %pre getent group munge >/dev/null || \ groupadd -r munge getent passwd munge >/dev/null || \ useradd -c "MUNGE authentication service" -d "%{_sysconfdir}/munge" \ -g munge -s /sbin/nologin -r munge exit 0 %post if test ! -f %{_sysconfdir}/munge/munge.key; then echo "Run %{_sbindir}/mungekey as the munge user to create a key." echo "For example: \"sudo -u munge %{_sbindir}/mungekey -v\"." echo "Refer to the mungekey(8) manpage for more information." fi %systemd_post munge.service # %if 0%{?rhel} == 7 systemd-tmpfiles --create %{_tmpfilesdir}/munge.conf %endif %post libs -p /sbin/ldconfig %preun %systemd_preun munge.service %postun %systemd_postun_with_restart munge.service %postun libs -p /sbin/ldconfig %files %{!?_licensedir:%global license %doc} %license COPYING* %doc AUTHORS %doc DISCLAIMER* %doc HISTORY %doc JARGON %doc KEYS %doc NEWS %doc PLATFORMS %doc QUICKSTART %doc README %doc THANKS %doc doc/credential_v3_format.txt %dir %attr(0700,munge,munge) %{_sysconfdir}/munge %attr(0600,munge,munge) %config(noreplace) %ghost %{_sysconfdir}/munge/munge.key %config(noreplace) %{_sysconfdir}/logrotate.d/munge %config(noreplace) %{_sysconfdir}/sysconfig/munge %dir %attr(0700,munge,munge) %{_localstatedir}/lib/munge %attr(0600,munge,munge) %ghost %{_localstatedir}/lib/munge/munged.seed %dir %attr(0700,munge,munge) %{_localstatedir}/log/munge %attr(0640,munge,munge) %ghost %{_localstatedir}/log/munge/munged.log %dir %attr(0755,munge,munge) %ghost %{_rundir}/munge %attr(0644,munge,munge) %ghost %{_rundir}/munge/munged.pid %{_bindir}/* %{_sbindir}/* %{_mandir}/man[^3]/* %{_unitdir}/munge.service # %if 0%{?rhel} == 7 %{_tmpfilesdir}/munge.conf %endif %files devel %{_includedir}/* %if 0%{?fedora} < 36 %{_libdir}/libmunge.la %endif %{_libdir}/libmunge.so %{_libdir}/pkgconfig/munge.pc %{_mandir}/man3/* %files libs %{_libdir}/libmunge.so.2 %{_libdir}/libmunge.so.2.0.0 munge-munge-0.5.15/src/000077500000000000000000000000001425467526100146315ustar00rootroot00000000000000munge-munge-0.5.15/src/Makefile.am000066400000000000000000000004571425467526100166730ustar00rootroot00000000000000# MUNGE src/Makefile.am # # This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE). # For details, see . include $(top_srcdir)/Make-inc.mk SUBDIRS = \ common \ etc \ libcommon \ libmissing \ libmunge \ libtap \ munge \ munged \ mungekey \ # End of SUBDIRS munge-munge-0.5.15/src/common/000077500000000000000000000000001425467526100161215ustar00rootroot00000000000000munge-munge-0.5.15/src/common/Makefile.am000066400000000000000000000035721425467526100201640ustar00rootroot00000000000000# MUNGE src/common/Makefile.am # # This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE). # For details, see . include $(top_srcdir)/Make-inc.mk check_PROGRAMS = \ $(TESTS) \ # End of check_PROGRAMS TESTS = \ hkdf_api_test \ hkdf_rfc_test \ mac_test \ # End of TESTS hkdf_api_test_CPPFLAGS = \ -I$(top_srcdir)/src/libcommon \ -I$(top_srcdir)/src/libmunge \ -I$(top_srcdir)/src/libtap \ $(CRYPTO_CFLAGS) \ # End of hkdf_api_test_CPPFLAGS hkdf_api_test_LDADD = \ $(top_builddir)/src/libcommon/libcommon.la \ $(top_builddir)/src/libmunge/libmunge.la \ $(top_builddir)/src/libtap/libtap.la \ $(CRYPTO_LIBS) \ # End of hkdf_api_test_LDADD hkdf_api_test_SOURCES = \ crypto.c \ crypto.h \ hkdf.c \ hkdf.h \ mac.c \ mac.h \ md.c \ md.h \ hkdf_api_test.c \ # End of hkdf_api_test_SOURCES hkdf_rfc_test_CPPFLAGS = \ -I$(top_srcdir)/src/libcommon \ -I$(top_srcdir)/src/libmunge \ -I$(top_srcdir)/src/libtap \ $(CRYPTO_CFLAGS) \ # End of hkdf_rfc_test_CPPFLAGS hkdf_rfc_test_LDADD = \ $(top_builddir)/src/libcommon/libcommon.la \ $(top_builddir)/src/libmunge/libmunge.la \ $(top_builddir)/src/libtap/libtap.la \ $(CRYPTO_LIBS) \ # End of hkdf_rfc_test_LDADD hkdf_rfc_test_SOURCES = \ crypto.c \ crypto.h \ hkdf.c \ hkdf.h \ mac.c \ mac.h \ md.c \ md.h \ hkdf_rfc_test.c \ # End of hkdf_rfc_test_SOURCES mac_test_CPPFLAGS = \ -I$(top_srcdir)/src/libcommon \ -I$(top_srcdir)/src/libmunge \ -I$(top_srcdir)/src/libtap \ $(CRYPTO_CFLAGS) \ # End of mac_test_CPPFLAGS mac_test_LDADD = \ $(top_builddir)/src/libcommon/libcommon.la \ $(top_builddir)/src/libmunge/libmunge.la \ $(top_builddir)/src/libtap/libtap.la \ $(CRYPTO_LIBS) \ # End of mac_test_LDADD mac_test_SOURCES = \ crypto.c \ crypto.h \ mac.c \ mac.h \ md.c \ md.h \ mac_test.c \ # End of mac_test_SOURCES .NOTPARALLEL: hkdf_api_test hkdf_rfc_test mac_test munge-munge-0.5.15/src/common/crypto.c000066400000000000000000000300241425467526100176040ustar00rootroot00000000000000/***************************************************************************** * Written by Chris Dunlap . * Copyright (C) 2007-2022 Lawrence Livermore National Security, LLC. * Copyright (C) 2002-2007 The Regents of the University of California. * UCRL-CODE-155910. * * This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE). * For details, see . * * MUNGE 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. Additionally for the MUNGE library (libmunge), you * can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation, * either version 3 of the License, or (at your option) any later version. * * MUNGE 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 * and GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * and GNU Lesser General Public License along with MUNGE. If not, see * . *****************************************************************************/ #if HAVE_CONFIG_H # include #endif /* HAVE_CONFIG_H */ #include #include #include #include #include "crypto.h" #include "log.h" /***************************************************************************** * Libgcrypt Functions *****************************************************************************/ #if HAVE_LIBGCRYPT #include #if GCRYPT_VERSION_NUMBER < 0x010600 GCRY_THREAD_OPTION_PTHREAD_IMPL; #endif /* GCRYPT_VERSION_NUMBER */ void crypto_init (void) { gcry_error_t e; const char *v; #if GCRYPT_VERSION_NUMBER < 0x010600 /* GCRYCTL_SET_THREAD_CBS must be set before any other Libcrypt function. * Obsolete since Libgcrypt 1.6. */ e = gcry_control (GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread); if (e) { log_err (EMUNGE_SNAFU, LOG_ERR, "Failed to set Libgcrypt thread callbacks: %s", gcry_strerror (e)); } #endif /* GCRYPT_VERSION_NUMBER */ /* gcry_check_version() must be called before any other Libgcrypt function * (except the GCRYCTL_SET_THREAD_CBS command prior to Libgcrypt 1.6). */ v = gcry_check_version (NULL); if (v == NULL) { log_err (EMUNGE_SNAFU, LOG_ERR, "Failed to initialize Libgcrypt %s", GCRYPT_VERSION); } e = gcry_control (GCRYCTL_DISABLE_SECMEM, 0); if (e) { log_err (EMUNGE_SNAFU, LOG_ERR, "Failed to disable Libgcrypt secure memory: %s", gcry_strerror (e)); } e = gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0); if (e) { log_err (EMUNGE_SNAFU, LOG_ERR, "Failed to enable Libgcrypt quick random: %s", gcry_strerror (e)); } e = gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0); if (e) { log_err (EMUNGE_SNAFU, LOG_ERR, "Failed to initialize Libgcrypt: %s", gcry_strerror (e)); } return; } void crypto_fini (void) { return; } #endif /* HAVE_LIBGCRYPT */ /***************************************************************************** * OpenSSL Functions *****************************************************************************/ #if HAVE_OPENSSL #include #include #include #include #include #if HAVE_OPENSSL_PROVIDER_H #include static OSSL_PROVIDER *_openssl_provider_default; static OSSL_PROVIDER *_openssl_provider_legacy; #endif /* HAVE_OPENSSL_PROVIDER_H */ static void _openssl_thread_setup (void); static void _openssl_thread_cleanup (void); #if OPENSSL_VERSION_NUMBER < 0x10100000L static pthread_mutex_t * openssl_mutex_array = NULL; static int openssl_mutex_array_num_locks = 0; #if HAVE_CRYPTO_THREADID_SET_CALLBACK static void _openssl_thread_threadid_cb (CRYPTO_THREADID *id) { CRYPTO_THREADID_set_numeric (id, (unsigned long) pthread_self ()); } #elif HAVE_CRYPTO_SET_ID_CALLBACK static unsigned long _openssl_thread_id_cb (void) { return ((unsigned long) pthread_self ()); } #endif /* HAVE_CRYPTO_SET_ID_CALLBACK */ static void _openssl_thread_lock_cb (int mode, int n, const char *file, int line) { int rv; if (mode & CRYPTO_LOCK) { rv = pthread_mutex_lock (&openssl_mutex_array[n]); if (rv != 0) { errno = rv; log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to lock OpenSSL mutex #%d", n); } } else { rv = pthread_mutex_unlock (&openssl_mutex_array[n]); if (rv != 0) { errno = rv; log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to unlock OpenSSL mutex #%d", n); } } return; } #if HAVE_CRYPTO_DYNLOCK struct CRYPTO_dynlock_value { pthread_mutex_t mutex; }; static struct CRYPTO_dynlock_value * _openssl_thread_dynlock_create_cb (const char *file, int line) { struct CRYPTO_dynlock_value *lock; int rv; lock = malloc (sizeof (struct CRYPTO_dynlock_value)); if (lock == NULL) { log_err (EMUNGE_SNAFU, LOG_ERR, "Failed to allocate OpenSSL dynamic mutex"); } rv = pthread_mutex_init (&lock->mutex, NULL); if (rv != 0) { errno = rv; log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to initialize OpenSSL dynamic mutex"); } return (lock); } static void _openssl_thread_dynlock_lock_cb ( int mode, struct CRYPTO_dynlock_value *lock, const char *file, int line) { int rv; if (mode & CRYPTO_LOCK) { rv = pthread_mutex_lock (&lock->mutex); if (rv != 0) { errno = rv; log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to lock OpenSSL dynamic mutex"); } } else { rv = pthread_mutex_unlock (&lock->mutex); if (rv != 0) { errno = rv; log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to unlock OpenSSL dynamic mutex"); } } return; } static void _openssl_thread_dynlock_destroy_cb ( struct CRYPTO_dynlock_value *lock, const char *file, int line) { int rv; rv = pthread_mutex_destroy (&lock->mutex); if (rv != 0) { errno = rv; log_msg (LOG_ERR, "Failed to destroy OpenSSL dynamic mutex: %s", strerror (rv)); } free (lock); return; } #endif /* HAVE_CRYPTO_DYNLOCK */ #endif /* OPENSSL_VERSION_NUMBER < 0x10100000L */ void crypto_init (void) { #if HAVE_ERR_LOAD_CRYPTO_STRINGS /* OpenSSL < 1.1.0 */ ERR_load_crypto_strings (); #endif /* HAVE_ERR_LOAD_CRYPTO_STRINGS */ _openssl_thread_setup (); #if HAVE_OPENSSL_PROVIDER_H if (!(_openssl_provider_default = OSSL_PROVIDER_load (NULL, "default"))) { log_err (EMUNGE_SNAFU, LOG_ERR, "Failed to load OpenSSL default provider"); } /* OpenSSL 3.0: The legacy provider is needed for implementations of * Blowfish (cipher 2), CAST5 (cipher 3), and RIPEMD160 (mac 4). * Treat failure as a warning since these are not default algorithms. */ if (!(_openssl_provider_legacy = OSSL_PROVIDER_load (NULL, "legacy"))) { log_msg (LOG_WARNING, "%s: %s", "Failed to load OpenSSL legacy provider", "See OSSL_PROVIDER-legacy(7ssl) manpage for more info"); } #endif /* HAVE_OPENSSL_PROVIDER_H */ return; } void crypto_fini (void) { #if HAVE_OPENSSL_PROVIDER_H if (_openssl_provider_legacy != NULL) { if (OSSL_PROVIDER_unload (_openssl_provider_legacy) != 1) { log_msg (LOG_WARNING, "Failed to unload OpenSSL legacy provider"); } } if (_openssl_provider_default != NULL) { if (OSSL_PROVIDER_unload (_openssl_provider_default) != 1) { log_msg (LOG_WARNING, "Failed to unload OpenSSL default provider"); } } #endif /* HAVE_OPENSSL_PROVIDER_H */ _openssl_thread_cleanup (); #if HAVE_ERR_FREE_STRINGS /* OpenSSL < 1.1.0 */ ERR_free_strings (); #endif /* HAVE_ERR_FREE_STRINGS */ return; } static void _openssl_thread_setup (void) { #if OPENSSL_VERSION_NUMBER < 0x10100000L int i; int rv; if (openssl_mutex_array) { return; } #if HAVE_CRYPTO_NUM_LOCKS /* OpenSSL >= 0.9.4, < 1.1.0 */ openssl_mutex_array_num_locks = CRYPTO_num_locks (); #endif /* HAVE_CRYPTO_NUM_LOCKS */ if (openssl_mutex_array_num_locks <= 0) { log_err (EMUNGE_SNAFU, LOG_ERR, "Failed to determine requisite number of OpenSSL mutex locks"); } openssl_mutex_array = calloc (openssl_mutex_array_num_locks, sizeof (pthread_mutex_t)); if (openssl_mutex_array == NULL) { log_err (EMUNGE_SNAFU, LOG_ERR, "Failed to allocate memory for %d OpenSSL mutex%s", openssl_mutex_array_num_locks, (openssl_mutex_array_num_locks == 1) ? "" : "es"); } for (i = 0; i < openssl_mutex_array_num_locks; i++) { rv = pthread_mutex_init (&openssl_mutex_array[i], NULL); if (rv != 0) { errno = rv; log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to initialize OpenSSL mutex #%d", i); } } #if HAVE_CRYPTO_THREADID_SET_CALLBACK /* OpenSSL >= 1.0.0, < 1.1.0 */ CRYPTO_THREADID_set_callback (_openssl_thread_threadid_cb); #elif HAVE_CRYPTO_SET_ID_CALLBACK /* OpenSSL < 1.0.0 */ CRYPTO_set_id_callback (_openssl_thread_id_cb); #endif /* HAVE_CRYPTO_SET_ID_CALLBACK */ #if HAVE_CRYPTO_SET_LOCKING_CALLBACK /* OpenSSL < 1.1.0 */ CRYPTO_set_locking_callback (_openssl_thread_lock_cb); #endif /* HAVE_CRYPTO_SET_LOCKING_CALLBACK */ #if HAVE_CRYPTO_DYNLOCK /* OpenSSL >= 0.9.5b-dev, < 1.1.0 */ CRYPTO_set_dynlock_create_callback (_openssl_thread_dynlock_create_cb); CRYPTO_set_dynlock_lock_callback (_openssl_thread_dynlock_lock_cb); CRYPTO_set_dynlock_destroy_callback (_openssl_thread_dynlock_destroy_cb); #endif /* HAVE_CRYPTO_DYNLOCK */ #endif /* OPENSSL_VERSION_NUMBER < 0x10100000L */ return; } static void _openssl_thread_cleanup (void) { #if OPENSSL_VERSION_NUMBER < 0x10100000L int i; int rv; if (!openssl_mutex_array) { return; } #if HAVE_CRYPTO_THREADID_SET_CALLBACK /* OpenSSL >= 1.0.0, < 1.1.0 */ CRYPTO_THREADID_set_callback (NULL); #elif HAVE_CRYPTO_SET_ID_CALLBACK /* OpenSSL < 1.0.0 */ CRYPTO_set_id_callback (NULL); #endif /* HAVE_CRYPTO_SET_ID_CALLBACK */ #if HAVE_CRYPTO_SET_LOCKING_CALLBACK /* OpenSSL < 1.1.0 */ CRYPTO_set_locking_callback (NULL); #endif /* HAVE_CRYPTO_SET_LOCKING_CALLBACK */ #if HAVE_CRYPTO_DYNLOCK /* OpenSSL >= 0.9.5b-dev, < 1.1.0 */ CRYPTO_set_dynlock_create_callback (NULL); CRYPTO_set_dynlock_lock_callback (NULL); CRYPTO_set_dynlock_destroy_callback (NULL); #endif /* HAVE_CRYPTO_DYNLOCK */ for (i = 0; i < openssl_mutex_array_num_locks; i++) { rv = pthread_mutex_destroy (&openssl_mutex_array[i]); if (rv != 0) { errno = rv; log_msg (LOG_ERR, "Failed to destroy OpenSSL mutex #%d: %s", i, strerror (errno)); } } free (openssl_mutex_array); openssl_mutex_array = NULL; openssl_mutex_array_num_locks = 0; #endif /* OPENSSL_VERSION_NUMBER < 0x10100000L */ return; } #endif /* HAVE_OPENSSL */ /***************************************************************************** * Common Functions *****************************************************************************/ int crypto_memcmp (const void *s1, const void *s2, size_t n) { const unsigned char *a = s1; const unsigned char *b = s2; size_t i; unsigned char x; for (i = 0, x = 0; i < n; i++) { x |= a[i] ^ b[i]; } return (x != 0); } munge-munge-0.5.15/src/common/crypto.h000066400000000000000000000042621425467526100176160ustar00rootroot00000000000000/***************************************************************************** * Written by Chris Dunlap . * Copyright (C) 2007-2022 Lawrence Livermore National Security, LLC. * Copyright (C) 2002-2007 The Regents of the University of California. * UCRL-CODE-155910. * * This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE). * For details, see . * * MUNGE 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. Additionally for the MUNGE library (libmunge), you * can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation, * either version 3 of the License, or (at your option) any later version. * * MUNGE 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 * and GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * and GNU Lesser General Public License along with MUNGE. If not, see * . *****************************************************************************/ #ifndef CRYPTO_H #define CRYPTO_H #if HAVE_CONFIG_H # include #endif /* HAVE_CONFIG_H */ #if HAVE_LIBGCRYPT && HAVE_OPENSSL # error "Libgcrypt and OpenSSL are mutually-exclusive" #endif #include void crypto_init (void); /* * Initializes the cryptographic subsystem. */ void crypto_fini (void); /* * Shuts down the cryptographic subsystem. */ int crypto_memcmp (const void *s1, const void *s2, size_t n); /* * Compares the first [n] bytes of the memory regions [s1] and [s2] in an * amount of time dependent upon the length [n], but independent of the * contents of either [s1] or [s2]. * Returns 0 if the memory regions are equal, or non-zero otherwise. */ #endif /* !CRYPTO_H */ munge-munge-0.5.15/src/common/entropy.c000066400000000000000000000147561425467526100200020ustar00rootroot00000000000000/***************************************************************************** * Written by Chris Dunlap . * Copyright (C) 2007-2022 Lawrence Livermore National Security, LLC. * Copyright (C) 2002-2007 The Regents of the University of California. * UCRL-CODE-155910. * * This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE). * For details, see . * * MUNGE 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. Additionally for the MUNGE library (libmunge), you * can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation, * either version 3 of the License, or (at your option) any later version. * * MUNGE 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 * and GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * and GNU Lesser General Public License along with MUNGE. If not, see * . *****************************************************************************/ #if HAVE_CONFIG_H # include "config.h" #endif /* HAVE_CONFIG_H */ #include #include #include #include #if HAVE_SYS_RANDOM_H #include #endif /* HAVE_SYS_RANDOM_H */ #include #include #include #include #include "common.h" #include "entropy.h" #include "log.h" #include "rotate.h" /***************************************************************************** * Constants *****************************************************************************/ /* Pathname of the kernel urandom device. */ #define ENTROPY_URANDOM_PATH "/dev/urandom" /***************************************************************************** * Public Functions *****************************************************************************/ /* Read up to [buflen] bytes of entropy from the kernel's CSPRNG, * storing the data in [buf]. * If [srcp] is not NULL, it will be set to a static string identifying * the entropy source on success or NULL on error. * Return the number of bytes read, or -1 on error (with errno set). */ int entropy_read (void *buf, size_t buflen, const char **srcp) { size_t len; int rv; int n = -1; const char *src = NULL; if (buf == NULL) { errno = EINVAL; return -1; } #if HAVE_GETRANDOM /* * If the urandom source has been initialized, reads of up to 256 bytes * will always return as many bytes as requested and not be interrupted * by signals. No such guarantees apply for larger buffer sizes. */ len = MIN(256, buflen); do { rv = getrandom (buf, len, 0); } while ((rv < 0) && (errno == EINTR)); if (rv < 0) { log_msg (LOG_WARNING, "Failed to fill buffer via getrandom(): %s", strerror (errno)); } else if (rv > 0) { n = rv; src = "getrandom()"; } #elif HAVE_GETENTROPY /* * The maximum buffer size permitted is 256 bytes. */ len = MIN(256, buflen); rv = getentropy (buf, len); if (rv < 0) { log_msg (LOG_WARNING, "Failed to fill buffer via getentropy(): %s", strerror (errno)); } else if (rv == 0) { n = len; src = "getentropy()"; } #endif /* HAVE_GETENTROPY */ if (n < 0) { int fd; struct stat st; do { fd = open (ENTROPY_URANDOM_PATH, O_RDONLY | O_NONBLOCK); } while ((fd < 0) && (errno == EINTR)); if (fd < 0) { log_msg (LOG_WARNING, "Failed to open \"%s\": %s", ENTROPY_URANDOM_PATH, strerror (errno)); } else { if (fstat (fd, &st) < 0) { log_msg (LOG_WARNING, "Failed to stat \"%s\": %s", ENTROPY_URANDOM_PATH, strerror (errno)); } else if (!S_ISCHR (st.st_mode)) { errno = ENODEV; log_msg (LOG_WARNING, "Failed to validate \"%s\": " "not a character device (type=%07o)", ENTROPY_URANDOM_PATH, (st.st_mode & S_IFMT)); } else { len = buflen; rv = fd_read_n (fd, buf, len); if (rv < 0) { log_msg (LOG_WARNING, "Failed to read from \"%s\": %s", ENTROPY_URANDOM_PATH, strerror (errno)); } else if (rv > 0) { n = rv; src = "\"" ENTROPY_URANDOM_PATH "\""; } } if (close (fd) < 0) { log_msg (LOG_WARNING, "Failed to close \"%s\": %s", ENTROPY_URANDOM_PATH, strerror (errno)); } } } if (srcp != NULL) { *srcp = src; } return n; } /* Read entropy into the unsigned integer referenced by [up]. * This entropy will be from sources independent of the kernel's CSPRNG. * It may be of lower quality and not uniformly distributed. * The bits in the uint arg are rotated between entropic additions to better * distribute the entropy. Spin the wheel of entropy and win a prize! * Return 0 on success, or -1 on error (with errno set). */ int entropy_read_uint (unsigned *up) { pid_t pid; clock_t cpu_time; struct timeval tv; if (up == NULL) { errno = EINVAL; return -1; } *up = 0; pid = getpid (); *up ^= (unsigned) pid; rotate_left (up, *up); pid = getppid (); *up ^= (unsigned) pid; rotate_right (up, *up); cpu_time = clock (); if (cpu_time != (clock_t) -1) { *up ^= (unsigned) cpu_time; rotate_left (up, *up); } /* FIXME: Replace gettimeofday() (usec resolution) with * clock_gettime() (nsec resolution) for more entropy. */ if (gettimeofday (&tv, NULL) == 0) { *up ^= (unsigned) tv.tv_sec; rotate_right (up, *up); *up ^= (unsigned) tv.tv_usec; rotate_left (up, *up); } return 0; } munge-munge-0.5.15/src/common/entropy.h000066400000000000000000000042011425467526100177670ustar00rootroot00000000000000/***************************************************************************** * Written by Chris Dunlap . * Copyright (C) 2007-2022 Lawrence Livermore National Security, LLC. * Copyright (C) 2002-2007 The Regents of the University of California. * UCRL-CODE-155910. * * This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE). * For details, see . * * MUNGE 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. Additionally for the MUNGE library (libmunge), you * can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation, * either version 3 of the License, or (at your option) any later version. * * MUNGE 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 * and GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * and GNU Lesser General Public License along with MUNGE. If not, see * . *****************************************************************************/ #ifndef MUNGE_ENTROPY_H #define MUNGE_ENTROPY_H #include /***************************************************************************** * Constants *****************************************************************************/ /* Number of bytes guaranteed for reading in a single call to entropy_read(). */ #define ENTROPY_NUM_BYTES_GUARANTEED 256 /***************************************************************************** * Prototypes *****************************************************************************/ int entropy_read (void *buf, size_t buflen, const char **srcp); int entropy_read_uint (unsigned *up); #endif /* !MUNGE_ENTROPY_H */ munge-munge-0.5.15/src/common/hkdf.c000066400000000000000000000411501425467526100172020ustar00rootroot00000000000000/***************************************************************************** * Written by Chris Dunlap . * Copyright (C) 2007-2022 Lawrence Livermore National Security, LLC. * Copyright (C) 2002-2007 The Regents of the University of California. * UCRL-CODE-155910. * * This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE). * For details, see . * * MUNGE 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. Additionally for the MUNGE library (libmunge), you * can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation, * either version 3 of the License, or (at your option) any later version. * * MUNGE 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 * and GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * and GNU Lesser General Public License along with MUNGE. If not, see * . *****************************************************************************/ #if HAVE_CONFIG_H # include "config.h" #endif /* HAVE_CONFIG_H */ #include #include #include #include #include #include #include #include #include "common.h" #include "hkdf.h" #include "log.h" #include "mac.h" #include "str.h" /***************************************************************************** * Notes ***************************************************************************** * * Implementation based on RFC 5869: HMAC-based Extract-and-Expand * Key Derivation Function (HKDF). * * Refer to "Cryptographic Extraction and Key Derivation: The HKDF Scheme" * (2010) by Hugo Krawczyk for further details. */ /***************************************************************************** * Constants *****************************************************************************/ /* As per RFC 5869: For HKDF-Expand, the output keying material (OKM) is * calculated by generating sufficient octets of T(1)...T(N), where * N = ceil (L / HashLen). L (length of OKM in octets) <= 255 * HashLen. * HashLen denotes the length of the hash function output in octets. * Thus, the maximum number of rounds is 255. * Furthermore, the number of the round concatenated to the end of each T(n) * is a single octet which architecturally limits it to 255. */ #define HKDF_MAX_ROUNDS 255 /***************************************************************************** * Data Types *****************************************************************************/ struct hkdf_ctx { unsigned salt_is_allocated:1; munge_mac_t md; /* message digest / hash function */ size_t mdlen; /* length of MD output (in bytes) */ const void *key; /* input keying material */ size_t keylen; /* length of key (in bytes) */ const void *salt; /* optional: non-secret random value */ size_t saltlen; /* length of salt (in bytes) */ const void *info; /* optional: context specific info */ size_t infolen; /* length of info (in bytes) */ }; /***************************************************************************** * Private Prototypes *****************************************************************************/ static int _hkdf_extract (hkdf_ctx_t *ctxp, void *prk, size_t *prklenp); static int _hkdf_expand (hkdf_ctx_t *ctxp, const void *prk, size_t prklen, void *dst, size_t *dstlenp); /***************************************************************************** * Public Functions *****************************************************************************/ /* Create a new HKDF context. * Return a ptr to the context on success, or NULL on error. */ hkdf_ctx_t * hkdf_ctx_create (void) { hkdf_ctx_t *ctxp; ctxp = calloc (1, sizeof (*ctxp)); return ctxp; } /* Destroy the HKDF context [ctxp]. */ void hkdf_ctx_destroy (hkdf_ctx_t *ctxp) { if (ctxp == NULL) { return; } if ((ctxp->key != NULL) && (ctxp->keylen > 0)) { ctxp->key = NULL; ctxp->keylen = 0; } if ((ctxp->salt != NULL) && (ctxp->saltlen > 0)) { if (ctxp->salt_is_allocated) { free ((void *) ctxp->salt); ctxp->salt_is_allocated = 0; } ctxp->salt = NULL; ctxp->saltlen = 0; } if ((ctxp->info != NULL) && (ctxp->infolen > 0)) { ctxp->info = NULL; ctxp->infolen = 0; } free (ctxp); } /* Specify the message digest / hash function [md] for use with the * HKDF context [ctxp]. * Return 0 on success, or -1 on error (with errno set). */ int hkdf_ctx_set_md (hkdf_ctx_t *ctxp, munge_mac_t md) { if (ctxp == NULL) { errno = EINVAL; return -1; } if (mac_map_enum (md, NULL) < 0) { errno = EINVAL; return -1; } ctxp->md = md; return 0; } /* Specify the input keying material [key] of length [keylen] for use with * the HKDF context [ctxp]. * Return 0 on success, or -1 on error (with errno set). */ int hkdf_ctx_set_key (hkdf_ctx_t *ctxp, const void *key, size_t keylen) { if ((ctxp == NULL) || (key == NULL)) { errno = EINVAL; return -1; } ctxp->key = key; ctxp->keylen = keylen; return 0; } /* Specify an optional [salt] of length [saltlen] for use with the * HKDF context [ctxp]. * The salt is a non-secret random value; if not provided, it is set to a * string of zeros equal in length to the size of the hash function output. * The use of salt adds significantly to the strength of HKDF, ensuring * independence between different uses of the hash function, supporting * source-independent extraction, and strengthening the analytical results * that back the HKDF design. * Ideally, the salt value is a random (or pseudorandom) string equal in * length to the size of the hash function output. Yet, even a salt value * of less quality (i.e., shorter in size, or with limited entropy) may * still make a significant contribution to the security of the output * keying material. * The salt value should be independent of the input keying material. * Return 0 on success, or -1 on error (with errno set). */ int hkdf_ctx_set_salt (hkdf_ctx_t *ctxp, const void *salt, size_t saltlen) { if ((ctxp == NULL) || (salt == NULL)) { errno = EINVAL; return -1; } if (ctxp->salt_is_allocated) { free ((void *) ctxp->salt); ctxp->salt_is_allocated = 0; } ctxp->salt = salt; ctxp->saltlen = saltlen; return 0; } /* Specify optional context and application specific information [info] * of length [infolen] for use with the HKDF context [ctxp]. * This information binds the derived key material to application- and * context-specific information. * This information should be independent of the input keying material. * Return 0 on success, or -1 on error (with errno set). */ int hkdf_ctx_set_info (hkdf_ctx_t *ctxp, const void *info, size_t infolen) { if ((ctxp == NULL) || (info == NULL)) { errno = EINVAL; return -1; } ctxp->info = info; ctxp->infolen = infolen; return 0; } /* Compute the HMAC-based Key Derivation Function (HKDF) based on the * HKDF context [ctxp]. * The resulting output keying material will be written into the buffer [dst]. * [dstlenp] is a value-result parameter; it must be initialized to the size * of the [dst] buffer (in bytes). * Return 0 on success (with [*dstlenp] set to the number of bytes written * into the [dst] buffer), or -1 on error (with errno set). */ int hkdf (hkdf_ctx_t *ctxp, void *dst, size_t *dstlenp) { unsigned char *prk = NULL; /* pseudorandom key */ size_t prklen; /* length of PRK (in bytes) */ size_t prklen_used; /* length of PRK used (in bytes) */ int rv; if ((ctxp == NULL) || (dst == NULL) || (dstlenp == NULL)) { errno = EINVAL; return -1; } /* Validate mac. * ctx is initialized with 0 which equates to MUNGE_MAC_NONE which is * invalid by definition. The mac will be validated by mac_size() when * computing the length of the hash function output. */ ctxp->mdlen = (size_t) mac_size (ctxp->md); if (ctxp->mdlen == (size_t) -1) { errno = EINVAL; return -1; } /* Validate key. * A zero-length key seems to be allowed, but the key ptr must not be NULL * due to assertions in mac.c. */ if (ctxp->key == NULL) { errno = EINVAL; return -1; } /* Allocate salt, if not already set. */ if (ctxp->salt == NULL) { ctxp->saltlen = ctxp->mdlen; ctxp->salt = calloc (1, ctxp->saltlen); if (ctxp->salt == NULL) { return -1; } ctxp->salt_is_allocated = 1; } /* Allocate pseudorandom key. * The length of the PRK is the length of the hash function output. */ prklen = ctxp->mdlen; prk = calloc (1, prklen); if (prk == NULL) { return -1; } prklen_used = prklen; /* initialize value-result parm */ /* * Extract pseudorandom key. */ rv = _hkdf_extract (ctxp, prk, &prklen_used); if (rv == -1) { goto cleanup; } if (prklen != prklen_used) { log_err (EMUNGE_SNAFU, LOG_ERR, "Failed HKDF Extraction: expected %u bytes, received %u bytes", prklen, prklen_used); } /* Expand pseudorandom key to desired length. */ rv = _hkdf_expand (ctxp, prk, prklen, dst, dstlenp); cleanup: if (prk != NULL) { memburn (prk, 0, prklen); free (prk); } return rv; } /***************************************************************************** * Private Functions *****************************************************************************/ /* HKDF First Stage. * Extract (or concentrate) the possibly dispersed entropy of the input * keying material into a short, but cryptographically strong, * pseudorandom key (prk). * [prklenp] is a value-result parameter; it must be initialized to the size * of the [prk] buffer (in bytes). * Return 0 on success (with [*prklenp] set to the number of bytes written * into the [prk] buffer), or -1 on error (with errno set). */ static int _hkdf_extract (hkdf_ctx_t *ctxp, void *prk, size_t *prklenp) { mac_ctx mac_ctx; int mac_ctx_is_initialized = 0; int prklen; int rv = 0; assert (ctxp != NULL); assert (ctxp->salt != NULL); assert (ctxp->key != NULL); assert (prk != NULL); assert (prklenp != NULL); assert (*prklenp > 0); /* Convert prklen size_t to int for the call to mac_final() since the parm * is being passed as a ptr, and size of size_t and int may differ. * *prklenp must be representable as an int because it was assigned * (via ctxp->mdlen) by mac_size() which returns an int. */ assert (*prklenp <= INT_MAX); prklen = (int) *prklenp; /* Compute the pseudorandom key. * prk = HMAC (salt, ikm) */ rv = mac_init (&mac_ctx, ctxp->md, ctxp->salt, ctxp->saltlen); if (rv == -1) { log_msg (LOG_ERR, "Failed to initialize HKDF MAC ctx for extraction"); goto err; } mac_ctx_is_initialized = 1; rv = mac_update (&mac_ctx, ctxp->key, ctxp->keylen); if (rv == -1) { log_msg (LOG_ERR, "Failed to update HKDF MAC ctx for extraction"); goto err; } rv = mac_final (&mac_ctx, prk, &prklen); if (rv == -1) { log_msg (LOG_ERR, "Failed to finalize HKDF MAC ctx for extraction"); goto err; } err: if (mac_ctx_is_initialized) { if (mac_cleanup (&mac_ctx) == -1) { log_msg (LOG_ERR, "Failed to cleanup HKDF MAC ctx for extraction"); return -1; } } /* Update [prklenp] on success. */ if (rv >= 0) { assert (prklen >= 0); *prklenp = (size_t) prklen; } return rv; } /* HKDF Second Stage. * Expand the pseudorandom key [prk] of length [prklen] to the desired length, * writing the output keying material into the buffer [dst]. * [dstlenp] is a value-result parameter; it must be initialized to the size * of the [dst] buffer (in bytes). * Return 0 on success (with [*dstlenp] set to the number of bytes written * into the [dst] buffer), or -1 on error (with errno set). */ static int _hkdf_expand (hkdf_ctx_t *ctxp, const void *prk, size_t prklen, void *dst, size_t *dstlenp) { unsigned char *dstp; size_t dstlen_left; unsigned char *okm = NULL; int okmlen; unsigned char round; mac_ctx mac_ctx; int mac_ctx_is_initialized = 0; int n; int rv = 0, rv2; assert (ctxp != NULL); assert (prk != NULL); assert (prklen > 0); assert (dst != NULL); assert (dstlenp != NULL); dstp = dst; dstlen_left = *dstlenp; /* Allocate buffer for output keying material. * The buffer size is equal to the size of the hash function output. * Note that okmlen must be an int (and not size_t) for the call to * mac_final() since the parm is being passed as a ptr, and size of * size_t and int may differ. * ctxp->mdlen must be representable as an int because it was assigned * by mac_size() which returns an int. */ assert (ctxp->mdlen <= INT_MAX); okmlen = (int) ctxp->mdlen; okm = calloc (1, okmlen); if (okm == NULL) { rv = -1; goto err; } /* Compute output keying material for each expansion round. * okm(i) = HMAC (prk, okm(i-i) | [info] | i) */ round = 0; while (dstlen_left > 0) { round++; rv = mac_init (&mac_ctx, ctxp->md, prk, prklen); if (rv == -1) { log_msg (LOG_ERR, "Failed to initialize HKDF MAC ctx " "for expansion round #%u", round); goto err; } mac_ctx_is_initialized = 1; if (round > 1) { rv = mac_update (&mac_ctx, okm, okmlen); if (rv == -1) { log_msg (LOG_ERR, "Failed to update HKDF MAC ctx with prev okm " "for expansion round #%u", round); goto err; } } if (ctxp->infolen > 0) { rv = mac_update (&mac_ctx, ctxp->info, ctxp->infolen); if (rv == -1) { log_msg (LOG_ERR, "Failed to update HKDF MAC ctx with info " "for expansion round #%u", round); goto err; } } assert (sizeof (round) == 1); rv = mac_update (&mac_ctx, &round, sizeof (round)); if (rv == -1) { log_msg (LOG_ERR, "Failed to update HKDF MAC ctx with count " "for expansion round #%u", round); goto err; } rv = mac_final (&mac_ctx, okm, &okmlen); if (rv == -1) { log_msg (LOG_ERR, "Failed to finalize HKDF MAC ctx " "for expansion round #%u", round); goto err; } rv = mac_cleanup (&mac_ctx); mac_ctx_is_initialized = 0; if (rv == -1) { log_msg (LOG_ERR, "Failed to cleanup HKDF MAC ctx for expansion"); goto err; } assert (okmlen == ctxp->mdlen); n = MIN(okmlen, dstlen_left); memcpy (dstp, okm, n); dstp += n; dstlen_left -= n; if (round == HKDF_MAX_ROUNDS) { break; } } *dstlenp = dstp - (unsigned char *) dst; err: if (mac_ctx_is_initialized) { rv2 = mac_cleanup (&mac_ctx); if (rv2 == -1) { log_msg (LOG_ERR, "Failed to cleanup HKDF MAC ctx for expansion"); rv = -1; } } if (okm != NULL) { memburn (okm, 0, ctxp->mdlen); free (okm); } return rv; } munge-munge-0.5.15/src/common/hkdf.h000066400000000000000000000045611425467526100172140ustar00rootroot00000000000000/***************************************************************************** * Written by Chris Dunlap . * Copyright (C) 2007-2022 Lawrence Livermore National Security, LLC. * Copyright (C) 2002-2007 The Regents of the University of California. * UCRL-CODE-155910. * * This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE). * For details, see . * * MUNGE 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. Additionally for the MUNGE library (libmunge), you * can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation, * either version 3 of the License, or (at your option) any later version. * * MUNGE 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 * and GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * and GNU Lesser General Public License along with MUNGE. If not, see * . *****************************************************************************/ #ifndef MUNGE_HKDF_H #define MUNGE_HKDF_H #include #include /***************************************************************************** * Data Types *****************************************************************************/ typedef struct hkdf_ctx hkdf_ctx_t; /***************************************************************************** * Prototypes *****************************************************************************/ hkdf_ctx_t * hkdf_ctx_create (void); void hkdf_ctx_destroy (hkdf_ctx_t *ctxp); int hkdf_ctx_set_md (hkdf_ctx_t *ctxp, munge_mac_t md); int hkdf_ctx_set_key (hkdf_ctx_t *ctxp, const void *key, size_t keylen); int hkdf_ctx_set_salt (hkdf_ctx_t *ctxp, const void *salt, size_t saltlen); int hkdf_ctx_set_info (hkdf_ctx_t *ctxp, const void *info, size_t infolen); int hkdf (hkdf_ctx_t *ctxp, void *dst, size_t *dstlenp); #endif /* !MUNGE_HKDF_H */ munge-munge-0.5.15/src/common/hkdf_api_test.c000066400000000000000000000166761425467526100211110ustar00rootroot00000000000000/***************************************************************************** * Written by Chris Dunlap . * Copyright (C) 2007-2022 Lawrence Livermore National Security, LLC. * Copyright (C) 2002-2007 The Regents of the University of California. * UCRL-CODE-155910. * * This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE). * For details, see . * * MUNGE 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. Additionally for the MUNGE library (libmunge), you * can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation, * either version 3 of the License, or (at your option) any later version. * * MUNGE 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 * and GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * and GNU Lesser General Public License along with MUNGE. If not, see * . *****************************************************************************/ #if HAVE_CONFIG_H # include "config.h" #endif /* HAVE_CONFIG_H */ #include #include #include #include #include "crypto.h" #include "hkdf.h" #include "md.h" #include "tap.h" int main (int argc, char *argv[]) { hkdf_ctx_t *hkdfp; size_t buflen; unsigned char buf[8200]; unsigned char vanillabuf[8200]; unsigned char partialbuf[13]; crypto_init (); md_init_subsystem (); /* initialize bufs with different data in preparation for memcmp tests */ memset (buf, 1, sizeof (buf)); memset (vanillabuf, 2, sizeof (vanillabuf)); memset (partialbuf, 3, sizeof (partialbuf)); plan (NO_PLAN); ok ((hkdfp = hkdf_ctx_create ()) != NULL, "hkdf_ctx_create"); if (hkdfp == NULL) { BAIL_OUT ("Testing cannot proceed without hkdf ctx"); } /* validate hkdf() with null parms and unset md */ buflen = sizeof (buf); ok (hkdf (NULL, buf, &buflen) < 0 && (errno == EINVAL), "hkdf failure for null ctx ptr"); buflen = sizeof (buf); ok (hkdf (hkdfp, NULL, &buflen) < 0 && (errno == EINVAL), "hkdf failure for null dst ptr"); buflen = sizeof (buf); ok (hkdf (hkdfp, buf, NULL) < 0 && (errno == EINVAL), "hkdf failure for null dstlenp value-result"); /* validate hkdf_ctx_set_md() */ buflen = sizeof (buf); ok (hkdf (hkdfp, buf, &buflen) < 0, "hkdf failure for unset md"); ok (hkdf_ctx_set_md (NULL, MUNGE_MAC_SHA256) < 0 && (errno == EINVAL), "hkdf_ctx_set_md failure for null ctx ptr"); ok (hkdf_ctx_set_md (hkdfp, 1313) < 0 && (errno == EINVAL), "hkdf_ctx_set_md failure for invalid md"); ok (hkdf_ctx_set_md (hkdfp, MUNGE_MAC_SHA256) == 0, "hkdf_ctx_set_md success"); /* validate hkdf_ctx_set_key() */ buflen = sizeof (buf); ok (hkdf (hkdfp, buf, &buflen) < 0, "hkdf failure for unset key"); ok (hkdf_ctx_set_key (NULL, "xyzzy", 5) < 0 && (errno == EINVAL), "hkdf_ctx_set_key failure for null ctx ptr"); ok (hkdf_ctx_set_key (hkdfp, NULL, 0) < 0 && (errno == EINVAL), "hkdf_ctx_set_key failure for null key ptr"); ok (hkdf_ctx_set_key (hkdfp, "xyzzy", 5) == 0, "hkdf_ctx_set_key success for nonzero-length key"); buflen = sizeof (buf); ok (hkdf (hkdfp, buf, &buflen) == 0, "hkdf success for nonzero-length key"); /* vanillabuf with SHA256, zero-length key, no salt, no info */ ok (hkdf_ctx_set_key (hkdfp, "", 0) == 0, "hkdf_ctx_set_key success for zero-length key"); ok (sizeof (vanillabuf) == sizeof (buf), "hkdf vanillabuf size matches buf size"); buflen = sizeof (vanillabuf); ok (hkdf (hkdfp, vanillabuf, &buflen) == 0, "hkdf success for zero-length key"); ok (memcmp (buf, vanillabuf, buflen) != 0, "hkdf differing keys yield differing bufs"); /* max dstlen = mdlen * HKDF_MAX_ROUNDS = 32 * 255 = 8160 bytes */ ok (sizeof (buf) > 32 * 255, "hkdf buf size suitable for max dst check"); buflen = sizeof (buf); ok (hkdf (hkdfp, buf, &buflen) == 0, "hkdf success for max dst"); ok (buflen == 32 * 255, "hkdf buflen correct for max dst"); ok (memcmp (vanillabuf, buf, buflen) == 0, "hkdf matching keys yield matching bufs"); /* partialbuf must be smaller than the SHA256 block size of 32 bytes */ ok (sizeof (partialbuf) < 32, "hkdf buf size suitable for partial md block check"); buflen = sizeof (partialbuf); ok (hkdf (hkdfp, partialbuf, &buflen) == 0, "hkdf success for partial md block"); ok (buflen == sizeof (partialbuf), "hkdf buflen correct for partial md block"); ok (memcmp (vanillabuf, partialbuf, buflen) == 0, "hkdf buf from partial md block matches partial buf"); /* validate hkdf_ctx_set_salt() */ ok (hkdf_ctx_set_salt (NULL, "salt", 4) < 0 && (errno == EINVAL), "hkdf_ctx_set_salt failure for null ctx ptr"); ok (hkdf_ctx_set_salt (hkdfp, NULL, 0) < 0 && (errno == EINVAL), "hkdf_ctx_set_salt failure for null salt ptr"); ok (hkdf_ctx_set_salt (hkdfp, "salt", 4) == 0, "hkdf_ctx_set_salt success for nonzero-length salt"); buflen = sizeof (buf); ok (hkdf (hkdfp, buf, &buflen) == 0, "hkdf success for nonzero-length salt"); ok (memcmp (vanillabuf, buf, buflen) != 0, "hkdf differing salts yield differing bufs"); ok (hkdf_ctx_set_salt (hkdfp, "", 0) == 0, "hkdf_ctx_set_salt success for zero-length salt"); buflen = sizeof (buf); ok (hkdf (hkdfp, buf, &buflen) == 0, "hkdf success for zero-length salt"); ok (memcmp (vanillabuf, buf, buflen) == 0, "hkdf buf from zero-length salt matches vanilla buf"); /* validate hkdf_ctx_set_info() */ ok (hkdf_ctx_set_info (NULL, "info", 4) < 0 && (errno == EINVAL), "hkdf_ctx_set_info failure for null ctx ptr"); ok (hkdf_ctx_set_info (hkdfp, NULL, 0) < 0 && (errno == EINVAL), "hkdf_ctx_set_info failure for null info ptr"); ok (hkdf_ctx_set_info (hkdfp, "info", 4) == 0, "hkdf_ctx_set_info success for nonzero-length info"); buflen = sizeof (buf); ok (hkdf (hkdfp, buf, &buflen) == 0, "hkdf success for nonzero-length info"); ok (memcmp (vanillabuf, buf, buflen) != 0, "hkdf differing infos yield differing bufs"); ok (hkdf_ctx_set_info (hkdfp, "", 0) == 0, "hkdf_ctx_set_info success for zero-length info"); buflen = sizeof (buf); ok (hkdf (hkdfp, buf, &buflen) == 0, "hkdf success for zero-length info"); ok (memcmp (vanillabuf, buf, buflen) == 0, "hkdf buf from zero-length info matches vanilla buf"); /* cleanup */ hkdf_ctx_destroy (hkdfp); done_testing (); crypto_fini (); exit (EXIT_SUCCESS); } munge-munge-0.5.15/src/common/hkdf_rfc_test.c000066400000000000000000000341351425467526100211000ustar00rootroot00000000000000/***************************************************************************** * Written by Chris Dunlap . * Copyright (C) 2007-2022 Lawrence Livermore National Security, LLC. * Copyright (C) 2002-2007 The Regents of the University of California. * UCRL-CODE-155910. * * This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE). * For details, see . * * MUNGE 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. Additionally for the MUNGE library (libmunge), you * can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation, * either version 3 of the License, or (at your option) any later version. * * MUNGE 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 * and GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * and GNU Lesser General Public License along with MUNGE. If not, see * . *****************************************************************************/ #if HAVE_CONFIG_H # include "config.h" #endif /* HAVE_CONFIG_H */ #include #include #include #include "crypto.h" #include "hkdf.h" #include "md.h" #include "tap.h" /***************************************************************************** * Test cases from RFC 5869: HMAC-based Extract-and-Expand Key Derivation * Function (HKDF), Appendix A. * * Note that PRK is not being checked since it is internal to hkdf(). * But if OKM matches, PRK presumably does as well. *****************************************************************************/ int hkdf_test (munge_mac_t md, const unsigned char *ikm, size_t ikmlen, const unsigned char *salt, size_t saltlen, const unsigned char *info, size_t infolen, const unsigned char *okm, size_t okmlen) { unsigned char buf[128]; size_t buflen; hkdf_ctx_t *hkdfp; int rv; hkdfp = hkdf_ctx_create (); if (hkdfp == NULL) { diag ("Failed to allocate memory for HKDF context"); return -1; } rv = hkdf_ctx_set_md (hkdfp, md); if (rv == -1) { diag ("Failed to set HKDF message digest to md=%d", md); return -1; } if (ikm != NULL) { rv = hkdf_ctx_set_key (hkdfp, ikm, ikmlen); if (rv == -1) { diag ("Failed to set HKDF input keying material"); return -1; } } if (salt != NULL) { rv = hkdf_ctx_set_salt (hkdfp, salt, saltlen); if (rv == -1) { diag ("Failed to set HKDF salt"); return -1; } } if (info != NULL) { rv = hkdf_ctx_set_info (hkdfp, info, infolen); if (rv == -1) { diag ("Failed to set HKDF info"); return -1; } } if (okmlen > sizeof (buf)) { diag ("Exceeded %zu-byte buffer with %zu bytes of " "HKDF output keying material", sizeof (buf), okmlen); return -1; } buflen = okmlen; rv = hkdf (hkdfp, buf, &buflen); if (rv == -1) { diag ("Failed to compute HKDF key derivation"); return -1; } if (buflen != okmlen) { diag ("Expected %zu bytes of output keying material, " "but got %zu bytes", okmlen, buflen); return -1; } if (memcmp (buf, okm, okmlen) != 0) { diag ("Failed to match expected HKDF output keying material"); return -1; } hkdf_ctx_destroy (hkdfp); return 0; } /* Test Case 1: SHA-256 basic test */ int hkdf_test_1 (void) { const unsigned char ikm[22] = { 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b }; const unsigned char salt[13] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c }; const unsigned char info[10] = { 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9 }; const unsigned char okm[42] = { 0x3c, 0xb2, 0x5f, 0x25, 0xfa, 0xac, 0xd5, 0x7a, 0x90, 0x43, 0x4f, 0x64, 0xd0, 0x36, 0x2f, 0x2a, 0x2d, 0x2d, 0x0a, 0x90, 0xcf, 0x1a, 0x5a, 0x4c, 0x5d, 0xb0, 0x2d, 0x56, 0xec, 0xc4, 0xc5, 0xbf, 0x34, 0x00, 0x72, 0x08, 0xd5, 0xb8, 0x87, 0x18, 0x58, 0x65 }; const munge_mac_t md = MUNGE_MAC_SHA256; return hkdf_test (md, ikm, sizeof (ikm), salt, sizeof (salt), info, sizeof (info), okm, sizeof (okm)); } /* Test Case 2: SHA-256 with longer inputs/outputs */ int hkdf_test_2 (void) { const unsigned char ikm[80] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f }; const unsigned char salt[80] = { 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf }; const unsigned char info[80] = { 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff }; const unsigned char okm[82] = { 0xb1, 0x1e, 0x39, 0x8d, 0xc8, 0x03, 0x27, 0xa1, 0xc8, 0xe7, 0xf7, 0x8c, 0x59, 0x6a, 0x49, 0x34, 0x4f, 0x01, 0x2e, 0xda, 0x2d, 0x4e, 0xfa, 0xd8, 0xa0, 0x50, 0xcc, 0x4c, 0x19, 0xaf, 0xa9, 0x7c, 0x59, 0x04, 0x5a, 0x99, 0xca, 0xc7, 0x82, 0x72, 0x71, 0xcb, 0x41, 0xc6, 0x5e, 0x59, 0x0e, 0x09, 0xda, 0x32, 0x75, 0x60, 0x0c, 0x2f, 0x09, 0xb8, 0x36, 0x77, 0x93, 0xa9, 0xac, 0xa3, 0xdb, 0x71, 0xcc, 0x30, 0xc5, 0x81, 0x79, 0xec, 0x3e, 0x87, 0xc1, 0x4c, 0x01, 0xd5, 0xc1, 0xf3, 0x43, 0x4f, 0x1d, 0x87 }; const munge_mac_t md = MUNGE_MAC_SHA256; return hkdf_test (md, ikm, sizeof (ikm), salt, sizeof (salt), info, sizeof (info), okm, sizeof (okm)); } /* Test Case 3: SHA-256 with zero-length salt/info */ int hkdf_test_3 (void) { const unsigned char ikm[22] = { 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b }; const unsigned char salt[1] = { 0x00 }; const unsigned char info[1] = { 0x00 }; const unsigned char okm[42] = { 0x8d, 0xa4, 0xe7, 0x75, 0xa5, 0x63, 0xc1, 0x8f, 0x71, 0x5f, 0x80, 0x2a, 0x06, 0x3c, 0x5a, 0x31, 0xb8, 0xa1, 0x1f, 0x5c, 0x5e, 0xe1, 0x87, 0x9e, 0xc3, 0x45, 0x4e, 0x5f, 0x3c, 0x73, 0x8d, 0x2d, 0x9d, 0x20, 0x13, 0x95, 0xfa, 0xa4, 0xb6, 0x1a, 0x96, 0xc8 }; const munge_mac_t md = MUNGE_MAC_SHA256; return hkdf_test (md, ikm, sizeof (ikm), salt, 0, info, 0, okm, sizeof (okm)); } /* Test Case 4: SHA-1 basic test */ int hkdf_test_4 (void) { const unsigned char ikm[11] = { 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b }; const unsigned char salt[13] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c }; const unsigned char info[10] = { 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9 }; const unsigned char okm[42] = { 0x08, 0x5a, 0x01, 0xea, 0x1b, 0x10, 0xf3, 0x69, 0x33, 0x06, 0x8b, 0x56, 0xef, 0xa5, 0xad, 0x81, 0xa4, 0xf1, 0x4b, 0x82, 0x2f, 0x5b, 0x09, 0x15, 0x68, 0xa9, 0xcd, 0xd4, 0xf1, 0x55, 0xfd, 0xa2, 0xc2, 0x2e, 0x42, 0x24, 0x78, 0xd3, 0x05, 0xf3, 0xf8, 0x96 }; const munge_mac_t md = MUNGE_MAC_SHA1; return hkdf_test (md, ikm, sizeof (ikm), salt, sizeof (salt), info, sizeof (info), okm, sizeof (okm)); } /* Test Case 5: SHA-1 with longer inputs/outputs */ int hkdf_test_5 (void) { const unsigned char ikm[80] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f }; const unsigned char salt[80] = { 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf }; const unsigned char info[80] = { 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff }; const unsigned char okm[82] = { 0x0b, 0xd7, 0x70, 0xa7, 0x4d, 0x11, 0x60, 0xf7, 0xc9, 0xf1, 0x2c, 0xd5, 0x91, 0x2a, 0x06, 0xeb, 0xff, 0x6a, 0xdc, 0xae, 0x89, 0x9d, 0x92, 0x19, 0x1f, 0xe4, 0x30, 0x56, 0x73, 0xba, 0x2f, 0xfe, 0x8f, 0xa3, 0xf1, 0xa4, 0xe5, 0xad, 0x79, 0xf3, 0xf3, 0x34, 0xb3, 0xb2, 0x02, 0xb2, 0x17, 0x3c, 0x48, 0x6e, 0xa3, 0x7c, 0xe3, 0xd3, 0x97, 0xed, 0x03, 0x4c, 0x7f, 0x9d, 0xfe, 0xb1, 0x5c, 0x5e, 0x92, 0x73, 0x36, 0xd0, 0x44, 0x1f, 0x4c, 0x43, 0x00, 0xe2, 0xcf, 0xf0, 0xd0, 0x90, 0x0b, 0x52, 0xd3, 0xb4 }; const munge_mac_t md = MUNGE_MAC_SHA1; return hkdf_test (md, ikm, sizeof (ikm), salt, sizeof (salt), info, sizeof (info), okm, sizeof (okm)); } /* Test Case 6: SHA-1 with zero-length salt/info */ int hkdf_test_6 (void) { const unsigned char ikm[22] = { 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b }; const unsigned char salt[1] = { 0x00 }; const unsigned char info[1] = { 0x00 }; const unsigned char okm[42] = { 0x0a, 0xc1, 0xaf, 0x70, 0x02, 0xb3, 0xd7, 0x61, 0xd1, 0xe5, 0x52, 0x98, 0xda, 0x9d, 0x05, 0x06, 0xb9, 0xae, 0x52, 0x05, 0x72, 0x20, 0xa3, 0x06, 0xe0, 0x7b, 0x6b, 0x87, 0xe8, 0xdf, 0x21, 0xd0, 0xea, 0x00, 0x03, 0x3d, 0xe0, 0x39, 0x84, 0xd3, 0x49, 0x18 }; const munge_mac_t md = MUNGE_MAC_SHA1; return hkdf_test (md, ikm, sizeof (ikm), salt, 0, info, 0, okm, sizeof (okm)); } /* Test Case 7: SHA-1 with no salt and zero-length info */ int hkdf_test_7 (void) { const unsigned char ikm[22] = { 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c }; const unsigned char info[1] = { 0x00 }; const unsigned char okm[42] = { 0x2c, 0x91, 0x11, 0x72, 0x04, 0xd7, 0x45, 0xf3, 0x50, 0x0d, 0x63, 0x6a, 0x62, 0xf6, 0x4f, 0x0a, 0xb3, 0xba, 0xe5, 0x48, 0xaa, 0x53, 0xd4, 0x23, 0xb0, 0xd1, 0xf2, 0x7e, 0xbb, 0xa6, 0xf5, 0xe5, 0x67, 0x3a, 0x08, 0x1d, 0x70, 0xcc, 0xe7, 0xac, 0xfc, 0x48 }; const munge_mac_t md = MUNGE_MAC_SHA1; return hkdf_test (md, ikm, sizeof (ikm), NULL, 0, info, 0, okm, sizeof (okm)); } int main (int argc, char *argv[]) { crypto_init (); md_init_subsystem (); plan (7); ok (hkdf_test_1 () == 0, "RFC 5869 Test Case 1: SHA-256 basic test"); ok (hkdf_test_2 () == 0, "RFC 5869 Test Case 2: SHA-256 with longer inputs/outputs"); ok (hkdf_test_3 () == 0, "RFC 5869 Test Case 3: SHA-256 with zero-length salt/info"); ok (hkdf_test_4 () == 0, "RFC 5869 Test Case 4: SHA-1 basic test"); ok (hkdf_test_5 () == 0, "RFC 5869 Test Case 5: SHA-1 with longer inputs/outputs"); ok (hkdf_test_6 () == 0, "RFC 5869 Test Case 6: SHA-1 with zero-length salt/info"); ok (hkdf_test_7 () == 0, "RFC 5869 Test Case 7: SHA-1 with no salt and zero-length info"); done_testing (); crypto_fini (); exit (EXIT_SUCCESS); } munge-munge-0.5.15/src/common/mac.c000066400000000000000000000336001425467526100170270ustar00rootroot00000000000000/***************************************************************************** * Written by Chris Dunlap . * Copyright (C) 2007-2022 Lawrence Livermore National Security, LLC. * Copyright (C) 2002-2007 The Regents of the University of California. * UCRL-CODE-155910. * * This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE). * For details, see . * * MUNGE 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. Additionally for the MUNGE library (libmunge), you * can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation, * either version 3 of the License, or (at your option) any later version. * * MUNGE 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 * and GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * and GNU Lesser General Public License along with MUNGE. If not, see * . *****************************************************************************/ #if HAVE_CONFIG_H # include #endif /* HAVE_CONFIG_H */ #include #include #include "mac.h" #include "md.h" /***************************************************************************** * Private Prototypes *****************************************************************************/ static int _mac_init (mac_ctx *x, munge_mac_t md, const void *key, int keylen); static int _mac_update (mac_ctx *x, const void *src, int srclen); static int _mac_final (mac_ctx *x, void *dst, int *dstlenp); static int _mac_cleanup (mac_ctx *x); static int _mac_block (munge_mac_t md, const void *key, int keylen, void *dst, int *dstlenp, const void *src, int srclen); static int _mac_map_enum (munge_mac_t md, void *dst); /***************************************************************************** * Public Functions *****************************************************************************/ int mac_init (mac_ctx *x, munge_mac_t md, const void *key, int keylen) { int rc; if (!x || !key || (keylen < 0)) { return (-1); } rc = _mac_init (x, md, key, keylen); return (rc); } int mac_update (mac_ctx *x, const void *src, int srclen) { int rc; if (!x || !src || (srclen < 0)) { return (-1); } rc = _mac_update (x, src, srclen); return (rc); } int mac_final (mac_ctx *x, void *dst, int *dstlenp) { int rc; if (!x || !dst || !dstlenp) { return (-1); } rc = _mac_final (x, dst, dstlenp); return (rc); } int mac_cleanup (mac_ctx *x) { int rc; if (!x) { return (-1); } rc = _mac_cleanup (x); memset (x, 0, sizeof (*x)); return (rc); } int mac_size (munge_mac_t md) { return (md_size (md)); } int mac_block (munge_mac_t md, const void *key, int keylen, void *dst, int *dstlenp, const void *src, int srclen) { int rc; if (!key || (keylen < 0) || !dst || !dstlenp || !src || (srclen < 0)) { return (-1); } rc = _mac_block (md, key, keylen, dst, dstlenp, src, srclen); return (rc); } int mac_map_enum (munge_mac_t md, void *dst) { if ((md <= MUNGE_MAC_DEFAULT) || (md >= MUNGE_MAC_LAST_ITEM)) { return (-1); } return (_mac_map_enum (md, dst)); } /***************************************************************************** * Private Functions (Libgcrypt) *****************************************************************************/ #if HAVE_LIBGCRYPT #include #include "log.h" static int _mac_init (mac_ctx *x, munge_mac_t md, const void *key, int keylen) { gcry_error_t e; int algo; if (_mac_map_enum (md, &algo) < 0) { return (-1); } if ((e = gcry_md_open (&(x->ctx), algo, GCRY_MD_FLAG_HMAC)) != 0) { log_msg (LOG_DEBUG, "gcry_md_open failed for MAC=%d HMAC: %s", md, gcry_strerror (e)); return (-1); } if ((e = gcry_md_setkey (x->ctx, key, keylen)) != 0) { log_msg (LOG_DEBUG, "gcry_md_setkey failed for MAC=%d HMAC: %s", md, gcry_strerror (e)); return (-1); } /* Bypass mac_size() since md->algo mapping has already been computed. */ x->diglen = gcry_md_get_algo_dlen (algo); return (0); } static int _mac_update (mac_ctx *x, const void *src, int srclen) { gcry_md_write (x->ctx, src, srclen); return (0); } static int _mac_final (mac_ctx *x, void *dst, int *dstlenp) { unsigned char *digest; if (*dstlenp < x->diglen) { return (-1); } if ((digest = gcry_md_read (x->ctx, 0)) == NULL) { return (-1); } memcpy (dst, digest, x->diglen); *dstlenp = x->diglen; return (0); } static int _mac_cleanup (mac_ctx *x) { gcry_md_close (x->ctx); return (0); } static int _mac_block (munge_mac_t md, const void *key, int keylen, void *dst, int *dstlenp, const void *src, int srclen) { gcry_error_t e; int algo; int len; gcry_md_hd_t ctx; unsigned char *digest; if (_mac_map_enum (md, &algo) < 0) { return (-1); } /* Bypass mac_size() since md->algo mapping has already been computed. */ len = gcry_md_get_algo_dlen (algo); if (*dstlenp < len) { return (-1); } if ((e = gcry_md_open (&ctx, algo, GCRY_MD_FLAG_HMAC)) != 0) { log_msg (LOG_DEBUG, "gcry_md_open failed for MAC=%d HMAC: %s", md, gcry_strerror (e)); return (-1); } if ((e = gcry_md_setkey (ctx, key, keylen)) != 0) { log_msg (LOG_DEBUG, "gcry_md_setkey failed for MAC=%d HMAC: %s", md, gcry_strerror (e)); gcry_md_close (ctx); return (-1); } gcry_md_write (ctx, src, srclen); if ((digest = gcry_md_read (ctx, 0)) == NULL) { gcry_md_close (ctx); return (-1); } memcpy (dst, digest, len); *dstlenp = len; gcry_md_close (ctx); memset (&ctx, 0, sizeof (ctx)); return (0); } int _mac_map_enum (munge_mac_t md, void *dst) { return (md_map_enum (md, dst)); } #endif /* HAVE_LIBGCRYPT */ /***************************************************************************** * Private Functions (OpenSSL) *****************************************************************************/ #if HAVE_OPENSSL #include #include #if HAVE_OPENSSL_CORE_H #include #endif /* HAVE_OPENSSL_CORE_H */ #if HAVE_OPENSSL_CORE_NAMES_H #include #endif /* HAVE_OPENSSL_CORE_NAMES_H */ #if HAVE_OPENSSL_HMAC_H #include #endif /* HAVE_OPENSSL_HMAC_H */ static int _mac_init (mac_ctx *x, munge_mac_t md, const void *key, int keylen) { #if HAVE_OSSL_PARAM_P && HAVE_EVP_MAC_P /* OpenSSL >= 3.0 */ OSSL_PARAM *algo; EVP_MAC *mac; #else /* !HAVE_OSSL_PARAM_P */ /* OpenSSL < 3.0 */ EVP_MD *algo; #endif /* !HAVE_OSSL_PARAM_P */ if (_mac_map_enum (md, &algo) < 0) { return (-1); } #if HAVE_EVP_MAC_FETCH && HAVE_EVP_MAC_CTX_NEW /* OpenSSL >= 3.0 */ mac = EVP_MAC_fetch (NULL, "HMAC", NULL); if (mac == NULL) { return (-1); } x->ctx = EVP_MAC_CTX_new (mac); EVP_MAC_free (mac); #elif HAVE_HMAC_CTX_NEW /* OpenSSL >= 1.1.0, Deprecated since OpenSSL 3.0 */ x->ctx = HMAC_CTX_new (); #else /* !HAVE_HMAC_CTX_NEW */ x->ctx = OPENSSL_malloc (sizeof (HMAC_CTX)); #if HAVE_HMAC_CTX_INIT /* OpenSSL >= 0.9.7, < 1.1.0, Replaced with HMAC_CTX_reset() in 1.1.0 */ if (x->ctx != NULL) { HMAC_CTX_init (x->ctx); } #endif /* HAVE_HMAC_CTX_INIT */ #endif /* !HAVE_HMAC_CTX_NEW */ if (x->ctx == NULL) { return (-1); } #if HAVE_EVP_MAC_INIT /* OpenSSL >= 3.0 */ if (EVP_MAC_init (x->ctx, key, (size_t) keylen, algo) != 1) { return (-1); } #elif HAVE_HMAC_INIT_EX_RETURN_INT /* OpenSSL >= 1.0.0, Deprecated since OpenSSL 3.0 */ if (HMAC_Init_ex (x->ctx, key, keylen, algo, NULL) != 1) { return (-1); } #elif HAVE_HMAC_INIT_EX /* OpenSSL >= 0.9.7, < 1.0.0, Deprecated since OpenSSL 3.0 */ HMAC_Init_ex (x->ctx, key, keylen, algo, NULL); #elif HAVE_HMAC_INIT /* HMAC_Init() implicitly initializes the HMAC_CTX. */ /* OpenSSL >= 0.9.0, Deprecated since OpenSSL 1.1.0 */ HMAC_Init (x->ctx, key, keylen, algo); #else /* !HAVE_HMAC_INIT */ #error "No OpenSSL HMAC_Init" #endif /* !HAVE_HMAC_INIT */ x->diglen = mac_size (md); return (0); } static int _mac_update (mac_ctx *x, const void *src, int srclen) { #if HAVE_EVP_MAC_UPDATE /* OpenSSL >= 3.0 */ if (EVP_MAC_update (x->ctx, src, (size_t) srclen) != 1) { return (-1); } #elif HAVE_HMAC_UPDATE_RETURN_INT /* OpenSSL >= 1.0.0, Deprecated since OpenSSL 3.0 */ if (HMAC_Update (x->ctx, src, srclen) != 1) { return (-1); } #elif HAVE_HMAC_UPDATE /* OpenSSL >= 0.9.0, < 1.0.0, Deprecated since OpenSSL 3.0 */ HMAC_Update (x->ctx, src, srclen); #else /* !HAVE_HMAC_UPDATE */ #error "No OpenSSL HMAC_Update" #endif /* !HAVE_HMAC_UPDATE */ return (0); } static int _mac_final (mac_ctx *x, void *dst, int *dstlenp) { if (*dstlenp < x->diglen) { return (-1); } #if HAVE_EVP_MAC_FINAL /* OpenSSL >= 3.0 */ size_t dstsize = (size_t) *dstlenp; if (EVP_MAC_final (x->ctx, dst, &dstsize, dstsize) != 1) { return (-1); } if (dstsize > INT_MAX) { return (-1); } *dstlenp = (int) dstsize; #elif HAVE_HMAC_FINAL_RETURN_INT /* OpenSSL >= 1.0.0, Deprecated since OpenSSL 3.0 */ if (HMAC_Final (x->ctx, dst, (unsigned int *) dstlenp) != 1) { return (-1); } #elif HAVE_HMAC_FINAL /* OpenSSL >= 0.9.0, < 1.0.0, Deprecated since OpenSSL 3.0 */ HMAC_Final (x->ctx, dst, (unsigned int *) dstlenp); #else /* !HAVE_HMAC_FINAL */ #error "No OpenSSL HMAC_Final" #endif /* !HAVE_HMAC_FINAL */ return (0); } static int _mac_cleanup (mac_ctx *x) { #if HAVE_EVP_MAC_CTX_FREE /* OpenSSL >= 3.0 */ EVP_MAC_CTX_free (x->ctx); #elif HAVE_HMAC_CTX_FREE /* OpenSSL >= 1.1.0, Deprecated since OpenSSL 3.0 */ HMAC_CTX_free (x->ctx); #else /* !HAVE_HMAC_CTX_FREE */ #if HAVE_HMAC_CTX_CLEANUP /* OpenSSL >= 0.9.7, < 1.1.0 */ HMAC_CTX_cleanup (x->ctx); #elif HAVE_HMAC_CLEANUP /* OpenSSL >= 0.9.0, < 0.9.7 */ HMAC_cleanup (x->ctx); #endif /* HAVE_HMAC_CLEANUP */ OPENSSL_free (x->ctx); #endif /* !HAVE_HMAC_CTX_FREE */ x->ctx = NULL; return (0); } static int _mac_block (munge_mac_t md, const void *key, int keylen, void *dst, int *dstlenp, const void *src, int srclen) { #if HAVE_OSSL_PARAM_P /* OpenSSL >= 3.0 */ OSSL_PARAM *algo; #else /* !HAVE_OSSL_PARAM_P */ /* OpenSSL < 3.0 */ EVP_MD *algo; #endif /* !HAVE_OSSL_PARAM_P */ /* OpenSSL has EVP_MD_size(const EVP_MD *md) to get the size of the * message digest [md]. Converting from munge_mac_t to EVP_MD * is * straightforward. * OpenSSL 3.0 introduces EVP_MAC_CTX_get_mac_size(EVP_MAC_CTX *ctx). * But before that can be called, one needs to create the context via * EVP_MAC_fetch() and EVP_MAC_CTX_new(), specify the underlying message * digest in an OSSL_PARAM array, and initialize the context via * EVP_MAC_init(). And none of that is needed with EVP_Q_mac()! * So instead, mac_size() is called to abstract away any shenanigans in * getting the size of the message digest [md] needed to validate the * buffer size in [dstlenp]. */ if (*dstlenp < mac_size (md)) { return (-1); } if (_mac_map_enum (md, &algo) < 0) { return (-1); } #if HAVE_EVP_Q_MAC /* OpenSSL >= 3.0 */ size_t dstsize = (size_t) *dstlenp; if (!EVP_Q_mac (NULL, "HMAC", NULL, NULL, algo, key, (size_t) keylen, src, (size_t) srclen, dst, dstsize, &dstsize)) { return (-1); } if (dstsize > INT_MAX) { return (-1); } *dstlenp = (int) dstsize; #elif HAVE_HMAC /* OpenSSL < 3.0 */ if (!HMAC (algo, key, keylen, src, srclen, dst, (unsigned int *)dstlenp)) { return (-1); } #else #error "No OpenSSL single-pass HMAC routine" #endif return (0); } int _mac_map_enum (munge_mac_t md, void *dst) { #if HAVE_EVP_MAC_INIT /* * EVP_MAC_init() has a parameter of type "const OSSL_PARAM params[]", * so HAVE_EVP_MAC_INIT is being used here as a proxy to detect OpenSSL 3.0 * API changes. */ static const OSSL_PARAM param[][2] = { { OSSL_PARAM_END }, /* MUNGE_MAC_NONE */ { OSSL_PARAM_END }, /* MUNGE_MAC_DEFAULT */ { OSSL_PARAM_utf8_string (OSSL_ALG_PARAM_DIGEST, "MD5", 3), OSSL_PARAM_END }, /* MUNGE_MAC_MD5 */ { OSSL_PARAM_utf8_string (OSSL_ALG_PARAM_DIGEST, "SHA1", 4), OSSL_PARAM_END }, /* MUNGE_MAC_SHA1 */ { OSSL_PARAM_utf8_string (OSSL_ALG_PARAM_DIGEST, "RIPEMD160", 9), OSSL_PARAM_END }, /* MUNGE_MAC_RIPEMD160 */ { OSSL_PARAM_utf8_string (OSSL_ALG_PARAM_DIGEST, "SHA2-256", 8), OSSL_PARAM_END }, /* MUNGE_MAC_SHA256 */ { OSSL_PARAM_utf8_string (OSSL_ALG_PARAM_DIGEST, "SHA2-512", 8), OSSL_PARAM_END }, /* MUNGE_MAC_SHA512 */ }; if ((md < MUNGE_MAC_MD5) || (md > MUNGE_MAC_SHA512)) { return (-1); } if (dst != NULL) { * (const OSSL_PARAM **) dst = param[md]; } return (0); #else /* !HAVE_EVP_MAC_INIT */ return (md_map_enum (md, dst)); #endif /* !HAVE_EVP_MAC_INIT */ } #endif /* HAVE_OPENSSL */ munge-munge-0.5.15/src/common/mac.h000066400000000000000000000117061425467526100170370ustar00rootroot00000000000000/***************************************************************************** * Written by Chris Dunlap . * Copyright (C) 2007-2022 Lawrence Livermore National Security, LLC. * Copyright (C) 2002-2007 The Regents of the University of California. * UCRL-CODE-155910. * * This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE). * For details, see . * * MUNGE 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. Additionally for the MUNGE library (libmunge), you * can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation, * either version 3 of the License, or (at your option) any later version. * * MUNGE 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 * and GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * and GNU Lesser General Public License along with MUNGE. If not, see * . *****************************************************************************/ #ifndef MAC_H #define MAC_H #if HAVE_CONFIG_H # include #endif /* HAVE_CONFIG_H */ #include /***************************************************************************** * Data Types *****************************************************************************/ #if HAVE_LIBGCRYPT #include typedef struct { gcry_md_hd_t ctx; int diglen; } mac_ctx; #endif /* HAVE_LIBGCRYPT */ #if HAVE_OPENSSL #include /* openSUSE 15.1 has OpenSSL 1.1.0i-fips (14 Aug 2018) but defines EVP_MAC_CTX * in (libopenssl-1_1-devel-1.1.0i-lp151.8.12.2.x86_64) * (EVP_MAC_CTX shouldn't appear until OpenSSL 3.0), so also add a guard for * HAVE_EVP_MAC_CTX_NEW to prevent EVP_MAC_CTX from being erroneously used. */ #if HAVE_EVP_MAC_CTX_P && HAVE_EVP_MAC_CTX_NEW /* OpenSSL >= 3.0 */ typedef struct { EVP_MAC_CTX *ctx; int diglen; } mac_ctx; #else /* !HAVE_EVP_MAC_CTX_P */ #if HAVE_OPENSSL_HMAC_H #include #endif /* HAVE_OPENSSL_HMAC_H */ /* OpenSSL < 3.0 */ typedef struct { HMAC_CTX *ctx; int diglen; } mac_ctx; #endif /* !HAVE_EVP_MAC_CTX_P */ #endif /* HAVE_OPENSSL */ /***************************************************************************** * Prototypes *****************************************************************************/ int mac_init (mac_ctx *x, munge_mac_t md, const void *key, int keylen); /* * Initializes the message authentication code (MAC) context [x] * with the message digest [md] and key [key] of [keylen] bytes. * Returns 0 on success, or -1 on error. */ int mac_update (mac_ctx *x, const void *src, int srclen); /* * Updates the MAC context [x], reading [srclen] bytes from [src]. * This can be called multiple times to process successive blocks of data. * Returns 0 on success, or -1 on error. */ int mac_final (mac_ctx *x, void *dst, int *dstlenp); /* * Finalizes the MAC context [x], placing the MAC in [dst] of length * [dstlenp]. The [dst] buffer must have sufficient space for the MAC * output (mac_size). * After this function, no further calls to md_update() should be made. * Returns 0 on success, or -1 on error; in addition, [dstlenp] will be set * to the number of bytes written to [dst]. */ int mac_cleanup (mac_ctx *x); /* * Clears the MAC context [x]. * Returns 0 on success, or -1 on error. */ int mac_size (munge_mac_t md); /* * Returns the size (in bytes) of the message digest [md], or -1 on error. */ int mac_block (munge_mac_t md, const void *key, int keylen, void *dst, int *dstlenp, const void *src, int srclen); /* * Computes the MAC without the need of a context; this requires * the [src] to be contiguous. * Uses the message digest [md] and key [key] of [keylen] bytes. * Reads [srclen] bytes of data from [src], and writes the MAC to [dst] * of length [dstlenp]. * Returns 0 on success, or -1 on error; in addition, [dstlenp] will be set * to the number of bytes written to [dst]. */ int mac_map_enum (munge_mac_t md, void *dst); /* * Map the specified [md] algorithm to the internal representation used * by the underlying cryptographic library. * If [dst] is non-NULL, write the cryptographic library's internal * representation of the message digest algorithm to [dst]; otherwise, just * validate the specified [md] algorithm. * Returns 0 on success, or -1 on error. */ #endif /* !MAC_H */ munge-munge-0.5.15/src/common/mac_test.c000066400000000000000000000130371425467526100200700ustar00rootroot00000000000000/***************************************************************************** * Written by Chris Dunlap . * Copyright (C) 2007-2022 Lawrence Livermore National Security, LLC. * Copyright (C) 2002-2007 The Regents of the University of California. * UCRL-CODE-155910. * * This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE). * For details, see . * * MUNGE 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. Additionally for the MUNGE library (libmunge), you * can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation, * either version 3 of the License, or (at your option) any later version. * * MUNGE 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 * and GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * and GNU Lesser General Public License along with MUNGE. If not, see * . *****************************************************************************/ #if HAVE_CONFIG_H # include "config.h" #endif /* HAVE_CONFIG_H */ #include #include #include #include #include "crypto.h" #include "mac.h" #include "md.h" #include "tap.h" int check_mac (munge_mac_t m, const char *str, const char *key, int keylen, const char *src, int srclen, const unsigned char *dst, int dstlen) { unsigned char buf[64]; int buflen; mac_ctx ctx; int rv; if (!str) { fail ("check_mac empty str for mac #%d", (int) m); return -1; } if (!key || (keylen <= 0)) { fail ("check_mac invalid key or keylen for %s", str); return -1; } if (!src || (srclen <= 0)) { fail ("check_mac invalid src or srclen for %s", str); return -1; } if (!dst || (dstlen <= 0)) { fail ("check_mac invalid dst or dstlen for %s", str); return -1; } if (dstlen > sizeof (buf)) { fail ("check_mac %ld-byte buf too small for %s %d-byte result", sizeof (buf), str, dstlen); return -1; } ok (mac_size (m) == dstlen, "mac_size %s is %d", str, dstlen); ok (!mac_map_enum (m, NULL), "mac_map_enum %s", str); buflen = sizeof (buf); memset (buf, 0, sizeof (buf)); ok (!mac_block (m, key, keylen, buf, &buflen, src, srclen), "mac_block %s", str); ok (buflen == dstlen, "mac_block %s outlen", str); cmp_mem (buf, dst, dstlen, "mac_block %s output", str); buflen = sizeof (buf); memset (buf, 0, sizeof (buf)); ok (!(rv = mac_init (&ctx, m, key, keylen)), "mac_init %s", str); ok (!rv && !(rv = mac_update (&ctx, src, srclen)), "mac_update %s", str); ok (!rv && !(rv = mac_final (&ctx, buf, &buflen)), "mac_final %s", str); ok (buflen == dstlen, "mac_final %s outlen", str); cmp_mem (buf, dst, dstlen, "mac_final %s output", str); ok (!rv && !(rv = mac_cleanup (&ctx)), "mac_cleanup %s", str); return rv; } int main (int argc, char *argv[]) { const char *key = "magic words"; const char *in = "squeamish ossifrage"; const unsigned char out_md5[16] = { 0x89, 0x98, 0xc9, 0xb1, 0xb6, 0xf9, 0xfd, 0xd6, 0x6f, 0x3a, 0x5c, 0x0a, 0xf9, 0x22, 0x69, 0x60 }; const unsigned char out_sha1[20] = { 0x1e, 0x17, 0x06, 0x6e, 0x61, 0x71, 0xe5, 0x75, 0x7a, 0xcf, 0x1c, 0x99, 0x35, 0x04, 0x14, 0x36, 0x7f, 0x98, 0x33, 0xe5 }; const unsigned char out_ripemd160[20] = { 0x11, 0x68, 0x37, 0x52, 0x26, 0xcd, 0xc5, 0xfe, 0xb7, 0xb9, 0xce, 0x45, 0x0c, 0xfc, 0x73, 0xd9, 0x68, 0x3c, 0xaf, 0xa2 }; const unsigned char out_sha256[32] = { 0xcb, 0xc1, 0xa8, 0xe6, 0x30, 0x0d, 0x7f, 0x92, 0xb0, 0xbe, 0x65, 0x97, 0x6a, 0xe3, 0x61, 0x47, 0x61, 0x44, 0x81, 0x4a, 0xfc, 0xac, 0x1e, 0x6b, 0x81, 0xbb, 0xf6, 0x81, 0x9c, 0x31, 0xda, 0x0f }; const unsigned char out_sha512[64] = { 0xa1, 0x3d, 0x45, 0x37, 0x3a, 0xad, 0x58, 0x08, 0xa4, 0x31, 0x0b, 0x9b, 0xd5, 0xb7, 0x88, 0xd4, 0x64, 0x86, 0xf2, 0x26, 0xbe, 0x0d, 0x7e, 0xcc, 0xd9, 0xcf, 0xab, 0x8d, 0x88, 0x0f, 0x9d, 0x35, 0xa9, 0x66, 0x2a, 0x78, 0xfa, 0x87, 0x6a, 0x62, 0x89, 0x3c, 0x1c, 0x1e, 0x87, 0xcb, 0x13, 0x2e, 0xef, 0x39, 0x87, 0xac, 0xb3, 0xb9, 0x7e, 0x73, 0x10, 0x9b, 0xae, 0xde, 0xce, 0x1b, 0xd4, 0x79 }; crypto_init (); md_init_subsystem (); plan (NO_PLAN); check_mac (MUNGE_MAC_MD5, "MUNGE_MAC_MD5", key, strlen (key), in, strlen (in), out_md5, sizeof (out_md5)); check_mac (MUNGE_MAC_SHA1, "MUNGE_MAC_SHA1", key, strlen (key), in, strlen (in), out_sha1, sizeof (out_sha1)); check_mac (MUNGE_MAC_RIPEMD160, "MUNGE_MAC_RIPEMD160", key, strlen (key), in, strlen (in), out_ripemd160, sizeof (out_ripemd160)); check_mac (MUNGE_MAC_SHA256, "MUNGE_MAC_SHA256", key, strlen (key), in, strlen (in), out_sha256, sizeof (out_sha256)); check_mac (MUNGE_MAC_SHA512, "MUNGE_MAC_SHA512", key, strlen (key), in, strlen (in), out_sha512, sizeof (out_sha512)); done_testing (); crypto_fini (); exit (EXIT_SUCCESS); } munge-munge-0.5.15/src/common/md.c000066400000000000000000000260251425467526100166720ustar00rootroot00000000000000/***************************************************************************** * Written by Chris Dunlap . * Copyright (C) 2007-2022 Lawrence Livermore National Security, LLC. * Copyright (C) 2002-2007 The Regents of the University of California. * UCRL-CODE-155910. * * This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE). * For details, see . * * MUNGE 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. Additionally for the MUNGE library (libmunge), you * can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation, * either version 3 of the License, or (at your option) any later version. * * MUNGE 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 * and GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * and GNU Lesser General Public License along with MUNGE. If not, see * . *****************************************************************************/ #if HAVE_CONFIG_H # include #endif /* HAVE_CONFIG_H */ #include #include #include #include "md.h" /***************************************************************************** * Private Data *****************************************************************************/ static int _md_is_initialized = 0; /***************************************************************************** * Private Prototypes *****************************************************************************/ static void _md_init_subsystem (void); static int _md_init (md_ctx *x, munge_mac_t md); static int _md_update (md_ctx *x, const void *src, int srclen); static int _md_final (md_ctx *x, void *dst, int *dstlenp); static int _md_cleanup (md_ctx *x); static int _md_copy (md_ctx *xdst, md_ctx *xsrc); static int _md_size (munge_mac_t md); static int _md_map_enum (munge_mac_t md, void *dst); /***************************************************************************** * Public Functions *****************************************************************************/ void md_init_subsystem (void) { /* Note that this call is *NOT* thread-safe. */ if (! _md_is_initialized) { _md_init_subsystem (); _md_is_initialized++; } return; } int md_init (md_ctx *x, munge_mac_t md) { int rc; assert (_md_is_initialized); if (!x) { return (-1); } rc = _md_init (x, md); return (rc); } int md_update (md_ctx *x, const void *src, int srclen) { int rc; assert (_md_is_initialized); if (!x || !src || (srclen < 0)) { return (-1); } rc = _md_update (x, src, srclen); return (rc); } int md_final (md_ctx *x, void *dst, int *dstlenp) { int rc; assert (_md_is_initialized); if (!x || !dst || !dstlenp) { return (-1); } rc = _md_final (x, dst, dstlenp); return (rc); } int md_cleanup (md_ctx *x) { int rc; assert (_md_is_initialized); if (!x) { return (-1); } rc = _md_cleanup (x); memset (x, 0, sizeof (*x)); return (rc); } int md_copy (md_ctx *xdst, md_ctx *xsrc) { int rc; assert (_md_is_initialized); if (!xdst || !xsrc) { return (-1); } xdst->diglen = xsrc->diglen; rc = _md_copy (xdst, xsrc); return (rc); } int md_size (munge_mac_t md) { assert (_md_is_initialized); return (_md_size (md)); } int md_map_enum (munge_mac_t md, void *dst) { assert (_md_is_initialized); return (_md_map_enum (md, dst)); } /***************************************************************************** * Private Functions (Libgcrypt) *****************************************************************************/ #if HAVE_LIBGCRYPT #include #include #include "log.h" static int _md_map [MUNGE_MAC_LAST_ITEM]; static void _md_init_subsystem (void) { int i; for (i = 0; i < MUNGE_MAC_LAST_ITEM; i++) { _md_map [i] = -1; } _md_map [MUNGE_MAC_MD5] = GCRY_MD_MD5; _md_map [MUNGE_MAC_SHA1] = GCRY_MD_SHA1; _md_map [MUNGE_MAC_RIPEMD160] = GCRY_MD_RMD160; _md_map [MUNGE_MAC_SHA256] = GCRY_MD_SHA256; _md_map [MUNGE_MAC_SHA512] = GCRY_MD_SHA512; return; } static int _md_init (md_ctx *x, munge_mac_t md) { gcry_error_t e; int algo; if (_md_map_enum (md, &algo) < 0) { return (-1); } if ((e = gcry_md_open (&(x->ctx), algo, 0)) != 0) { log_msg (LOG_DEBUG, "gcry_md_open failed for MAC=%d: %s", md, gcry_strerror (e)); return (-1); } x->diglen = gcry_md_get_algo_dlen (algo); return (0); } static int _md_update (md_ctx *x, const void *src, int srclen) { gcry_md_write (x->ctx, src, srclen); return (0); } static int _md_final (md_ctx *x, void *dst, int *dstlenp) { unsigned char *digest; if (*dstlenp < x->diglen) { return (-1); } if ((digest = gcry_md_read (x->ctx, 0)) == NULL) { return (-1); } memcpy (dst, digest, x->diglen); *dstlenp = x->diglen; return (0); } static int _md_cleanup (md_ctx *x) { gcry_md_close (x->ctx); return (0); } static int _md_copy (md_ctx *xdst, md_ctx *xsrc) { gcry_error_t e; if ((e = gcry_md_copy (&(xdst->ctx), xsrc->ctx)) != 0) { log_msg (LOG_DEBUG, "gcry_md_copy failed: %s", gcry_strerror (e)); return (-1); } return (0); } static int _md_size (munge_mac_t md) { int algo; if (_md_map_enum (md, &algo) < 0) { return (-1); } return (gcry_md_get_algo_dlen (algo)); } static int _md_map_enum (munge_mac_t md, void *dst) { int algo = -1; if ((md > MUNGE_MAC_DEFAULT) && (md < MUNGE_MAC_LAST_ITEM)) { algo = _md_map [md]; } if (algo < 0) { return (-1); } if (dst != NULL) { * (int *) dst = algo; } return (0); } #endif /* HAVE_LIBGCRYPT */ /***************************************************************************** * Private Functions (OpenSSL) *****************************************************************************/ #if HAVE_OPENSSL #include static const EVP_MD * _md_map [MUNGE_MAC_LAST_ITEM]; static int _md_ctx_create (md_ctx *x); static void _md_init_subsystem (void) { int i; for (i = 0; i < MUNGE_MAC_LAST_ITEM; i++) { _md_map [i] = NULL; } _md_map [MUNGE_MAC_MD5] = EVP_md5 (); _md_map [MUNGE_MAC_SHA1] = EVP_sha1 (); _md_map [MUNGE_MAC_RIPEMD160] = EVP_ripemd160 (); #if HAVE_EVP_SHA256 _md_map [MUNGE_MAC_SHA256] = EVP_sha256 (); #endif /* HAVE_EVP_SHA256 */ #if HAVE_EVP_SHA512 _md_map [MUNGE_MAC_SHA512] = EVP_sha512 (); #endif /* HAVE_EVP_SHA512 */ return; } static int _md_init (md_ctx *x, munge_mac_t md) { EVP_MD *algo; if (_md_map_enum (md, &algo) < 0) { return (-1); } if (_md_ctx_create (x) < 0) { return (-1); } #if HAVE_EVP_DIGESTINIT_EX /* OpenSSL >= 0.9.7 */ if (EVP_DigestInit_ex (x->ctx, algo, NULL) != 1) { return (-1); } #elif HAVE_EVP_DIGESTINIT /* EVP_DigestInit() implicitly initializes the EVP_MD_CTX. */ /* OpenSSL < 0.9.7 */ EVP_DigestInit (x->ctx, algo); #else /* !HAVE_EVP_DIGESTINIT */ #error "No OpenSSL EVP_DigestInit" #endif /* !HAVE_EVP_DIGESTINIT */ x->diglen = EVP_MD_size (algo); return (0); } static int _md_ctx_create (md_ctx *x) { #if HAVE_EVP_MD_CTX_NEW /* OpenSSL >= 1.1.0 */ x->ctx = EVP_MD_CTX_new (); /* alloc & init */ #elif HAVE_EVP_MD_CTX_CREATE /* OpenSSL >= 0.9.7, < 1.1.0 */ x->ctx = EVP_MD_CTX_create (); /* alloc & init */ #else /* !HAVE_EVP_MD_CTX_CREATE */ x->ctx = OPENSSL_malloc (sizeof (EVP_MD_CTX)); /* allocate */ #if HAVE_EVP_MD_CTX_INIT /* OpenSSL >= 0.9.7, < 1.1.0 */ if (x->ctx != NULL ) { EVP_MD_CTX_init (x->ctx); /* initialize */ } #endif /* HAVE_EVP_MD_CTX_INIT */ #endif /* !HAVE_EVP_MD_CTX_CREATE */ if (x->ctx == NULL) { return (-1); } return (0); } static int _md_update (md_ctx *x, const void *src, int srclen) { #if HAVE_EVP_DIGESTUPDATE_RETURN_INT /* OpenSSL >= 0.9.7 */ if (EVP_DigestUpdate (x->ctx, src, (unsigned int) srclen) != 1) { return (-1); } #elif HAVE_EVP_DIGESTUPDATE /* OpenSSL < 0.9.7 */ EVP_DigestUpdate (x->ctx, src, (unsigned int) srclen); #else /* !HAVE_EVP_DIGESTUPDATE */ #error "No OpenSSL EVP_DigestUpdate" #endif /* !HAVE_EVP_DIGESTUPDATE */ return (0); } static int _md_final (md_ctx *x, void *dst, int *dstlenp) { if (*dstlenp < x->diglen) { return (-1); } #if HAVE_EVP_DIGESTFINAL_EX /* OpenSSL >= 0.9.7 */ if (!(EVP_DigestFinal_ex (x->ctx, dst, (unsigned int *) dstlenp))) { return (-1); } #elif HAVE_EVP_DIGESTFINAL /* OpenSSL < 0.9.7 */ EVP_DigestFinal (x->ctx, dst, (unsigned int *) dstlenp); #else /* !HAVE_EVP_DIGESTFINAL */ #error "No OpenSSL EVP_DigestFinal" #endif /* !HAVE_EVP_DIGESTFINAL */ return (0); } static int _md_cleanup (md_ctx *x) { int rc = 0; #if HAVE_EVP_MD_CTX_FREE /* OpenSSL >= 1.1.0 */ EVP_MD_CTX_free (x->ctx); #elif HAVE_EVP_MD_CTX_DESTROY /* OpenSSL >= 0.9.7, < 1.1.0 */ EVP_MD_CTX_destroy (x->ctx); #else /* !HAVE_EVP_MD_CTX_DESTROY */ #if HAVE_EVP_MD_CTX_CLEANUP /* OpenSSL >= 0.9.7, < 1.1.0 */ if (EVP_MD_CTX_cleanup (x->ctx) != 1) { rc = -1; } #endif /* HAVE_EVP_MD_CTX_CLEANUP */ OPENSSL_free (x->ctx); #endif /* !HAVE_EVP_MD_CTX_DESTROY */ x->ctx = NULL; return (rc); } static int _md_copy (md_ctx *xdst, md_ctx *xsrc) { if (_md_ctx_create (xdst) < 0) { return (-1); } #if HAVE_EVP_MD_CTX_COPY_EX /* OpenSSL >= 0.9.7 */ if (!(EVP_MD_CTX_copy_ex (xdst->ctx, xsrc->ctx))) { return (-1); } #elif HAVE_EVP_MD_CTX_COPY /* EVP_MD_CTX_copy() implicitly initializes the EVP_MD_CTX for xdst. */ if (!(EVP_MD_CTX_copy (xdst->ctx, xsrc->ctx))) { return (-1); } #else /* !HAVE_EVP_MD_CTX_COPY */ #error "No OpenSSL EVP_MD_CTX_copy" #endif /* !HAVE_EVP_MD_CTX_COPY */ return (0); } static int _md_size (munge_mac_t md) { EVP_MD *algo; if (_md_map_enum (md, &algo) < 0) { return (-1); } return (EVP_MD_size (algo)); } static int _md_map_enum (munge_mac_t md, void *dst) { const EVP_MD *algo = NULL; if ((md > MUNGE_MAC_DEFAULT) && (md < MUNGE_MAC_LAST_ITEM)) { algo = _md_map [md]; } if (algo == NULL) { return (-1); } if (dst != NULL) { * (const EVP_MD **) dst = algo; } return (0); } #endif /* HAVE_OPENSSL */ munge-munge-0.5.15/src/common/md.h000066400000000000000000000103201425467526100166660ustar00rootroot00000000000000/***************************************************************************** * Written by Chris Dunlap . * Copyright (C) 2007-2022 Lawrence Livermore National Security, LLC. * Copyright (C) 2002-2007 The Regents of the University of California. * UCRL-CODE-155910. * * This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE). * For details, see . * * MUNGE 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. Additionally for the MUNGE library (libmunge), you * can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation, * either version 3 of the License, or (at your option) any later version. * * MUNGE 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 * and GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * and GNU Lesser General Public License along with MUNGE. If not, see * . *****************************************************************************/ #ifndef MD_H #define MD_H #if HAVE_CONFIG_H # include #endif /* HAVE_CONFIG_H */ #include /***************************************************************************** * Data Types *****************************************************************************/ #if HAVE_LIBGCRYPT #include typedef struct { gcry_md_hd_t ctx; int diglen; } md_ctx; #endif /* HAVE_LIBGCRYPT */ #if HAVE_OPENSSL #include typedef struct { EVP_MD_CTX *ctx; int diglen; } md_ctx; #endif /* HAVE_OPENSSL */ /***************************************************************************** * Prototypes *****************************************************************************/ void md_init_subsystem (void); /* * Initializes the message digest subsystem. * WARNING: This routine is *NOT* guaranteed to be thread-safe. */ int md_init (md_ctx *x, munge_mac_t md); /* * Initializes a new message digest context [x] with the message digest [md]. * Returns 0 on success, or -1 on error. */ int md_update (md_ctx *x, const void *src, int srclen); /* * Updates the message digest context [x], reading [srclen] bytes from [src]. * This can be called multiple times to process successive blocks of data. * Returns 0 on success, or -1 on error. */ int md_final (md_ctx *x, void *dst, int *dstlenp); /* * Finalizes the message digest context [x], placing the digest in [dst] * of length [dstlenp]. The [dst] buffer must have sufficient space for * the message digest output (md_size). * After this function, no further calls to md_update() should be made. * Returns 0 on success, or -1 on error; in addition, [dstlenp] will be set * to the number of bytes written to [dst]. */ int md_cleanup (md_ctx *x); /* * Clears the message digest context [x]. * Returns 0 on success, or -1 on error. */ int md_copy (md_ctx *xdst, md_ctx *xsrc); /* * Initializes a new message digest context [xdst], and copies the state * from the [xsrc] context to the new [xdst] context. * This is useful if large amounts of data are to be hashed which only differ * in the last few bytes. * Returns 0 on success, or -1 on error. */ int md_size (munge_mac_t md); /* * Returns the size (in bytes) of the message digest [md], or -1 on error. */ int md_map_enum (munge_mac_t md, void *dst); /* * Map the specified [md] algorithm to the internal representation used * by the underlying cryptographic library. * If [dst] is non-NULL, write the cryptographic library's internal * representation of the message digest algorithm to [dst]; otherwise, just * validate the specified [md] algorithm. * Returns 0 on success, or -1 on error. */ #endif /* !MD_H */ munge-munge-0.5.15/src/common/query.c000066400000000000000000000073531425467526100174420ustar00rootroot00000000000000/***************************************************************************** * Written by Chris Dunlap . * Copyright (C) 2007-2022 Lawrence Livermore National Security, LLC. * Copyright (C) 2002-2007 The Regents of the University of California. * UCRL-CODE-155910. * * This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE). * For details, see . * * MUNGE 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. Additionally for the MUNGE library (libmunge), you * can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation, * either version 3 of the License, or (at your option) any later version. * * MUNGE 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 * and GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * and GNU Lesser General Public License along with MUNGE. If not, see * . *****************************************************************************/ #if HAVE_CONFIG_H # include "config.h" #endif /* HAVE_CONFIG_H */ #include #include #include #include #include #include #include #include "common.h" #include "query.h" #include "xgetgr.h" #include "xgetpw.h" int query_uid (const char *user, uid_t *uid_ptr) { xpwbuf_p pwbufp; struct passwd pw; uid_t uid; long int l; char *end_ptr; int rv; if (user == NULL) { errno = EINVAL; return (-1); } pwbufp = xgetpwbuf_create (0); if (pwbufp == NULL) { return (-1); } if (xgetpwnam (user, &pw, pwbufp) == 0) { uid = pw.pw_uid; rv = 0; } else { errno = 0; l = strtol (user, &end_ptr, 10); if ((errno == ERANGE) && ((l == LONG_MIN) || (l == LONG_MAX))) { rv = -1; } else if ((user == end_ptr) || (*end_ptr != '\0')) { rv = -1; } else if ((l < 0) || ((unsigned int) l > UID_MAXIMUM)) { rv = -1; } else { uid = (uid_t) l; rv = 0; } } if ((uid_ptr != NULL) && (rv == 0)) { *uid_ptr = uid; } xgetpwbuf_destroy (pwbufp); return (rv); } int query_gid (const char *group, gid_t *gid_ptr) { xgrbuf_p grbufp; struct group gr; gid_t gid; long int l; char *end_ptr; int rv; if (group == NULL) { errno = EINVAL; return (-1); } grbufp = xgetgrbuf_create (0); if (grbufp == NULL) { return (-1); } if (xgetgrnam (group, &gr, grbufp) == 0) { gid = gr.gr_gid; rv = 0; } else { errno = 0; l = strtol (group, &end_ptr, 10); if ((errno == ERANGE) && ((l == LONG_MIN) || (l == LONG_MAX))) { rv = -1; } else if ((group == end_ptr) || (*end_ptr != '\0')) { rv = -1; } else if ((l < 0) || ((unsigned int) l > GID_MAXIMUM)) { rv = -1; } else { gid = (gid_t) l; rv = 0; } } if ((gid_ptr != NULL) && (rv == 0)) { *gid_ptr = gid; } xgetgrbuf_destroy (grbufp); return (rv); } munge-munge-0.5.15/src/common/query.h000066400000000000000000000041721425467526100174430ustar00rootroot00000000000000/***************************************************************************** * Written by Chris Dunlap . * Copyright (C) 2007-2022 Lawrence Livermore National Security, LLC. * Copyright (C) 2002-2007 The Regents of the University of California. * UCRL-CODE-155910. * * This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE). * For details, see . * * MUNGE 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. Additionally for the MUNGE library (libmunge), you * can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation, * either version 3 of the License, or (at your option) any later version. * * MUNGE 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 * and GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * and GNU Lesser General Public License along with MUNGE. If not, see * . *****************************************************************************/ #ifndef MUNGE_QUERY_H #define MUNGE_QUERY_H #include int query_uid (const char *user, uid_t *uid_ptr); /* * Queries for the User ID using the [user] string which can specify the * user name or UID number. * Returns 0 on success with the UID stored at [uid_ptr] (if non-NULL). * Returns -1 on error without updating [uid_ptr]. */ int query_gid (const char *group, gid_t *gid_ptr); /* * Queries for the Group ID using the [group] string which can specify the * group name or GID number. * Returns 0 on success with the GID stored at [gid_ptr] (if non-NULL). * Returns -1 on error without updating [gid_ptr]. */ #endif /* !MUNGE_QUERY_H */ munge-munge-0.5.15/src/common/rotate.c000066400000000000000000000052451425467526100175710ustar00rootroot00000000000000/***************************************************************************** * Written by Chris Dunlap . * Copyright (C) 2007-2022 Lawrence Livermore National Security, LLC. * Copyright (C) 2002-2007 The Regents of the University of California. * UCRL-CODE-155910. * * This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE). * For details, see . * * MUNGE 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. Additionally for the MUNGE library (libmunge), you * can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation, * either version 3 of the License, or (at your option) any later version. * * MUNGE 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 * and GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * and GNU Lesser General Public License along with MUNGE. If not, see * . *****************************************************************************/ #if HAVE_CONFIG_H # include "config.h" #endif /* HAVE_CONFIG_H */ #include #include #include "rotate.h" /***************************************************************************** * Public Functions *****************************************************************************/ /* Rotate the reference [*up] by [n] bits to the left. * Bits rotated off the left end are wrapped-around to the right. */ void rotate_left (unsigned *up, size_t n) { unsigned ntotal; unsigned mask; unsigned move; assert (up != NULL); ntotal = sizeof (*up) * 8; n %= ntotal; if (n == 0) { return; } mask = ~0 << (ntotal - n); move = *up & mask; move >>= ntotal - n; *up <<= n; *up |= move; } /* Rotate the reference [*up] by [n] bits to the right. * Bits rotated off the right end are wrapped-around to the left. */ void rotate_right (unsigned *up, size_t n) { unsigned ntotal; unsigned mask; unsigned move; assert (up != NULL); ntotal = sizeof (*up) * 8; n %= ntotal; if (n == 0) { return; } mask = ~0 >> (ntotal - n); move = *up & mask; move <<= ntotal - n; *up >>= n; *up |= move; } munge-munge-0.5.15/src/common/rotate.h000066400000000000000000000032211425467526100175660ustar00rootroot00000000000000/***************************************************************************** * Written by Chris Dunlap . * Copyright (C) 2007-2022 Lawrence Livermore National Security, LLC. * Copyright (C) 2002-2007 The Regents of the University of California. * UCRL-CODE-155910. * * This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE). * For details, see . * * MUNGE 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. Additionally for the MUNGE library (libmunge), you * can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation, * either version 3 of the License, or (at your option) any later version. * * MUNGE 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 * and GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * and GNU Lesser General Public License along with MUNGE. If not, see * . *****************************************************************************/ #ifndef MUNGE_ROTATE_H #define MUNGE_ROTATE_H #include void rotate_left (unsigned *up, size_t n); void rotate_right (unsigned *up, size_t n); #endif /* !MUNGE_ROTATE_H */ munge-munge-0.5.15/src/common/xgetgr.c000066400000000000000000000410631425467526100175710ustar00rootroot00000000000000/***************************************************************************** * Written by Chris Dunlap . * Copyright (C) 2007-2022 Lawrence Livermore National Security, LLC. * Copyright (C) 2002-2007 The Regents of the University of California. * UCRL-CODE-155910. * * This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE). * For details, see . * * MUNGE 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. Additionally for the MUNGE library (libmunge), you * can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation, * either version 3 of the License, or (at your option) any later version. * * MUNGE 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 * and GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * and GNU Lesser General Public License along with MUNGE. If not, see * . *****************************************************************************/ #if HAVE_CONFIG_H # include "config.h" #endif /* HAVE_CONFIG_H */ #if HAVE_GETGRENT_R_GNU #define _GNU_SOURCE 1 #elif HAVE_GETGRENT_R_AIX #define HAVE_GETGRENT_R_ERANGE_BROKEN 1 #define _THREAD_SAFE 1 #include #elif HAVE_GETGRENT_R_SUN #define HAVE_GETGRENT_R_ERANGE_BROKEN 1 #elif HAVE_GETGRENT #ifdef WITH_PTHREADS #include #endif /* WITH_PTHREADS */ #else #error "getgrent() not supported" #endif #if HAVE_GETGRNAM_R_POSIX #define _POSIX_PTHREAD_SEMANTICS 1 /* for SunOS */ #elif HAVE_GETGRNAM_R_SUN #undef _POSIX_PTHREAD_SEMANTICS #elif HAVE_GETGRNAM #ifdef WITH_PTHREADS #include #endif /* WITH_PTHREADS */ #else #error "getgrnam() not supported" #endif #include #include #include #include #include #include #include #include #include #include "log.h" #include "xgetgr.h" /***************************************************************************** * Compiler Fu *****************************************************************************/ #ifdef __GNUC__ #define _UNUSED_ __attribute__ ((unused)) #else #define _UNUSED_ #endif /***************************************************************************** * Constants *****************************************************************************/ #define MINIMUM_GR_BUF_SIZE 1024 /***************************************************************************** * Data Types *****************************************************************************/ struct xgrbuf_t { char *buf; size_t len; }; /***************************************************************************** * Private Variables *****************************************************************************/ #if HAVE_GETGRENT_R_AIX static FILE *_gr_fp; #endif /***************************************************************************** * Private Prototypes *****************************************************************************/ static size_t _xgetgrbuf_get_sys_size (void); static int _xgetgrbuf_grow (xgrbuf_p grbufp, size_t minlen); static int _xgetgrbuf_copy_struct (const struct group *src, struct group *dst, xgrbuf_p grbufp) _UNUSED_; static int _xgetgrbuf_copy_string (const char *src, char **dstp, char **bufp, size_t *buflenp) _UNUSED_; /***************************************************************************** * Public Functions *****************************************************************************/ xgrbuf_p xgetgrbuf_create (size_t len) { /* Allocates a buffer for xgetgrent(). [len] specifies a suggested size * for the buffer; if 0, the system recommended size will be used. * Returns the buffer on success, or NULL on error (with errno). */ xgrbuf_p grbufp; if (len == 0) { len = _xgetgrbuf_get_sys_size (); } grbufp = malloc (sizeof (struct xgrbuf_t)); if (grbufp == NULL) { return (NULL); } grbufp->buf = malloc (len); if (grbufp->buf == NULL) { free (grbufp); return (NULL); } grbufp->len = len; log_msg (LOG_DEBUG, "Created group entry buffer of size %u", len); return (grbufp); } void xgetgrbuf_destroy (xgrbuf_p grbufp) { /* Destroys the buffer [grbufp]. */ if (grbufp != NULL) { if (grbufp->buf != NULL) { free (grbufp->buf); } free (grbufp); } return; } size_t xgetgrbuf_get_len (xgrbuf_p grbufp) { /* Returns the current size of the allocated buffer within [grbufp], * or 0 on error (with errno). */ if (grbufp == NULL) { errno = EINVAL; return (0); } return (grbufp->len); } void xgetgrent_init (void) { /* Portable encapsulation of setgrent(). */ #if HAVE_GETGRENT_R_AIX _gr_fp = NULL; #endif setgrent (); return; } int xgetgrent (struct group *grp, xgrbuf_p grbufp) { /* Portable encapsulation of getgrent_r(). * Reads the next group entry from the stream initialized by xgetgrent_init(), * storing the struct group result in [grp] and additional strings in the * buffer [grbufp]. * Returns 0 on success, or -1 on error (with errno). * Returns -1 with ENOENT when there are no more entries. * Returns -1 with ERANGE when the underlying getgrent_r() call cannot be * automatically restarted after resizing the buffer [grbufp]. */ int rv; #if HAVE_GETGRENT_R_GNU struct group *rv_grp; #elif HAVE_GETGRENT_R_AIX #elif HAVE_GETGRENT_R_SUN struct group *rv_grp; #elif HAVE_GETGRENT #ifdef WITH_PTHREADS static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; int rv_mutex; #endif /* WITH_PTHREADS */ int rv_copy; struct group *rv_grp; #endif /* HAVE_GETGRENT */ int got_eof; int got_err; if ((grp == NULL) || (grbufp == NULL)) { errno = EINVAL; return (-1); } assert (grbufp->buf != NULL); assert (grbufp->len > 0); restart: errno = 0; got_eof = 0; got_err = 0; #if HAVE_GETGRENT_R_GNU rv_grp = NULL; rv = getgrent_r (grp, grbufp->buf, grbufp->len, &rv_grp); if (((rv == ENOENT) || (rv == 0)) && (rv_grp == NULL)) { got_eof = 1; } else if (rv != 0) { got_err = 1; errno = rv; } #elif HAVE_GETGRENT_R_AIX rv = getgrent_r (grp, grbufp->buf, grbufp->len, &_gr_fp); if (rv != 0) { if (errno == 0) { got_eof = 1; } else { got_err = 1; } } #elif HAVE_GETGRENT_R_SUN rv_grp = getgrent_r (grp, grbufp->buf, grbufp->len); if (rv_grp == NULL) { if (errno == 0) { got_eof = 1; } else { got_err = 1; } } #elif HAVE_GETGRENT #ifdef WITH_PTHREADS if ((rv_mutex = pthread_mutex_lock (&mutex)) != 0) { errno = rv_mutex; log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to lock xgetgrent mutex"); } #endif /* WITH_PTHREADS */ rv_grp = getgrent (); if (rv_grp == NULL) { if ((errno == 0) || (errno == ENOENT)) { got_eof = 1; } else { got_err = 1; } rv_copy = 0; } else { rv_copy = _xgetgrbuf_copy_struct (rv_grp, grp, grbufp); } #ifdef WITH_PTHREADS if ((rv_mutex = pthread_mutex_unlock (&mutex)) != 0) { errno = rv_mutex; log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to unlock xgetgrent mutex"); } #endif /* WITH_PTHREADS */ if (rv_copy < 0) { return (-1); } #endif /* HAVE_GETGRENT */ if (got_eof) { errno = ENOENT; return (-1); } if (got_err) { if (errno == ERANGE) { rv = _xgetgrbuf_grow (grbufp, 0); #if ! HAVE_GETGRENT_R_ERANGE_BROKEN if (rv == 0) { goto restart; } #endif /* ! HAVE_GETGRENT_R_ERANGE_BROKEN */ } return (-1); } return (0); } void xgetgrent_fini (void) { /* Portable encapsulation of endgrent(). */ endgrent (); return; } int xgetgrnam (const char *name, struct group *grp, xgrbuf_p grbufp) { /* Portable encapsulation of getgrnam_r(). */ #if HAVE_GETGRNAM_R_POSIX struct group *rv_grp; #elif HAVE_GETGRNAM_R_SUN struct group *rv_grp; #elif HAVE_GETGRNAM #ifdef WITH_PTHREADS static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; int rv_mutex; #endif /* WITH_PTHREADS */ int rv_copy; struct group *rv_grp; #endif /* HAVE_GETGRNAM */ int rv; int got_err; int got_none; if ((name == NULL) || (name[0] == '\0') || (grp == NULL) || (grbufp == NULL)) { errno = EINVAL; return (-1); } assert (grbufp->buf != NULL); assert (grbufp->len > 0); restart: errno = 0; got_err = 0; got_none = 0; #if HAVE_GETGRNAM_R_POSIX rv_grp = NULL; rv = getgrnam_r (name, grp, grbufp->buf, grbufp->len, &rv_grp); /* * POSIX.1-2001 does not call "name not found" an error, so the return * value of getgrnam_r() is of limited value. When errors do occur, * some systems return them via the retval and some via errno. */ if (rv_grp == NULL) { /* * Coalesce the error number onto rv if needed. */ if ((rv <= 0) && (errno != 0)) { rv = errno; } /* Likely that the name was not found. */ if ((rv == 0) || (rv == ENOENT) || (rv == ESRCH)) { got_none = 1; } /* Likely that an error occurred. */ else if ( (rv == EINTR) || (rv == ERANGE) || (rv == EIO) || (rv == EMFILE) || (rv == ENFILE)) { got_err = 1; errno = rv; } /* Unable to distinguish "name not found" from error. */ else { got_none = 1; } } #elif HAVE_GETGRNAM_R_SUN rv_grp = getgrnam_r (name, grp, grbufp->buf, grbufp->len); if (rv_grp == NULL) { if (errno == 0) { got_none = 1; } else { got_err = 1; } } #elif HAVE_GETGRNAM #ifdef WITH_PTHREADS if ((rv_mutex = pthread_mutex_lock (&mutex)) != 0) { errno = rv_mutex; log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to lock xgetgrnam mutex"); } #endif /* WITH_PTHREADS */ rv_grp = getgrnam (name); /* * The initial test for (errno != 0), while redundant, allows for the * "name not found" case to short-circuit the rest of the if-condition * on many systems. */ if (rv_grp == NULL) { if ((errno != 0) && ((errno == EINTR) || (errno == ERANGE) || (errno == EIO) || (errno == EMFILE) || (errno == ENFILE) || (errno == ENOMEM))) { got_err = 1; } else { got_none = 1; } rv_copy = 0; } else { rv_copy = _xgetgrbuf_copy_struct (rv_grp, grp, grbufp); } #ifdef WITH_PTHREADS if ((rv_mutex = pthread_mutex_unlock (&mutex)) != 0) { errno = rv_mutex; log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to unlock xgetgrnam mutex"); } #endif /* WITH_PTHREADS */ if (rv_copy < 0) { return (-1); } #endif /* HAVE_GETGRNAM */ if (got_none) { errno = ENOENT; return (-1); } if (got_err) { if (errno == EINTR) { goto restart; } if (errno == ERANGE) { rv = _xgetgrbuf_grow (grbufp, 0); if (rv == 0) { goto restart; } } return (-1); } /* Some systems set errno even on success. Go figure. */ errno = 0; return (0); } /***************************************************************************** * Private Functions *****************************************************************************/ static size_t _xgetgrbuf_get_sys_size (void) { /* Returns the system recommended size for the xgetgr buffer. */ long n = -1; size_t len; #if HAVE_SYSCONF #ifdef _SC_GETGR_R_SIZE_MAX n = sysconf (_SC_GETGR_R_SIZE_MAX); #endif /* _SC_GETGR_R_SIZE_MAX */ #endif /* HAVE_SYSCONF */ len = (n <= MINIMUM_GR_BUF_SIZE) ? MINIMUM_GR_BUF_SIZE : (size_t) n; return (len); } static int _xgetgrbuf_grow (xgrbuf_p grbufp, size_t minlen) { /* Grows the buffer [grbufp] to be at least as large as the length [minlen]. * Returns 0 on success, or -1 on error (with errno). */ size_t newlen; char *newbuf; assert (grbufp != NULL); assert (grbufp->buf != NULL); assert (grbufp->len > 0); newlen = grbufp->len; do { newlen *= 2; if (newlen < grbufp->len) { /* newlen overflowed */ errno = ENOMEM; return (-1); } } while (newlen < minlen); newbuf = realloc (grbufp->buf, newlen); if (newbuf == NULL) { errno = ENOMEM; return (-1); } grbufp->buf = newbuf; grbufp->len = newlen; log_msg (LOG_INFO, "Increased group entry buffer size to %u", newlen); return (0); } static int _xgetgrbuf_copy_struct (const struct group *src, struct group *dst, xgrbuf_p grbufp) { /* Copies the struct group [src] into [dst], placing additional strings and * whatnot into the buffer [grbufp]. * Returns 0 on success, or -1 on error (with errno). */ int num_ptrs; size_t num_bytes; char **userp; char *p; size_t n; int i; assert (src != NULL); assert (dst != NULL); assert (grbufp != NULL); assert (grbufp->buf != NULL); assert (grbufp->len > 0); /* Compute requisite buffer space. */ num_ptrs = 1; /* +1 for gr_mem[] null termination */ num_bytes = 0; for (userp = src->gr_mem; userp && *userp; userp++) { num_ptrs++; num_bytes += strlen (*userp) + 1; } if (src->gr_name) { num_bytes += strlen (src->gr_name) + 1; } if (src->gr_passwd) { num_bytes += strlen (src->gr_passwd) + 1; } num_bytes += num_ptrs * (sizeof (char *)); /* Ensure requisite buffer space. */ if (grbufp->len < num_bytes) { if (_xgetgrbuf_grow (grbufp, num_bytes) < 0) { return (-1); } } /* Copy group entry. */ assert (grbufp->len >= num_bytes); memset (dst, 0, sizeof (*dst)); p = grbufp->buf; n = num_ptrs * (sizeof (char *)); if (num_bytes < n) { goto err; } dst->gr_mem = (char **) p; p += n; num_bytes -= n; if (_xgetgrbuf_copy_string (src->gr_name, &(dst->gr_name), &p, &num_bytes) < 0) { goto err; } if (_xgetgrbuf_copy_string (src->gr_passwd, &(dst->gr_passwd), &p, &num_bytes) < 0) { goto err; } for (i = 0; i < num_ptrs; i++) { if (_xgetgrbuf_copy_string (src->gr_mem [i], &(dst->gr_mem [i]), &p, &num_bytes) < 0) { goto err; } } dst->gr_gid = src->gr_gid; assert (p <= grbufp->buf + grbufp->len); return (0); err: errno = ERANGE; return (-1); } static int _xgetgrbuf_copy_string (const char *src, char **dstp, char **bufp, size_t *buflenp) { /* Copies the string [src] into the buffer [bufp] of size [buflenp], * setting the pointer [dstp] to the newly-copied string. The values * for [bufp] and [buflenp] are adjusted for the remaining buffer space. * Note that [dstp], [bufp], and [buflenp] are all passed by reference. * Returns the number of bytes copied, or -1 on error. */ size_t n; assert (dstp != NULL); assert (bufp != NULL); assert (*bufp != NULL); assert (buflenp != NULL); if (src == NULL) { *dstp = NULL; return (0); } n = strlen (src) + 1; if (*buflenp < n) { return (-1); } *dstp = strcpy (*bufp, src); *bufp += n; *buflenp -= n; return (n); } munge-munge-0.5.15/src/common/xgetgr.h000066400000000000000000000043561425467526100176020ustar00rootroot00000000000000/***************************************************************************** * Written by Chris Dunlap . * Copyright (C) 2007-2022 Lawrence Livermore National Security, LLC. * Copyright (C) 2002-2007 The Regents of the University of California. * UCRL-CODE-155910. * * This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE). * For details, see . * * MUNGE 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. Additionally for the MUNGE library (libmunge), you * can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation, * either version 3 of the License, or (at your option) any later version. * * MUNGE 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 * and GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * and GNU Lesser General Public License along with MUNGE. If not, see * . *****************************************************************************/ #ifndef XGETGR_H #define XGETGR_H #include #include /***************************************************************************** * Data Types *****************************************************************************/ typedef struct xgrbuf_t * xgrbuf_p; /***************************************************************************** * Functions *****************************************************************************/ xgrbuf_p xgetgrbuf_create (size_t len); void xgetgrbuf_destroy (xgrbuf_p grbufp); size_t xgetgrbuf_get_len (xgrbuf_p grbufp); void xgetgrent_init (void); int xgetgrent (struct group *grp, xgrbuf_p grbufp); void xgetgrent_fini (void); int xgetgrnam (const char *name, struct group *grp, xgrbuf_p grbufp); #endif /* !XGETGR_H */ munge-munge-0.5.15/src/common/xgetpw.c000066400000000000000000000323151425467526100176070ustar00rootroot00000000000000/***************************************************************************** * Written by Chris Dunlap . * Copyright (C) 2007-2022 Lawrence Livermore National Security, LLC. * Copyright (C) 2002-2007 The Regents of the University of California. * UCRL-CODE-155910. * * This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE). * For details, see . * * MUNGE 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. Additionally for the MUNGE library (libmunge), you * can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation, * either version 3 of the License, or (at your option) any later version. * * MUNGE 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 * and GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * and GNU Lesser General Public License along with MUNGE. If not, see * . *****************************************************************************/ #if HAVE_CONFIG_H # include "config.h" #endif /* HAVE_CONFIG_H */ #if HAVE_GETPWNAM_R_POSIX #define _POSIX_PTHREAD_SEMANTICS 1 /* for SunOS */ #elif HAVE_GETPWNAM_R_AIX #define _THREAD_SAFE 1 #define _UNIX95 1 #define _XOPEN_SOURCE_EXTENDED 1 #elif HAVE_GETPWNAM_R_SUN #undef _POSIX_PTHREAD_SEMANTICS #elif HAVE_GETPWNAM #ifdef WITH_PTHREADS #include #endif /* WITH_PTHREADS */ #else #error "getpwnam() not supported" #endif #include #include #include #include #include #include #include #include #include #include "log.h" #include "xgetpw.h" /***************************************************************************** * Compiler Fu *****************************************************************************/ #ifdef __GNUC__ #define _UNUSED_ __attribute__ ((unused)) #else #define _UNUSED_ #endif /***************************************************************************** * Constants *****************************************************************************/ #define MINIMUM_PW_BUF_SIZE 1024 /***************************************************************************** * Data Types *****************************************************************************/ struct xpwbuf_t { char *buf; size_t len; }; /***************************************************************************** * Private Prototypes *****************************************************************************/ static size_t _xgetpwbuf_get_sys_size (void); static int _xgetpwbuf_grow (xpwbuf_p pwbufp, size_t minlen); static int _xgetpwbuf_copy_struct (const struct passwd *src, struct passwd *dst, xpwbuf_p pwbufp) _UNUSED_; static int _xgetpwbuf_copy_string (const char *src, char **dstp, char **bufp, size_t *buflenp) _UNUSED_; /***************************************************************************** * Public Functions *****************************************************************************/ xpwbuf_p xgetpwbuf_create (size_t len) { /* Allocates a buffer for xgetpwnam(). [len] specifies a suggested size * for the buffer; if 0, the system recommended size will be used. * Returns the buffer on success, or NULL on error (with errno). */ xpwbuf_p pwbufp; if (len == 0) { len = _xgetpwbuf_get_sys_size (); } pwbufp = malloc (sizeof (struct xpwbuf_t)); if (pwbufp == NULL) { return (NULL); } pwbufp->buf = malloc (len); if (pwbufp->buf == NULL) { free (pwbufp); return (NULL); } pwbufp->len = len; log_msg (LOG_DEBUG, "Created password entry buffer of size %u", len); return (pwbufp); } void xgetpwbuf_destroy (xpwbuf_p pwbufp) { /* Destroys the buffer [pwbufp]. */ if (pwbufp != NULL) { if (pwbufp->buf != NULL) { free (pwbufp->buf); } free (pwbufp); } return; } size_t xgetpwbuf_get_len (xpwbuf_p pwbufp) { /* Returns the current size of the allocated buffer within [pwbufp], * or 0 on error (with errno). */ if (pwbufp == NULL) { errno = EINVAL; return (0); } return (pwbufp->len); } int xgetpwnam (const char *name, struct passwd *pwp, xpwbuf_p pwbufp) { /* Portable encapsulation of getpwnam_r(). * Queries the password database for [name], storing the struct passwd result * in [pwp] and additional strings in the buffer [pwbufp]. * Returns 0 on success, or -1 on error (with errno). * Returns -1 with ENOENT when [name] is not found. */ #if HAVE_GETPWNAM_R_POSIX struct passwd *rv_pwp; #elif HAVE_GETPWNAM_R_AIX #elif HAVE_GETPWNAM_R_SUN struct passwd *rv_pwp; #elif HAVE_GETPWNAM #ifdef WITH_PTHREADS static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; int rv_mutex; #endif /* WITH_PTHREADS */ int rv_copy; struct passwd *rv_pwp; #endif /* HAVE_GETPWNAM */ int rv; int got_err; int got_none; if ((name == NULL) || (name[0] == '\0') || (pwp == NULL) || (pwbufp == NULL)) { errno = EINVAL; return (-1); } assert (pwbufp->buf != NULL); assert (pwbufp->len > 0); restart: errno = 0; got_err = 0; got_none = 0; #if HAVE_GETPWNAM_R_POSIX rv_pwp = NULL; rv = getpwnam_r (name, pwp, pwbufp->buf, pwbufp->len, &rv_pwp); /* * POSIX.1-2001 does not call "name not found" an error, so the return * value of getpwnam_r() is of limited value. When errors do occur, * some systems return them via the retval, some via errno, and some * return no indication whatsoever. */ if (rv_pwp == NULL) { /* * Coalesce the error number onto rv if needed. */ if ((rv < 0) && (errno != 0)) { rv = errno; } /* Likely that the name was not found. */ if ((rv == 0) || (rv == ENOENT) || (rv == ESRCH)) { got_none = 1; } /* Likely that an error occurred. */ else if ( (rv == EINTR) || (rv == ERANGE) || (rv == EIO) || (rv == EMFILE) || (rv == ENFILE)) { got_err = 1; errno = rv; } /* Unable to distinguish "name not found" from error. */ else { got_none = 1; } } #elif HAVE_GETPWNAM_R_AIX rv = getpwnam_r (name, pwp, pwbufp->buf, pwbufp->len); if (rv != 0) { if (errno == ESRCH) { got_none = 1; } else { got_err = 1; } } #elif HAVE_GETPWNAM_R_SUN rv_pwp = getpwnam_r (name, pwp, pwbufp->buf, pwbufp->len); if (rv_pwp == NULL) { if (errno == 0) { got_none = 1; } else { got_err = 1; } } #elif HAVE_GETPWNAM #ifdef WITH_PTHREADS if ((rv_mutex = pthread_mutex_lock (&mutex)) != 0) { errno = rv_mutex; log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to lock xgetpwnam mutex"); } #endif /* WITH_PTHREADS */ rv_pwp = getpwnam (name); /* * The initial test for (errno != 0), while redundant, allows for the * "name not found" case to short-circuit the rest of the if-condition * on many systems. */ if (rv_pwp == NULL) { if ((errno != 0) && ((errno == EINTR) || (errno == ERANGE) || (errno == EIO) || (errno == EMFILE) || (errno == ENFILE) || (errno == ENOMEM))) { got_err = 1; } else { got_none = 1; } rv_copy = 0; } else { rv_copy = _xgetpwbuf_copy_struct (rv_pwp, pwp, pwbufp); } #ifdef WITH_PTHREADS if ((rv_mutex = pthread_mutex_unlock (&mutex)) != 0) { errno = rv_mutex; log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to unlock xgetpwnam mutex"); } #endif /* WITH_PTHREADS */ if (rv_copy < 0) { return (-1); } #endif /* HAVE_GETPWNAM */ if (got_none) { errno = ENOENT; return (-1); } if (got_err) { if (errno == EINTR) { goto restart; } if (errno == ERANGE) { rv = _xgetpwbuf_grow (pwbufp, 0); if (rv == 0) { goto restart; } } return (-1); } /* Some systems set errno even on success. Go figure. */ errno = 0; return (0); } /***************************************************************************** * Private Functions *****************************************************************************/ static size_t _xgetpwbuf_get_sys_size (void) { /* Returns the system recommended size for the xgetpw buffer. */ long n = -1; size_t len; #if HAVE_SYSCONF #ifdef _SC_GETPW_R_SIZE_MAX n = sysconf (_SC_GETPW_R_SIZE_MAX); #endif /* _SC_GETPW_R_SIZE_MAX */ #endif /* HAVE_SYSCONF */ len = (n <= MINIMUM_PW_BUF_SIZE) ? MINIMUM_PW_BUF_SIZE : (size_t) n; return (len); } static int _xgetpwbuf_grow (xpwbuf_p pwbufp, size_t minlen) { /* Grows the buffer [pwbufp] to be at least as large as the length [minlen]. * Returns 0 on success, or -1 on error (with errno). */ size_t newlen; char *newbuf; assert (pwbufp != NULL); assert (pwbufp->buf != NULL); assert (pwbufp->len > 0); newlen = pwbufp->len; do { newlen *= 2; if (newlen < pwbufp->len) { /* newlen overflowed */ errno = ENOMEM; return (-1); } } while (newlen < minlen); newbuf = realloc (pwbufp->buf, newlen); if (newbuf == NULL) { errno = ENOMEM; return (-1); } pwbufp->buf = newbuf; pwbufp->len = newlen; log_msg (LOG_INFO, "Increased password entry buffer size to %u", newlen); return (0); } static int _xgetpwbuf_copy_struct (const struct passwd *src, struct passwd *dst, xpwbuf_p pwbufp) { /* Copies the struct passwd [src] into [dst], placing additional strings * and whatnot into buffer [pwbuf]. * Returns 0 on success, or -1 on error (with errno). */ size_t num_bytes; char *p; assert (src != NULL); assert (dst != NULL); assert (pwbufp != NULL); assert (pwbufp->buf != NULL); assert (pwbufp->len > 0); /* Compute requisite buffer space. */ num_bytes = 0; if (src->pw_name) { num_bytes += strlen (src->pw_name) + 1; } if (src->pw_passwd) { num_bytes += strlen (src->pw_passwd) + 1; } if (src->pw_gecos) { num_bytes += strlen (src->pw_gecos) + 1; } if (src->pw_dir) { num_bytes += strlen (src->pw_dir) + 1; } if (src->pw_shell) { num_bytes += strlen (src->pw_shell) + 1; } /* Ensure requisite buffer space. */ if (pwbufp->len < num_bytes) { if (_xgetpwbuf_grow (pwbufp, num_bytes) < 0) { return (-1); } } /* Copy password entry. */ assert (pwbufp->len >= num_bytes); memset (dst, 0, sizeof (*dst)); p = pwbufp->buf; if (_xgetpwbuf_copy_string (src->pw_name, &(dst->pw_name), &p, &num_bytes) < 0) { goto err; } if (_xgetpwbuf_copy_string (src->pw_passwd, &(dst->pw_passwd), &p, &num_bytes) < 0) { goto err; } if (_xgetpwbuf_copy_string (src->pw_gecos, &(dst->pw_gecos), &p, &num_bytes) < 0) { goto err; } if (_xgetpwbuf_copy_string (src->pw_dir, &(dst->pw_dir), &p, &num_bytes) < 0) { goto err; } if (_xgetpwbuf_copy_string (src->pw_shell, &(dst->pw_shell), &p, &num_bytes) < 0) { goto err; } dst->pw_uid = src->pw_uid; dst->pw_gid = src->pw_gid; assert (p <= pwbufp->buf + pwbufp->len); return (0); err: errno = ERANGE; return (-1); } static int _xgetpwbuf_copy_string (const char *src, char **dstp, char **bufp, size_t *buflenp) { /* Copies the string [src] into the buffer [bufp] of size [buflenp], * setting the pointer [dstp] to the newly-copied string. The values * for [bufp] and [buflenp] are adjusted for the remaining buffer space. * Note that [dstp], [bufp], and [buflenp] are all passed by reference. * Returns the number of bytes copied, or -1 on error. */ size_t n; assert (dstp != NULL); assert (bufp != NULL); assert (*bufp != NULL); assert (buflenp != NULL); if (src == NULL) { *dstp = NULL; return (0); } n = strlen (src) + 1; if (*buflenp < n) { return (-1); } *dstp = strcpy (*bufp, src); *bufp += n; *buflenp -= n; return (n); } munge-munge-0.5.15/src/common/xgetpw.h000066400000000000000000000042001425467526100176040ustar00rootroot00000000000000/***************************************************************************** * Written by Chris Dunlap . * Copyright (C) 2007-2022 Lawrence Livermore National Security, LLC. * Copyright (C) 2002-2007 The Regents of the University of California. * UCRL-CODE-155910. * * This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE). * For details, see . * * MUNGE 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. Additionally for the MUNGE library (libmunge), you * can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation, * either version 3 of the License, or (at your option) any later version. * * MUNGE 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 * and GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * and GNU Lesser General Public License along with MUNGE. If not, see * . *****************************************************************************/ #ifndef XGETPW_H #define XGETPW_H #include #include /***************************************************************************** * Data Types *****************************************************************************/ typedef struct xpwbuf_t * xpwbuf_p; /***************************************************************************** * Functions *****************************************************************************/ xpwbuf_p xgetpwbuf_create (size_t len); void xgetpwbuf_destroy (xpwbuf_p pwbufp); size_t xgetpwbuf_get_len (xpwbuf_p pwbufp); int xgetpwnam (const char *name, struct passwd *pwp, xpwbuf_p pwbufp); #endif /* !XGETPW_H */ munge-munge-0.5.15/src/common/xsignal.c000066400000000000000000000041421425467526100177330ustar00rootroot00000000000000/***************************************************************************** * Written by Chris Dunlap . * Copyright (C) 2007-2022 Lawrence Livermore National Security, LLC. * Copyright (C) 2002-2007 The Regents of the University of California. * UCRL-CODE-155910. * * This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE). * For details, see . * * MUNGE 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. Additionally for the MUNGE library (libmunge), you * can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation, * either version 3 of the License, or (at your option) any later version. * * MUNGE 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 * and GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * and GNU Lesser General Public License along with MUNGE. If not, see * . *****************************************************************************/ #if HAVE_CONFIG_H # include "config.h" #endif /* HAVE_CONFIG_H */ #include #include #include #include "log.h" #include "xsignal.h" void xsignal_ignore (int sig) { struct sigaction sa; int rv; sa.sa_handler = SIG_IGN; sa.sa_flags = 0; rv = sigfillset (&sa.sa_mask); if (rv == -1) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to initialize signal set to full"); } rv = sigaction (sig, &sa, NULL); if (rv == -1) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to ignore signal %d (%s)", sig, strsignal (sig)); } return; } munge-munge-0.5.15/src/common/xsignal.h000066400000000000000000000031421425467526100177370ustar00rootroot00000000000000/***************************************************************************** * Written by Chris Dunlap . * Copyright (C) 2007-2022 Lawrence Livermore National Security, LLC. * Copyright (C) 2002-2007 The Regents of the University of California. * UCRL-CODE-155910. * * This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE). * For details, see . * * MUNGE 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. Additionally for the MUNGE library (libmunge), you * can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation, * either version 3 of the License, or (at your option) any later version. * * MUNGE 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 * and GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * and GNU Lesser General Public License along with MUNGE. If not, see * . *****************************************************************************/ #ifndef XSIGNAL_H #define XSIGNAL_H void xsignal_ignore (int sig); /* * Ignore the signal specified by [sig]. */ #endif /* !XSIGNAL_H */ munge-munge-0.5.15/src/etc/000077500000000000000000000000001425467526100154045ustar00rootroot00000000000000munge-munge-0.5.15/src/etc/Makefile.am000066400000000000000000000134161425467526100174450ustar00rootroot00000000000000# MUNGE src/etc/Makefile.am # # This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE). # For details, see . include $(top_srcdir)/Make-inc.mk TEMPLATE_FILES = \ munge.logrotate.conf.in \ munge.pkgconfig.pc.in \ munge.systemd.service.in \ munge.systemd.sysconfig.in \ munge.sysvinit.init.in \ munge.sysvinit.sysconfig.in \ munge.tmpfiles.conf.in \ # End of TEMPLATE_FILES SUBSTITUTE_FILES = \ munge.logrotate.conf \ munge.pkgconfig.pc \ munge.systemd.service \ munge.systemd.sysconfig \ munge.sysvinit.init \ munge.sysvinit.sysconfig \ munge.tmpfiles.conf \ # End of SUBSTITUTE_FILES EXTRA_DIST = \ $(TEMPLATE_FILES) \ # End of EXTRA_DIST CLEANFILES = \ $(SUBSTITUTE_FILES) \ # End of CLEANFILES $(SUBSTITUTE_FILES): Makefile $(AM_V_GEN)$(substitute) < '$(srcdir)/$@.in' > '$(builddir)/$@' munge.logrotate.conf: munge.logrotate.conf.in munge.pkgconfig.pc: munge.pkgconfig.pc.in munge.systemd.service: munge.systemd.service.in munge.systemd.sysconfig: munge.systemd.sysconfig.in munge.sysvinit.init: munge.sysvinit.init.in munge.sysvinit.sysconfig: munge.sysvinit.sysconfig.in munge.tmpfiles.conf: munge.tmpfiles.conf.in noinst_DATA = \ $(SUBSTITUTE_FILES) \ # End of noinst_DATA install-data-hook: install-dirs install-logrotate install-pkgconfig install-systemd install-sysvinit uninstall-local: uninstall-dirs uninstall-logrotate uninstall-pkgconfig uninstall-systemd uninstall-sysvinit install-dirs: $(MKDIR_P) -m 0700 '$(DESTDIR)$(sysconfdir)/munge' $(MKDIR_P) -m 0711 '$(DESTDIR)$(localstatedir)/lib/munge' $(MKDIR_P) -m 0700 '$(DESTDIR)$(localstatedir)/log/munge' uninstall-dirs: rmdir '$(DESTDIR)$(sysconfdir)/munge' 2>/dev/null || : rmdir '$(DESTDIR)$(localstatedir)/lib/munge' 2>/dev/null || : rmdir '$(DESTDIR)$(localstatedir)/log/munge' 2>/dev/null || : rmdir '$(DESTDIR)$(runstatedir)/munge' 2>/dev/null || : install-logrotate: munge.logrotate.conf @if test 'x$(logrotateddir)' != x; then \ echo $(MKDIR_P) "'$(DESTDIR)$(logrotateddir)'"; \ $(MKDIR_P) '$(DESTDIR)$(logrotateddir)'; \ echo $(INSTALL_DATA) "'$(builddir)/munge.logrotate.conf'" \ "'$(DESTDIR)$(logrotateddir)/$(PACKAGE)'"; \ $(INSTALL_DATA) '$(builddir)/munge.logrotate.conf' \ '$(DESTDIR)$(logrotateddir)/$(PACKAGE)'; \ fi uninstall-logrotate: @if test 'x$(logrotateddir)' != x; then \ echo rm -f "'$(DESTDIR)$(logrotateddir)/$(PACKAGE)'"; \ rm -f '$(DESTDIR)$(logrotateddir)/$(PACKAGE)'; \ fi install-pkgconfig: munge.pkgconfig.pc @if test 'x$(pkgconfigdir)' != x; then \ echo $(MKDIR_P) "'$(DESTDIR)$(pkgconfigdir)'"; \ $(MKDIR_P) '$(DESTDIR)$(pkgconfigdir)'; \ echo $(INSTALL_DATA) "'$(builddir)/munge.pkgconfig.pc'" \ "'$(DESTDIR)$(pkgconfigdir)/$(PACKAGE).pc'"; \ $(INSTALL_DATA) '$(builddir)/munge.pkgconfig.pc' \ '$(DESTDIR)$(pkgconfigdir)/$(PACKAGE).pc'; \ fi uninstall-pkgconfig: @if test 'x$(pkgconfigdir)' != x; then \ echo rm -f "'$(DESTDIR)$(pkgconfigdir)/$(PACKAGE).pc'"; \ rm -f '$(DESTDIR)$(pkgconfigdir)/$(PACKAGE).pc'; \ fi install-systemd: munge.systemd.service install-systemd-sysconfig @if test 'x$(systemdunitdir)' != x; then \ echo $(MKDIR_P) "'$(DESTDIR)$(systemdunitdir)'"; \ $(MKDIR_P) '$(DESTDIR)$(systemdunitdir)'; \ echo $(INSTALL_DATA) "'$(builddir)/munge.systemd.service'" \ "'$(DESTDIR)$(systemdunitdir)/$(PACKAGE).service'"; \ $(INSTALL_DATA) '$(builddir)/munge.systemd.service' \ '$(DESTDIR)$(systemdunitdir)/$(PACKAGE).service'; \ else \ echo $(MKDIR_P) -m 0755 "'$(DESTDIR)$(runstatedir)/munge'"; \ $(MKDIR_P) -m 0755 '$(DESTDIR)$(runstatedir)/munge'; \ fi uninstall-systemd: uninstall-systemd-sysconfig @if test 'x$(systemdunitdir)' != x; then \ echo rm -f "'$(DESTDIR)$(systemdunitdir)/$(PACKAGE).service'"; \ rm -f '$(DESTDIR)$(systemdunitdir)/$(PACKAGE).service'; \ fi install-systemd-sysconfig: munge.systemd.sysconfig @if test 'x$(systemdunitdir)' != x \ && test 'x$(sysconfigdir)' != x; then \ echo $(MKDIR_P) "'$(DESTDIR)$(sysconfigdir)'"; \ $(MKDIR_P) '$(DESTDIR)$(sysconfigdir)'; \ echo $(INSTALL_DATA) "'$(builddir)/munge.systemd.sysconfig'" \ "'$(DESTDIR)$(sysconfigdir)/$(PACKAGE)'"; \ $(INSTALL_DATA) '$(builddir)/munge.systemd.sysconfig' \ '$(DESTDIR)$(sysconfigdir)/$(PACKAGE)'; \ fi uninstall-systemd-sysconfig: @if test 'x$(systemdunitdir)' != x \ && test 'x$(sysconfigdir)' != x; then \ echo rm -f "'$(DESTDIR)$(sysconfigdir)/$(PACKAGE)'"; \ rm -f '$(DESTDIR)$(sysconfigdir)/$(PACKAGE)'; \ fi install-sysvinit: munge.sysvinit.init install-sysvinit-sysconfig @if test 'x$(sysvinitddir)' != x; then \ echo $(MKDIR_P) "'$(DESTDIR)$(sysvinitddir)'"; \ $(MKDIR_P) '$(DESTDIR)$(sysvinitddir)'; \ echo $(INSTALL_SCRIPT) "'$(builddir)/munge.sysvinit.init'" \ "'$(DESTDIR)$(sysvinitddir)/$(PACKAGE)'"; \ $(INSTALL_SCRIPT) '$(builddir)/munge.sysvinit.init' \ '$(DESTDIR)$(sysvinitddir)/$(PACKAGE)'; \ fi uninstall-sysvinit: uninstall-sysvinit-sysconfig @if test 'x$(sysvinitddir)' != x; then \ echo rm -f "'$(DESTDIR)$(sysvinitddir)/$(PACKAGE)'"; \ rm -f '$(DESTDIR)$(sysvinitddir)/$(PACKAGE)'; \ fi install-sysvinit-sysconfig: munge.sysvinit.sysconfig @if test 'x$(sysvinitddir)' != x \ && test 'x$(sysconfigdir)' != x; then \ echo $(MKDIR_P) "'$(DESTDIR)$(sysconfigdir)'"; \ $(MKDIR_P) '$(DESTDIR)$(sysconfigdir)'; \ echo $(INSTALL_DATA) "'$(builddir)/munge.sysvinit.sysconfig'" \ "'$(DESTDIR)$(sysconfigdir)/$(PACKAGE)'"; \ $(INSTALL_DATA) '$(builddir)/munge.sysvinit.sysconfig' \ '$(DESTDIR)$(sysconfigdir)/$(PACKAGE)'; \ fi uninstall-sysvinit-sysconfig: @if test 'x$(sysvinitddir)' != x \ && test 'x$(sysconfigdir)' != x; then \ echo rm -f "'$(DESTDIR)$(sysconfigdir)/$(PACKAGE)'"; \ rm -f '$(DESTDIR)$(sysconfigdir)/$(PACKAGE)'; \ fi munge-munge-0.5.15/src/etc/munge.logrotate.conf.in000066400000000000000000000002041425467526100217660ustar00rootroot00000000000000@localstatedir@/log/munge/munged.log { rotate 1 size 100k copytruncate compress nodelaycompress missingok } munge-munge-0.5.15/src/etc/munge.pkgconfig.pc.in000066400000000000000000000003701425467526100214160ustar00rootroot00000000000000prefix=@prefix@ exec_prefix=@exec_prefix@ includedir=@includedir@ libdir=@libdir@ Name: MUNGE Description: MUNGE authentication service library URL: https://dun.github.io/munge/ Version: @VERSION@ Cflags: -I${includedir} Libs: -L${libdir} -lmunge munge-munge-0.5.15/src/etc/munge.systemd.service.in000066400000000000000000000006431425467526100222000ustar00rootroot00000000000000[Unit] Description=MUNGE authentication service Documentation=man:munged(8) Wants=network-online.target After=network-online.target After=time-sync.target [Service] Type=forking EnvironmentFile=-@sysconfigdir@/munge ExecStart=@sbindir@/munged $OPTIONS PIDFile=@runstatedir@/munge/munged.pid RuntimeDirectory=munge RuntimeDirectoryMode=0755 User=munge Group=munge Restart=on-abort [Install] WantedBy=multi-user.target munge-munge-0.5.15/src/etc/munge.systemd.sysconfig.in000066400000000000000000000002151425467526100225370ustar00rootroot00000000000000# MUNGE configuration # Pass additional command-line options to munged. # OPTIONS="--key-file=@sysconfdir@/munge/munge.key --num-threads=2" munge-munge-0.5.15/src/etc/munge.sysvinit.init.in000066400000000000000000000347661425467526100217200ustar00rootroot00000000000000#!/bin/sh ############################################################################### # Written by Chris Dunlap . # Copyright (C) 2007-2022 Lawrence Livermore National Security, LLC. # Copyright (C) 2002-2007 The Regents of the University of California. # UCRL-CODE-155910. ############################################################################### # chkconfig: - 66 33 # description: MUNGE Uid 'N' Gid Emporium authentication service ############################################################################### ### BEGIN INIT INFO # Provides: munge # Required-Start: $local_fs $remote_fs $network $time # Required-Stop: $local_fs $remote_fs # Should-Start: $named $syslog # Should-Stop: $named $syslog # Default-Start: # Default-Stop: # Short-Description: MUNGE Uid 'N' Gid Emporium authentication service # Description: MUNGE (MUNGE Uid 'N' Gid Emporium) is a highly scalable # authentication service for creating and validating # credentials. ### END INIT INFO ############################################################################### unset SERVICE_NAME DAEMON_EXEC DAEMON_ARGS CONFIG PIDFILE NICE USER GROUP \ SIGHUP_RELOAD VARRUNDIR prefix="@prefix@" exec_prefix="@exec_prefix@" sbindir="@sbindir@" sysconfdir="@sysconfdir@" runstatedir="@runstatedir@" SERVICE_NAME="MUNGE" DAEMON_EXEC="$sbindir/munged" #DAEMON_ARGS= #CONFIG=#_NOT_SUPPORTED_# PIDFILE="$runstatedir/munge/munged.pid" #NICE= USER="munge" GROUP="munge" #SIGHUP_RELOAD=#_NOT_SUPPORTED_# VARRUNDIR="$runstatedir/munge" ############################################################################### service_init () { # Determine the system type and initialize the environment. # # Note that the shell positional parameters must be preserved when calling # this function in order for SuSE to initialize its environment properly. ## PATH=/sbin:/usr/sbin:/bin:/usr/bin INIT_NAME="`basename \"$0\" .init | sed 's/^[SK][0-9][0-9]*//'`" DAEMON_NAME="`basename \"$DAEMON_EXEC\"`" SIGTERM_TIMEOUT="3" STATUS=0 # Read configuration defaults to override variables: # $CONFIG, $DAEMON_ARGS, $PIDFILE, $USER, $NICE, $SIGHUP_RELOAD ## for dir in "$sysconfdir/default" "$sysconfdir/sysconfig"; do [ -r "$dir/$INIT_NAME" ] && . "$dir/$INIT_NAME" done [ -z "$DAEMON_ARGS" -a -n "$OPTIONS" ] && DAEMON_ARGS="$OPTIONS" [ "`id | sed 's/^uid=\([0-9]*\).*/\1/'`" -ne 0 ] && unset USER expr -- "$NICE" : '[0-9]*$' >/dev/null 2>&1 && NICE="+$NICE" [ -n "$SIGHUP_RELOAD" -a "$SIGHUP_RELOAD" != 0 ] \ && RELOAD=1 || unset RELOAD if [ -f /etc/debian_version -a -x /sbin/start-stop-daemon ]; then SYSTEM="DEBIAN" [ -x "$DAEMON_EXEC" ] || exit 0 # pkg removed but not purged [ -r /etc/default/rcS ] && . /etc/default/rcS [ -r /lib/init/vars.sh ] && . /lib/init/vars.sh [ -r /lib/lsb/init-functions ] && . /lib/lsb/init-functions elif [ -f /etc/redhat-release -a -r /etc/rc.d/init.d/functions ]; then SYSTEM="REDHAT" . /etc/rc.d/init.d/functions RH_LOCK="/var/lock/subsys/$INIT_NAME" elif [ -f /etc/SuSE-release -a -r /etc/rc.status ]; then SYSTEM="SUSE" . /etc/rc.status rc_reset elif [ -r /lib/lsb/init-functions ]; then SYSTEM="LSB" . /lib/lsb/init-functions else SYSTEM="OTHER" fi # Exit if the package has been removed. ## [ -x "$DAEMON_EXEC" ] || exit 5 # LSB: program not installed # Exit if the configuration has been removed. ## [ -z "$CONFIG" -o -r "$CONFIG" ] || exit 6 # LSB: program not configured } service_fini () { # Return the exit status. ## case $SYSTEM in SUSE) rc_exit ;; DEBIAN|REDHAT|LSB|*) exit $STATUS ;; esac } service_start () { # Start the service. # # Required by LSB, where running "start" on a service already running should be # considered successful. ## log_init "Starting $SERVICE_NAME" "$DAEMON_NAME" if [ -n "$VARRUNDIR" -a ! -d "$VARRUNDIR" ]; then mkdir -m 755 -p "$VARRUNDIR" [ -n "$USER" ] && chown "$USER" "$VARRUNDIR" [ -n "$GROUP" ] && chgrp "$GROUP" "$VARRUNDIR" fi case $SYSTEM in DEBIAN) if $0 status >/dev/null 2>&1; then STATUS=0 else ERRMSG=`start-stop-daemon --start --quiet \ ${NICE:+"--nicelevel"} ${NICE:+"$NICE"} \ ${USER:+"--chuid"} ${USER:+"$USER"} \ ${PIDFILE:+"--pidfile"} ${PIDFILE:+"$PIDFILE"} \ --exec "$DAEMON_EXEC" -- $DAEMON_ARGS 2>&1` STATUS=$? fi ;; REDHAT) if $0 status >/dev/null 2>&1; then STATUS=0 else daemon ${NICE:+"$NICE"} ${USER:+"--user"} ${USER:+"$USER"} \ "$DAEMON_EXEC" $DAEMON_ARGS STATUS=$? fi [ $STATUS -eq 0 ] && touch "$RH_LOCK" >/dev/null 2>&1 ;; SUSE) ERRMSG=`startproc ${NICE:+"-n"} ${NICE:+"$NICE"} \ ${USER:+"-u"} ${USER:+"$USER"} \ ${PIDFILE:+"-p"} ${PIDFILE:+"$PIDFILE"} \ "$DAEMON_EXEC" $DAEMON_ARGS 2>&1` rc_status -v STATUS=$? ;; LSB) if [ -n "$USER" ]; then ERRMSG=`su "$USER" -c "/sbin/start_daemon \ ${NICE:+\"-n\"} ${NICE:+\"$NICE\"} \ ${PIDFILE:+\"-p\"} ${PIDFILE:+\"$PIDFILE\"} \ \"$DAEMON_EXEC\" $DAEMON_ARGS" 2>&1` else ERRMSG=`start_daemon ${NICE:+"-n"} ${NICE:+"$NICE"} \ ${PIDFILE:+"-p"} ${PIDFILE:+"$PIDFILE"} \ "$DAEMON_EXEC" $DAEMON_ARGS 2>&1` fi STATUS=$? ;; *) if $0 status >/dev/null 2>&1; then STATUS=0 else [ -n "$NICE" ] && nice="nice -n $NICE" if [ -n "$USER" ]; then ERRMSG=`su "$USER" -c "$nice \"$DAEMON_EXEC\" $DAEMON_ARGS" 2>&1` else ERRMSG=`$nice "$DAEMON_EXEC" $DAEMON_ARGS 2>&1` fi STATUS=$? fi ;; esac log_fini "$STATUS" "$ERRMSG" } service_stop () { # Stop the service. # # Required by LSB, where running "stop" on a service already stopped or not # running should be considered successful. ## log_init "Stopping $SERVICE_NAME" "$DAEMON_NAME" case $SYSTEM in DEBIAN) if ! $0 status >/dev/null 2>&1; then STATUS=0 else start-stop-daemon --stop --quiet \ ${PIDFILE:+"--pidfile"} ${PIDFILE:+"$PIDFILE"} \ --name "$DAEMON_NAME" ${SIGTERM_TIMEOUT:+"--retry"} \ ${SIGTERM_TIMEOUT:+"$SIGTERM_TIMEOUT"} >/dev/null 2>&1 STATUS=$? fi ;; REDHAT) if ! $0 status >/dev/null 2>&1; then STATUS=0 else killproc ${PIDFILE:+"-p"} ${PIDFILE:+"$PIDFILE"} \ ${SIGTERM_TIMEOUT:+"-d"} ${SIGTERM_TIMEOUT:+"$SIGTERM_TIMEOUT"} \ "$DAEMON_EXEC" STATUS=$? fi [ $STATUS -eq 0 ] && rm -f "$RH_LOCK" >/dev/null 2>&1 ;; SUSE) killproc ${PIDFILE:+"-p"} ${PIDFILE:+"$PIDFILE"} \ ${SIGTERM_TIMEOUT:+"-t"} ${SIGTERM_TIMEOUT:+"$SIGTERM_TIMEOUT"} \ "$DAEMON_EXEC" rc_status -v ;; LSB) killproc ${PIDFILE:+"-p"} ${PIDFILE:+"$PIDFILE"} "$DAEMON_EXEC" STATUS=$? ;; *) signal_process "$DAEMON_EXEC" rc=$? [ $rc -eq 0 -o $rc -eq 2 ] && STATUS=0 || STATUS=1 ;; esac log_fini "$STATUS" [ -f "$PIDFILE" ] && rm -f "$PIDFILE" } service_restart () { # Stop and restart the service if it is already running; # otherwise, start the service. # # Required by LSB, where running "restart" on a service already stopped or not # running should be considered successful. ## if $0 status >/dev/null 2>&1; then $0 stop && $0 start else $0 start fi case $SYSTEM in SUSE) rc_status ;; DEBIAN|REDHAT|LSB|*) STATUS=$? ;; esac } service_try_restart () { # Restart the service if it is already running. # # Optional for LSB, where running "try-restart" on a service already stopped or # not running should be considered successful. # Also known as "condrestart" by RedHat. ## case $SYSTEM in REDHAT) [ -f "$RH_LOCK" ] && $0 restart || : STATUS=$? ;; SUSE) $0 status >/dev/null 2>&1 && $0 restart || rc_reset rc_status ;; DEBIAN|LSB|*) $0 status >/dev/null 2>&1 && $0 restart || : STATUS=$? ;; esac } service_reload () { # Reload the configuration without stopping and restarting the service. # # Optional for LSB. ## [ -z "$RELOAD" ] && STATUS=3 # LSB: unimplemented feature log_init "Reloading $SERVICE_NAME" "$DAEMON_NAME" case $SYSTEM in DEBIAN) if [ -n "$RELOAD" ]; then start-stop-daemon --stop --quiet --signal HUP \ ${PIDFILE:+"--pidfile"} ${PIDFILE:+"$PIDFILE"} \ --name "$DAEMON_NAME" >/dev/null 2>&1 STATUS=$? fi ;; REDHAT) if [ -n "$RELOAD" ]; then killproc ${PIDFILE:+"-p"} ${PIDFILE:+"$PIDFILE"} "$DAEMON_EXEC" -HUP STATUS=$? else echo_failure fi ;; SUSE) if [ -n "$RELOAD" ]; then killproc -HUP ${PIDFILE:+"-p"} ${PIDFILE:+"$PIDFILE"} "$DAEMON_EXEC" else rc_failed $STATUS fi rc_status -v ;; LSB) if [ -n "$RELOAD" ]; then killproc ${PIDFILE:+"-p"} ${PIDFILE:+"$PIDFILE"} "$DAEMON_EXEC" -HUP STATUS=$? fi ;; *) if [ -n "$RELOAD" ]; then signal_process "$DAEMON_EXEC" "HUP" STATUS=$? fi ;; esac log_fini "$STATUS" } service_force_reload () { # Reload the configuration if the service supports this; # otherwise, restart the service if it is already running. # # Required by LSB, where running "force-reload" on a service already stopped or # not running should be considered successful. ## if [ -n "$RELOAD" ]; then $0 reload else $0 try-restart fi case $SYSTEM in SUSE) rc_status ;; DEBIAN|REDHAT|LSB|*) STATUS=$? ;; esac } service_status () { # Print the current status of the service. # # Required by LSB. ## case $SYSTEM in REDHAT) status ${PIDFILE:+"-p"} ${PIDFILE:+"$PIDFILE"} "$DAEMON_EXEC" STATUS=$? ;; SUSE) printf "Checking for service $SERVICE_NAME: " checkproc ${PIDFILE:+"-p"} ${PIDFILE:+"$PIDFILE"} "$DAEMON_EXEC" rc_status -v ;; LSB) printf "Checking status of $SERVICE_NAME: " pids=`pidofproc ${PIDFILE:+"-p"} ${PIDFILE:+"$PIDFILE"} \ "$DAEMON_EXEC" 2>/dev/null` STATUS=$? if [ $STATUS -eq 0 -a -n "$pids" ]; then echo "running." elif [ $STATUS -ne 0 -a -s "$PIDFILE" ]; then echo "dead." else echo "stopped." fi ;; DEBIAN|*) printf "Checking status of $SERVICE_NAME: " pids=`query_pids "$DAEMON_EXEC" "$PIDFILE"` rc=$? if [ $rc -eq 0 -a -n "$pids" ]; then echo "running." STATUS=0 # LSB: program is running elif [ $rc -ne 0 -a -s "$PIDFILE" ]; then echo "dead." STATUS=1 # LSB: program is dead & pidfile exists elif [ $rc -ne 0 ]; then echo "stopped." STATUS=3 # LSB: program is not running else echo "unknown." STATUS=4 # LSB: program status unknown fi ;; esac } query_pids () { # Writes the matching PIDs to stdout. # Returns 0 on success (ie, pids found). ## PROCNAME="$1" PIDFILE="$2" if type pgrep >/dev/null 2>&1; then pids=`pgrep -d ' ' -x "\`basename \"$PROCNAME\"\`" 2>/dev/null` rc=$? elif type pidof >/dev/null 2>&1; then pids=`pidof -o $$ -x "$PROCNAME" 2>/dev/null` rc=$? else pids=`(ps awx -o pid -o command || ps -e -f -o pid -o args) 2>/dev/null \ | tail +2 | egrep "( |/)$PROCNAME( |$)" | grep -v egrep \ | sed 's/ *\([0-9]*\).*/\1/' | sort -n | tr '\012' ' '` [ -n "$pids" ] && rc=0 || rc=1 fi unset pids_running if [ -n "$pids" -a -r "$PIDFILE" ]; then read pid_line < "$PIDFILE" for pid in $pid_line; do expr -- "$pid" : '[0-9]*$' >/dev/null 2>&1 \ && expr -- " $pids " : ".* $pid .*" >/dev/null 2>&1 \ && pids_running="$pids_running $pid" done [ -n "$pids_running" ] && pids=$pids_running fi echo $pids return $rc } signal_process () { # Returns 0 on success, 1 if kill failed, 2 if PROCNAME is not running. ## PROCNAME="$1" SIGNUM="$2" pids=`query_pids "$DAEMON_EXEC" "$PIDFILE"` [ $? -ne 0 -o -z "$pids" ] && return 2 kill ${SIGNUM:+"-$SIGNUM"} $pids >/dev/null 2>&1 [ $? -ne 0 ] && return 1 [ -n "$SIGNUM" ] && return 0 sleep 1 pids=`query_pids "$DAEMON_EXEC" "$PIDFILE"` [ $? -ne 0 -o -z "$pids" ] && return 0 [ -z "$SIGTERM_TIMEOUT" ] && return 1 sleep "$SIGTERM_TIMEOUT" kill -KILL $pids >/dev/null 2>&1 pids=`query_pids "$DAEMON_EXEC" "$PIDFILE"` [ $? -ne 0 -o -z "$pids" ] && return 0 return 1 } log_init () { # Output informational message at beginning of action. ## MESSAGE="$1" PROCNAME="$2" case $SYSTEM in DEBIAN) if [ "$VERBOSE" != no ]; then if type log_daemon_msg >/dev/null 2>&1; then log_daemon_msg "$MESSAGE" "$PROCNAME" else printf "$MESSAGE: $PROCNAME" fi fi ;; REDHAT|SUSE|LSB|*) printf "$MESSAGE: $PROCNAME" ;; esac } log_fini () { # Output informational/error message at end of action. ## STATUS="$1" ERRMSG="$2" case $SYSTEM in DEBIAN) if [ "$VERBOSE" != no ]; then if ( type log_end_msg && type log_failure_msg ) >/dev/null 2>&1; then log_end_msg "$STATUS" [ $STATUS -eq 0 -o -z "$ERRMSG" ] || log_failure_msg "$ERRMSG" else [ $STATUS -eq 0 ] && echo "." || echo " (failed)." [ $STATUS -eq 0 -o -z "$ERRMSG" ] || echo "$ERRMSG" >&2 fi fi ;; REDHAT) echo ;; SUSE) [ $STATUS -eq 0 -o -z "$ERRMSG" ] || echo "$ERRMSG" >&2 ;; LSB|*) [ $STATUS -eq 0 ] && echo "." || echo " (failed)." [ $STATUS -eq 0 -o -z "$ERRMSG" ] || echo "$ERRMSG" >&2 ;; esac } ############################################################################### service_init "$@" case "$1" in start) service_start ;; stop) service_stop ;; restart) service_restart ;; try-restart|condrestart) service_try_restart ;; reload) service_reload ;; force-reload) service_force_reload ;; status) service_status ;; *) echo "Usage: `basename \"$0\"`" \ "(start|stop|restart|try-restart|reload|force-reload|status)" >&2 exit 2 # LSB: invalid or excess argument(s) ;; esac service_fini munge-munge-0.5.15/src/etc/munge.sysvinit.sysconfig.in000066400000000000000000000004661425467526100227470ustar00rootroot00000000000000# MUNGE configuration # Pass additional command-line options to munged. # OPTIONS="--key-file=@sysconfdir@/munge/munge.key --num-threads=2" # Adjust the scheduling priority of munged. # NICE= # Execute munged under another username. # USER="munge" # Execute munged under another groupname. # GROUP="munge" munge-munge-0.5.15/src/etc/munge.tmpfiles.conf.in000066400000000000000000000000511425467526100216110ustar00rootroot00000000000000d @runstatedir@/munge 0755 munge munge - munge-munge-0.5.15/src/libcommon/000077500000000000000000000000001425467526100166105ustar00rootroot00000000000000munge-munge-0.5.15/src/libcommon/Makefile.am000066400000000000000000000022511425467526100206440ustar00rootroot00000000000000# MUNGE src/libcommon/Makefile.am # # This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE). # For details, see . include $(top_srcdir)/Make-inc.mk TEMPLATE_FILES = \ munge.7.in \ # End of TEMPLATE_FILES SUBSTITUTE_FILES = \ munge.7 \ # End of SUBSTITUTE_FILES EXTRA_DIST = \ $(TEMPLATE_FILES) \ # End of EXTRA_DIST CLEANFILES = \ $(SUBSTITUTE_FILES) \ # End of CLEANFILES $(SUBSTITUTE_FILES): Makefile $(AM_V_GEN)$(substitute) < '$(srcdir)/$@.in' > '$(builddir)/$@' munge.7: munge.7.in noinst_LTLIBRARIES = \ libcommon.la \ # End of noinst_LTLIBRARIES libcommon_la_CPPFLAGS = \ -DDATE='"$(DATE)"' \ -DLOCALSTATEDIR='"$(localstatedir)"' \ -DRUNSTATEDIR='"$(runstatedir)"' \ -DSYSCONFDIR='"$(sysconfdir)"' \ -I$(top_srcdir)/src/libmunge \ # End of libcommon_la_CPPFLAGS libcommon_la_SOURCES = \ common.h \ daemonpipe.c \ daemonpipe.h \ fd.c \ fd.h \ license.c \ license.h \ log.c \ log.h \ m_msg.c \ m_msg.h \ munge_defs.h \ str.c \ str.h \ version.c \ version.h \ # End of libcommon_la_SOURCES # For dependencies on DATE. # $(srcdir)/libcommon_la-version.lo: Makefile man_MANS = \ munge.7 \ # End of man_MANS munge-munge-0.5.15/src/libcommon/common.h000066400000000000000000000042611425467526100202540ustar00rootroot00000000000000/***************************************************************************** * Written by Chris Dunlap . * Copyright (C) 2007-2022 Lawrence Livermore National Security, LLC. * Copyright (C) 2002-2007 The Regents of the University of California. * UCRL-CODE-155910. * * This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE). * For details, see . * * MUNGE 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. Additionally for the MUNGE library (libmunge), you * can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation, * either version 3 of the License, or (at your option) any later version. * * MUNGE 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 * and GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * and GNU Lesser General Public License along with MUNGE. If not, see * . *****************************************************************************/ #ifndef MUNGE_COMMON_H #define MUNGE_COMMON_H #if HAVE_CONFIG_H # include #endif /* HAVE_CONFIG_H */ #include "fd.h" #include "license.h" #include "log.h" #include "m_msg.h" #include "munge_defs.h" #include "str.h" #if HAVE_BZLIB_H && HAVE_LIBBZ2 # define HAVE_PKG_BZLIB 1 #endif #if HAVE_ZLIB_H && HAVE_LIBZ # define HAVE_PKG_ZLIB 1 #endif #ifndef MAX # define MAX(a,b) ((a >= b) ? (a) : (b)) #endif /* !MAX */ #ifndef MIN # define MIN(a,b) ((a <= b) ? (a) : (b)) #endif /* !MIN */ #include #include #define UID_MAXIMUM (UINT32_MAX - 1) #define UID_SENTINEL ((uid_t) -1) #define GID_MAXIMUM (UINT32_MAX - 1) #define GID_SENTINEL ((gid_t) -1) #endif /* !MUNGE_COMMON_H */ munge-munge-0.5.15/src/libcommon/daemonpipe.c000066400000000000000000000170251425467526100211020ustar00rootroot00000000000000/***************************************************************************** * Written by Chris Dunlap . * Copyright (C) 2007-2022 Lawrence Livermore National Security, LLC. * Copyright (C) 2002-2007 The Regents of the University of California. * UCRL-CODE-155910. * * This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE). * For details, see . * * MUNGE 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. Additionally for the MUNGE library (libmunge), you * can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation, * either version 3 of the License, or (at your option) any later version. * * MUNGE 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 * and GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * and GNU Lesser General Public License along with MUNGE. If not, see * . *****************************************************************************/ #if HAVE_CONFIG_H # include "config.h" #endif /* HAVE_CONFIG_H */ #include #include #include #include #include "daemonpipe.h" #include "fd.h" /***************************************************************************** * Private Variables *****************************************************************************/ static int _daemonpipe_fd_read = -1; static int _daemonpipe_fd_write = -1; /***************************************************************************** * Public Functions *****************************************************************************/ /* daemonpipe_create * Create a "daemonpipe" for IPC synchronization between the parent process * and its double-forked grandchild process during daemonization. * Return 0 on success, or -1 on error with errno set. * The parent process will block upon reading from this pipe until signaled by * a write from its child or grandchild process, after which it will exit. * The grandchild process will write to this pipe once startup is complete. * If startup fails, an error message will be written to the pipe by the child * or grandchild process in order for the parent process to relay it to * stderr before exiting. */ int daemonpipe_create (void) { int fd_pipe [2]; int errno_bak; if (pipe (fd_pipe) < 0) { return (-1); } if (daemonpipe_close_reads () < 0) { goto err; } if (daemonpipe_close_writes () < 0) { goto err; } _daemonpipe_fd_read = fd_pipe[0]; _daemonpipe_fd_write = fd_pipe[1]; return (0); err: errno_bak = errno; (void) close (fd_pipe[0]); (void) close (fd_pipe[1]); errno = errno_bak; return (-1); } /* daemonpipe_close_reads * Close the read-end of the daemonpipe. * Return 0 on success, or -1 on error with errno set. * This should be called by the child process after having been forked. */ int daemonpipe_close_reads (void) { if (_daemonpipe_fd_read < 0) { return (0); } if (close (_daemonpipe_fd_read) < 0) { return (-1); } _daemonpipe_fd_read = -1; return (0); } /* daemonpipe_close_writes * Close the write-end of the daemonpipe. * Return 0 on success, or -1 on error with errno set. * This should be called by the parent process after forking. * This should be called by the grandchild process once startup is complete. * It will signal the parent process blocked on daemonpipe_read(). */ int daemonpipe_close_writes (void) { if (_daemonpipe_fd_write < 0) { return (0); } if (close (_daemonpipe_fd_write) < 0) { return (-1); } _daemonpipe_fd_write = -1; return (0); } /* daemonpipe_read * Read a status code into [statusptr], a priority level into [priorityptr], * and an error string into the buffer [dstbufptr] of length [dstbuflen]. * A status of 0 indicates success. * Return 0 on success, or -1 on error with errno set. * This should be called by the parent process once it is ready to block and * wait for its grandchild process to complete startup/initialization. */ int daemonpipe_read (int *statusptr, int *priorityptr, char *dstbufptr, size_t dstbuflen) { signed char c; char buf [1024]; ssize_t n, m; if ((statusptr == NULL) || (priorityptr == NULL) || (dstbufptr == NULL)) { errno = EINVAL; return (-1); } if (_daemonpipe_fd_read < 0) { errno = EBADF; return (-1); } /* Initialize result parms in case of early return. */ *statusptr = -1; *priorityptr = 0; if (dstbuflen > 0) { dstbufptr[0] = '\0'; } /* Read status. */ n = fd_read_n (_daemonpipe_fd_read, &c, sizeof (c)); if (n < 0) { return (-1); } else if (n == 0) { /* if EOF, no err so return success */ *statusptr = 0; return (0); } else if (n > 0) { *statusptr = (int) c; } /* Read priority. */ n = fd_read_n (_daemonpipe_fd_read, &c, sizeof (c)); if (n < 0) { return (-1); } else if (n == 0) { return (0); } else if (n > 0) { *priorityptr = (int) c; } /* Read error message. */ n = fd_read_n (_daemonpipe_fd_read, buf, sizeof (buf)); if (n < 0) { return (-1); } else if ((n > 0) && (dstbuflen > 0)) { /* * Ensure buf[] is null-terminated. */ m = (n < sizeof (buf)) ? n : sizeof (buf) - 1; buf[m] = '\0'; /* * Remove trailing LF if present. */ m = strlen (buf) - 1; if ((m >= 0) && (buf[m] == '\n')) { buf[m] = '\0'; } strncpy (dstbufptr, buf, dstbuflen); dstbufptr[dstbuflen - 1] = '\0'; } return (0); } /* daemonpipe_write * Write a status code and an error message string [msg] at the specified * [priority] level to the daemonpipe. A status of 0 indicates success. * Return 0 on success, or -1 on error with errno set. * This should be called by the child or grandchild process if an error * message needs to be relayed to the stderr of the parent process. * It will signal the parent process blocked on daemonpipe_read(). */ int daemonpipe_write (int status, int priority, const char *msg) { signed char c; ssize_t len; ssize_t n; if (_daemonpipe_fd_write < 0) { errno = EBADF; return (-1); } /* Write status. */ c = (signed char) status; len = sizeof (c); n = fd_write_n (_daemonpipe_fd_write, &c, len); if (n != len) { return (-1); } /* Write priority. */ c = (signed char) priority; len = sizeof (c); n = fd_write_n (_daemonpipe_fd_write, &c, len); if (n != len) { return (-1); } /* Write error message. If no message is specified, write a null string. */ if (msg == NULL) { msg = "\0"; } len = strlen (msg) + 1; n = fd_write_n (_daemonpipe_fd_write, msg, len); if (n != len) { return (-1); } return (0); } munge-munge-0.5.15/src/libcommon/daemonpipe.h000066400000000000000000000036061425467526100211070ustar00rootroot00000000000000/***************************************************************************** * Written by Chris Dunlap . * Copyright (C) 2007-2022 Lawrence Livermore National Security, LLC. * Copyright (C) 2002-2007 The Regents of the University of California. * UCRL-CODE-155910. * * This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE). * For details, see . * * MUNGE 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. Additionally for the MUNGE library (libmunge), you * can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation, * either version 3 of the License, or (at your option) any later version. * * MUNGE 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 * and GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * and GNU Lesser General Public License along with MUNGE. If not, see * . *****************************************************************************/ #ifndef DAEMONPIPE_H #define DAEMONPIPE_H #if HAVE_CONFIG_H # include "config.h" #endif /* HAVE_CONFIG_H */ #include int daemonpipe_create (void); int daemonpipe_close_reads (void); int daemonpipe_close_writes (void); int daemonpipe_read (int *statusptr, int *priorityptr, char *dstbufptr, size_t dstbuflen); int daemonpipe_write (int status, int priority, const char *msg); #endif /* !DAEMONPIPE_H */ munge-munge-0.5.15/src/libcommon/fd.c000066400000000000000000000271631425467526100173560ustar00rootroot00000000000000/***************************************************************************** * Written by Chris Dunlap . * Copyright (C) 2007-2022 Lawrence Livermore National Security, LLC. * Copyright (C) 2002-2007 The Regents of the University of California. * UCRL-CODE-155910. * * This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE). * For details, see . * * MUNGE 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. Additionally for the MUNGE library (libmunge), you * can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation, * either version 3 of the License, or (at your option) any later version. * * MUNGE 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 * and GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * and GNU Lesser General Public License along with MUNGE. If not, see * . ***************************************************************************** * Refer to "fd.h" for documentation on public functions. *****************************************************************************/ #if HAVE_CONFIG_H # include "config.h" #endif /* HAVE_CONFIG_H */ #include #include #include #include #include #include #include #include #include #include "fd.h" /***************************************************************************** * Private Prototypes *****************************************************************************/ static int _fd_get_poll_timeout (const struct timeval *when); /***************************************************************************** * Public Functions for I/O *****************************************************************************/ ssize_t fd_read_n (int fd, void *buf, size_t n) { unsigned char *p; size_t nleft; ssize_t nread; p = buf; nleft = n; while (nleft > 0) { if ((nread = read (fd, p, nleft)) < 0) { if (errno == EINTR) continue; else return (-1); } else if (nread == 0) { /* EOF */ break; } nleft -= nread; p += nread; } return (n - nleft); } ssize_t fd_write_n (int fd, const void *buf, size_t n) { const unsigned char *p; size_t nleft; ssize_t nwritten; p = buf; nleft = n; while (nleft > 0) { if ((nwritten = write (fd, p, nleft)) < 0) { if (errno == EINTR) continue; else return (-1); } nleft -= nwritten; p += nwritten; } return (n); } ssize_t fd_timed_read_n (int fd, void *buf, size_t n, const struct timeval *when, int do_skip_first_poll) { unsigned char *p; int msecs; struct pollfd pfd; int nfd; size_t nleft; ssize_t nread; if ((fd < 0) || (buf == NULL)) { errno = EINVAL; return (-1); } p = buf; nleft = n; pfd.fd = fd; pfd.events = POLLIN; if (do_skip_first_poll && (nleft > 0)) { msecs = -1; goto read_me; } while (nleft > 0) { msecs = _fd_get_poll_timeout (when); nfd = poll (&pfd, 1, msecs); if (nfd < 0) { if ((errno == EINTR) || (errno == EAGAIN)) continue; else return (-1); } else if (nfd == 0) { /* timeout */ errno = ETIMEDOUT; break; } else if (pfd.revents & POLLNVAL) { errno = EBADF; return (-1); } else if (pfd.revents & POLLERR) { errno = EIO; return (-1); } assert (pfd.revents & POLLIN); read_me: nread = read (fd, p, nleft); if (nread < 0) { if ((errno == EINTR) || (errno == EAGAIN)) continue; else return (-1); } else if (nread == 0) { /* EOF */ break; } nleft -= nread; p += nread; if (msecs == 0) { break; } } return (n - nleft); } ssize_t fd_timed_write_n (int fd, const void *buf, size_t n, const struct timeval *when, int do_skip_first_poll) { const unsigned char *p; int msecs; struct pollfd pfd; int nfd; size_t nleft; ssize_t nwritten; if ((fd < 0) || (buf == NULL)) { errno = EINVAL; return (-1); } p = buf; nleft = n; pfd.fd = fd; pfd.events = POLLOUT; if (do_skip_first_poll && (nleft > 0)) { msecs = -1; goto write_me; } while (nleft > 0) { msecs = _fd_get_poll_timeout (when); nfd = poll (&pfd, 1, msecs); if (nfd < 0) { if ((errno == EINTR) || (errno == EAGAIN)) continue; else return (-1); } else if (nfd == 0) { /* timeout */ errno = ETIMEDOUT; break; } else if (pfd.revents & POLLHUP) { break; } else if (pfd.revents & POLLNVAL) { errno = EBADF; return (-1); } else if (pfd.revents & POLLERR) { errno = EIO; return (-1); } assert (pfd.revents & POLLOUT); write_me: nwritten = write (fd, p, nleft); if (nwritten < 0) { if ((errno == EINTR) || (errno == EAGAIN)) continue; else return (-1); } nleft -= nwritten; p += nwritten; if (msecs == 0) { break; } } return (n - nleft); } ssize_t fd_timed_write_iov (int fd, const struct iovec *iov_orig, int iov_cnt, const struct timeval *when, int do_skip_first_poll) { int iov_mem_len; struct iovec *iov; int i; size_t n, nleft, iov_len; struct pollfd pfd; int nfd; int msecs; ssize_t nwritten; if ((fd < 0) || (iov_orig == NULL) || (iov_cnt <= 0)) { errno = EINVAL; return (-1); } /* Create copy of iovec for modification to handle retrying short writes. */ iov_mem_len = sizeof (struct iovec) * iov_cnt; iov = malloc (iov_mem_len); if (iov == NULL) { errno = ENOMEM; return (-1); } memcpy (iov, iov_orig, iov_mem_len); for (i = 0, n = 0; i < iov_cnt; i++) { n += iov[i].iov_len; } nleft = iov_len = n; pfd.fd = fd; pfd.events = POLLOUT; if (do_skip_first_poll && (nleft > 0)) { msecs = -1; goto writev_me; } while (nleft > 0) { msecs = _fd_get_poll_timeout (when); nfd = poll (&pfd, 1, msecs); if (nfd < 0) { if ((errno == EINTR) || (errno == EAGAIN)) continue; else goto err; } else if (nfd == 0) { /* timeout */ errno = ETIMEDOUT; break; } else if (pfd.revents & POLLHUP) { break; } else if (pfd.revents & POLLNVAL) { errno = EBADF; goto err; } else if (pfd.revents & POLLERR) { errno = EIO; goto err; } assert (pfd.revents & POLLOUT); writev_me: nwritten = writev (fd, iov, iov_cnt); if (nwritten < 0) { if ((errno == EINTR) || (errno == EAGAIN)) continue; else goto err; } nleft -= nwritten; if (msecs == 0) { break; } for (i = 0; (i < iov_cnt) && (nwritten > 0); i++) { n = (nwritten > iov[i].iov_len) ? iov[i].iov_len : nwritten; if (n == 0) continue; nwritten -= n; iov[i].iov_len -= n; iov[i].iov_base = (char *) iov[i].iov_base + n; } } free (iov); return (iov_len - nleft); err: free (iov); return (-1); } ssize_t fd_read_line (int fd, void *buf, size_t maxlen) { ssize_t n, rc; unsigned char c, *p; n = 0; p = buf; while (n < maxlen - 1) { /* reserve space for NUL-termination */ if ((rc = read (fd, &c, 1)) == 1) { n++; *p++ = c; if (c == '\n') break; /* store newline, like fgets() */ } else if (rc == 0) { if (n == 0) /* EOF, no data read */ return (0); else /* EOF, some data read */ break; } else { if (errno == EINTR) continue; return (-1); } } *p = '\0'; /* NUL-terminate, like fgets() */ return (n); } /***************************************************************************** * Public Functions for Attributes *****************************************************************************/ int fd_set_close_on_exec (int fd) { if (fd < 0) { errno = EINVAL; return (-1); } if (fcntl (fd, F_SETFD, FD_CLOEXEC) < 0) { return (-1); } return (0); } int fd_set_nonblocking (int fd) { int fval; if (fd < 0) { errno = EINVAL; return (-1); } if ((fval = fcntl (fd, F_GETFL, 0)) < 0) { return (-1); } if (fcntl (fd, F_SETFL, fval | O_NONBLOCK) < 0) { return (-1); } return (0); } int fd_is_nonblocking (int fd) { int fval; if (fd < 0) { errno = EINVAL; return (-1); } if ((fval = fcntl (fd, F_GETFL, 0)) < 0) { return (-1); } return ((fval & O_NONBLOCK) ? 1 : 0); } /***************************************************************************** * Private Functions *****************************************************************************/ static int _fd_get_poll_timeout (const struct timeval *when) { /* Returns the poll() timeout value for the number of milliseconds between now * and [when] (which specifies an absolute time in seconds and microseconds * since the Epoch), 0 if [when] is in the past, or -1 if [when] is NULL * (indicating poll() should wait indefinitely). */ struct timeval now; int msecs; if (when == NULL) { return (-1); } if ((when->tv_sec == 0) && (when->tv_usec == 0)) { return (0); } /* POSIX says gettimeofday() can't fail, but just in case ... */ if (gettimeofday (&now, NULL) < 0) { return (0); } /* Round up to the next millisecond. * XXX: msecs can overflow/underflow if [when] is too far from now. */ msecs = ( (when->tv_sec - now.tv_sec) * 1000 ) + ( (when->tv_usec - now.tv_usec + 999) / 1000 ) ; /* * Return 0 if [when] is in the past to indicate poll() should not block. */ return ((msecs < 0) ? 0 : msecs); } munge-munge-0.5.15/src/libcommon/fd.h000066400000000000000000000126271425467526100173620ustar00rootroot00000000000000/***************************************************************************** * Written by Chris Dunlap . * Copyright (C) 2007-2022 Lawrence Livermore National Security, LLC. * Copyright (C) 2002-2007 The Regents of the University of California. * UCRL-CODE-155910. * * This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE). * For details, see . * * MUNGE 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. Additionally for the MUNGE library (libmunge), you * can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation, * either version 3 of the License, or (at your option) any later version. * * MUNGE 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 * and GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * and GNU Lesser General Public License along with MUNGE. If not, see * . *****************************************************************************/ #ifndef FD_H #define FD_H #if HAVE_CONFIG_H # include "config.h" #endif /* HAVE_CONFIG_H */ #include #include #include #include ssize_t fd_read_n (int fd, void *buf, size_t n); /* * Reads up to [n] bytes from [fd] into [buf]. * Returns the number of bytes read, 0 on EOF, or -1 on error. */ ssize_t fd_write_n (int fd, const void *buf, size_t n); /* * Writes [n] bytes from [buf] to [fd]. * Returns the number of bytes written, or -1 on error. */ ssize_t fd_timed_read_n (int fd, void *buf, size_t n, const struct timeval *when, int do_skip_first_poll); /* * Reads up to [n] bytes from [fd] into [buf], timing-out at [when] * which specifies a ceiling on the time for which the call will block. * This ceiling is an absolute timeout in seconds and microseconds since * the Epoch. If [when] is NULL, the read will block until [n] bytes * have been read or an EOF is encountered. * If [do_skip_first_poll] is enabled, the poll() preceding the read() * will be skipped on the first iteration of the loop; this optimization * should only be enabled if [fd] is nonblocking. * Returns the number of bytes read, or -1 on error. A timeout is not * an error. If a timeout has occurred, errno will be set to ETIMEDOUT. * The caller should reset errno beforehand when checking for timeout. */ ssize_t fd_timed_write_n (int fd, const void *buf, size_t n, const struct timeval *when, int do_skip_first_poll); /* * Writes [n] bytes from [buf] to [fd], timing-out at [when] which * specifies a ceiling on the time for which the call will block. * This ceiling is an absolute timeout in seconds and microseconds since * the Epoch. If [when] is NULL, the write will block until [n] bytes * have been written or a POLLHUP is encountered. * If [do_skip_first_poll] is enabled, the poll() preceding the write() * will be skipped on the first iteration of the loop; this optimization * should only be enabled if [fd] is nonblocking. * Returns the number of bytes written, or -1 on error. A timeout is not * an error. If a timeout has occurred, errno will be set to ETIMEDOUT. * The caller should reset errno beforehand when checking for timeout. */ ssize_t fd_timed_write_iov (int fd, const struct iovec *iov, int iov_cnt, const struct timeval *when, int do_skip_first_poll); /* * Writes the [iov] vector of [iov_cnt] blocks to [fd], timing-out at [when] * which specifies a ceiling on the time for which the call will block. * This ceiling is an absolute timeout in seconds and microseconds since * the Epoch. If [when] is NULL, the write will block until [n] bytes * have been written or a POLLHUP is encountered. * If [do_skip_first_poll] is enabled, the poll() preceding the writev() * will be skipped on the first iteration of the loop; this optimization * should only be enabled if [fd] is nonblocking. * Returns the number of bytes written, or -1 on error. A timeout is not * an error. If a timeout has occurred, errno will be set to ETIMEDOUT. * The caller should reset errno beforehand when checking for timeout. */ ssize_t fd_read_line (int fd, void *buf, size_t maxlen); /* * Reads at most [maxlen-1] bytes up to a newline from [fd] into [buf]. * The [buf] is guaranteed to be NUL-terminated and will contain the * newline if it is encountered within [maxlen-1] bytes. * Returns the number of bytes read, 0 on EOF, or -1 on error. */ int fd_set_close_on_exec (int fd); /* * Sets the file descriptor [fd] to be closed on exec(). * Returns 0 on success, or -1 on error. */ int fd_set_nonblocking (int fd); /* * Sets the file descriptor [fd] for nonblocking I/O. * Returns 0 on success, or -1 on error. */ int fd_is_nonblocking (int fd); /* * Returns >0 if the file descriptor [fd] is set for nonblocking I/O, * 0 if not set, or -1 on error (with errno set appropriately). */ #endif /* !FD_H */ munge-munge-0.5.15/src/libcommon/license.c000066400000000000000000000062071425467526100204030ustar00rootroot00000000000000/***************************************************************************** * Written by Chris Dunlap . * Copyright (C) 2007-2022 Lawrence Livermore National Security, LLC. * Copyright (C) 2002-2007 The Regents of the University of California. * UCRL-CODE-155910. * * This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE). * For details, see . * * MUNGE 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. Additionally for the MUNGE library (libmunge), you * can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation, * either version 3 of the License, or (at your option) any later version. * * MUNGE 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 * and GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * and GNU Lesser General Public License along with MUNGE. If not, see * . *****************************************************************************/ #if HAVE_CONFIG_H # include "config.h" #endif /* HAVE_CONFIG_H */ #include #include "license.h" /* The license string was broken into an array of strings in order to keep * below the 509-character limit that ISO C90 compilers are required to * support (detected when compiling with -pedantic). */ static const char *license_text[] = { \ "Welcome to the MUNGE Uid 'N' Gid Emporium (MUNGE).", "https://dun.github.io/munge/", "", "Written by Chris Dunlap .", "Copyright (C) 2007-2022 Lawrence Livermore National Security, LLC.", "Copyright (C) 2002-2007 The Regents of the University of California.", "", "MUNGE 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.", "", "Additionally for the MUNGE library (libmunge), you can redistribute", "it and/or modify it under the terms of the GNU Lesser General Public", "License as published by the Free Software Foundation, either version 3", "of the License, or (at your option) any later version.", "", "MUNGE 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", "and GNU Lesser General Public License for more details.", "", NULL }; void display_license (void) { const char **pp; for (pp = license_text; *pp != NULL; pp++) { printf ("%s\n", *pp); } return; } munge-munge-0.5.15/src/libcommon/license.h000066400000000000000000000031011425467526100203760ustar00rootroot00000000000000/***************************************************************************** * Written by Chris Dunlap . * Copyright (C) 2007-2022 Lawrence Livermore National Security, LLC. * Copyright (C) 2002-2007 The Regents of the University of California. * UCRL-CODE-155910. * * This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE). * For details, see . * * MUNGE 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. Additionally for the MUNGE library (libmunge), you * can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation, * either version 3 of the License, or (at your option) any later version. * * MUNGE 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 * and GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * and GNU Lesser General Public License along with MUNGE. If not, see * . *****************************************************************************/ #ifndef MUNGE_LICENSE_H #define MUNGE_LICENSE_H void display_license (void); #endif /* !MUNGE_LICENSE_H */ munge-munge-0.5.15/src/libcommon/log.c000066400000000000000000000274151425467526100175460ustar00rootroot00000000000000/***************************************************************************** * Written by Chris Dunlap . * Copyright (C) 2007-2022 Lawrence Livermore National Security, LLC. * Copyright (C) 2002-2007 The Regents of the University of California. * UCRL-CODE-155910. * * This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE). * For details, see . * * MUNGE 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. Additionally for the MUNGE library (libmunge), you * can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation, * either version 3 of the License, or (at your option) any later version. * * MUNGE 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 * and GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * and GNU Lesser General Public License along with MUNGE. If not, see * . ***************************************************************************** * Refer to "log.h" for documentation on public functions. *****************************************************************************/ #if HAVE_CONFIG_H # include "config.h" #endif /* HAVE_CONFIG_H */ #include #include #include #include #include #include #include #include #include #include "daemonpipe.h" #include "log.h" #include "str.h" /***************************************************************************** * Constants *****************************************************************************/ #define LOG_BUFFER_MAXLEN 1024 #define LOG_IDENTITY_MAXLEN 128 #define LOG_PREFIX_MAXLEN 9 #define LOG_TRUNC_SUFFIX "+" /***************************************************************************** * Data Types *****************************************************************************/ struct log_ctx { FILE *fp; int got_init; int got_syslog; int got_fprintf_error; int priority; int options; char id [LOG_IDENTITY_MAXLEN]; }; /***************************************************************************** * Static Variables *****************************************************************************/ static struct log_ctx log_ctx = { NULL, 0, 0, 0, 0, 0, { '\0' } }; /***************************************************************************** * Static Prototypes *****************************************************************************/ static void _log_aux (int errnum, int priority, char *msgbuf, int msgbuflen, const char *format, va_list vargs); static void _log_die (int status, int priority, const char *msg); static char * _log_prefix (int priority); /***************************************************************************** * Extern Functions *****************************************************************************/ int log_open_file (FILE *fp, const char *identity, int priority, int options) { const char *p; if (!fp) { errno = EINVAL; return (-1); } if (ferror (fp)) { return (-1); } if (setvbuf (fp, NULL, _IONBF, 0) != 0) { /* set stream unbuffered */ return (-1); } log_ctx.fp = fp; memset (log_ctx.id, 0, sizeof (log_ctx.id)); if (identity) { p = (p = strrchr (identity, '/')) ? p + 1 : identity; if (strlen (p) < sizeof (log_ctx.id)) { strcpy (log_ctx.id, p); } } log_ctx.priority = (priority > 0) ? priority : 0; log_ctx.options = options; log_ctx.got_init = 1; return (0); } void log_close_file (void) { if (log_ctx.fp) { (void) fclose (log_ctx.fp); log_ctx.fp = NULL; } return; } int log_open_syslog (const char *identity, int facility) { char *p; if (!identity) { errno = EINVAL; return (-1); } if ((p = strrchr (identity, '/'))) { identity = p + 1; } openlog (identity, LOG_NDELAY | LOG_PID, facility); log_ctx.got_syslog = 1; log_ctx.got_init = 1; return (0); } void log_close_syslog (void) { if (log_ctx.got_syslog) { closelog (); log_ctx.got_syslog = 0; } return; } void log_close_all (void) { log_close_file (); log_close_syslog (); return; } void log_err (int status, int priority, const char *format, ...) { va_list vargs; char msg [LOG_BUFFER_MAXLEN]; va_start (vargs, format); _log_aux (0, priority, msg, sizeof (msg), format, vargs); va_end (vargs); _log_die (status, priority, msg); assert (1); /* not reached */ } void log_errno (int status, int priority, const char *format, ...) { va_list vargs; char msg [LOG_BUFFER_MAXLEN]; va_start (vargs, format); _log_aux (errno, priority, msg, sizeof (msg), format, vargs); va_end (vargs); _log_die (status, priority, msg); assert (1); /* not reached */ } void log_msg (int priority, const char *format, ...) { va_list vargs; va_start (vargs, format); _log_aux (0, priority, NULL, 0, format, vargs); va_end (vargs); return; } void log_err_or_warn (int got_force, const char *format, ...) { va_list vargs; char msg [LOG_BUFFER_MAXLEN]; int priority; priority = (got_force) ? LOG_WARNING : LOG_ERR; va_start (vargs, format); _log_aux (0, priority, msg, sizeof (msg), format, vargs); va_end (vargs); if (!got_force) { _log_die (1, priority, msg); } return; } /***************************************************************************** * Static Functions *****************************************************************************/ static void _log_aux (int errnum, int priority, char *msgbuf, int msgbuflen, const char *format, va_list vargs) { char buf [LOG_BUFFER_MAXLEN]; /* message buffer */ char *p; /* current position in msg buf */ char *sbuf; /* syslog portion of message buffer */ char *prefix; /* priority prefix message */ int n; /* return value of num chars written */ int len; /* remaining len in buf includes nul */ int append_nl = 0; /* set to 1 if trailing nl is needed */ /* If no log has been specified, output log msgs to stderr. */ if (!log_ctx.got_init) { log_ctx.fp = stderr; log_ctx.options = 0; log_ctx.priority = LOG_DEBUG; log_ctx.got_init = 1; } p = buf; sbuf = NULL; len = sizeof (buf); if ((!format) || (format [strlen (format) - 1] != '\n')) { append_nl = 1; --len; /* reserve space for trailing LF */ } /* Add identity string. */ if (log_ctx.id [0] != '\0') { n = snprintf (p, len, "%s: ", log_ctx.id); if ((n < 0) || (n >= len)) { p += len - 1; len = 0; } else { p += n; len -= n; } } /* Add timestamp. */ if ((len > 0) && (log_ctx.options & LOG_OPT_TIMESTAMP)) { n = strftimet (p, len, "%Y-%m-%d %H:%M:%S %z ", 0); if (n == 0) { len = 0; } else if (n > 0) { p += n; len -= n; } } /* Add priority string. */ if ((len > 0) && (log_ctx.options & LOG_OPT_PRIORITY)) { if ((prefix = _log_prefix (priority))) { int m = 1; if (log_ctx.options & LOG_OPT_JUSTIFY) { if ((m = LOG_PREFIX_MAXLEN + 1 - strlen (prefix)) < 0) { m = 1; } } n = snprintf (p, len, "%s:%*c", prefix, m, 0x20); if ((n < 0) || (n >= len)) { p += len - 1; len = 0; } else { p += n; len -= n; } } } /* Add actual message. */ if ((len > 0) && (format)) { sbuf = p; n = vsnprintf (p, len, format, vargs); if ((n < 0) || (n >= len)) { p += len - 1; len = 0; } else { p += n; len -= n; } } /* Add error string if: * - an error occurred (defined by errno), and * - the error string does not contain a trailing newline. */ if ((len > 0) && (errnum) && (append_nl)) { n = snprintf (p, len, "%s%s", (format ? ": " : ""), strerror (errnum)); if ((n < 0) || (n >= len)) { p += len - 1; len = 0; } else { p += n; len -= n; } } /* Add truncation string if buffer was overrun. */ if (len <= 0) { char *q; n = strlen (LOG_TRUNC_SUFFIX); q = buf + sizeof (buf) - 1 - append_nl - n; p = (p < q) ? p : q; strcpy (p, LOG_TRUNC_SUFFIX); p += n; } /* Terminate buffer with trailing newline and terminating NUL. */ if (append_nl) { *p++ = '\n'; } *p = '\0'; /* Return error message string. */ if (msgbuf && (msgbuflen > 0)) { if (sbuf) { strncpy (msgbuf, sbuf, msgbuflen); msgbuf[msgbuflen - 1] = '\0'; } else { msgbuf[0] = '\0'; } } /* Log message. */ if (log_ctx.got_syslog && sbuf) { syslog (priority, "%s", sbuf); } if (log_ctx.fp && (priority <= log_ctx.priority)) { errno = 0; if (fprintf (log_ctx.fp, "%s", buf) == EOF) { if (!log_ctx.got_fprintf_error) { syslog (LOG_ERR, "Failed logfile write: %s: messages may have been dropped", (errno != 0) ? strerror (errno) : "Unspecified error"); log_ctx.got_fprintf_error = 1; } } else if (log_ctx.got_fprintf_error) { log_ctx.got_fprintf_error = 0; } } return; } static void _log_die (int status, int priority, const char *msg) { /* If the daemonpipe is open between the (grand)child process and the * parent process, relay the error message to the parent for output onto * stderr. But if the error message has already been written to stderr, * simply relay the status without the message text. */ (void) daemonpipe_write (status, priority, (log_ctx.fp != stderr) ? msg : NULL); #ifndef NDEBUG /* Generate core for debugging. */ if ((status != EXIT_SUCCESS) && getenv ("DEBUG")) { abort (); } #endif /* !NDEBUG */ exit (status); } static char * _log_prefix (int priority) { switch (priority) { case LOG_EMERG: return ("Emergency"); case LOG_ALERT: return ("Alert"); case LOG_CRIT: return ("Critical"); case LOG_ERR: return ("Error"); case LOG_WARNING: return ("Warning"); case LOG_NOTICE: return ("Notice"); case LOG_INFO: return ("Info"); case LOG_DEBUG: return ("Debug"); default: return ("Unknown"); } assert (1); /* not reached */ } munge-munge-0.5.15/src/libcommon/log.h000066400000000000000000000102311425467526100175370ustar00rootroot00000000000000/***************************************************************************** * Written by Chris Dunlap . * Copyright (C) 2007-2022 Lawrence Livermore National Security, LLC. * Copyright (C) 2002-2007 The Regents of the University of California. * UCRL-CODE-155910. * * This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE). * For details, see . * * MUNGE 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. Additionally for the MUNGE library (libmunge), you * can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation, * either version 3 of the License, or (at your option) any later version. * * MUNGE 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 * and GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * and GNU Lesser General Public License along with MUNGE. If not, see * . *****************************************************************************/ #ifndef LOG_H #define LOG_H #if HAVE_CONFIG_H # include "config.h" #endif /* HAVE_CONFIG_H */ #include #include #define LOG_OPT_NONE 0x00 #define LOG_OPT_JUSTIFY 0x01 /* justify priority str field width */ #define LOG_OPT_PRIORITY 0x02 /* add priority string to message */ #define LOG_OPT_TIMESTAMP 0x04 /* add timestamp to message */ int log_open_file (FILE *fp, const char *identity, int priority, int options); /* * If [fp] is non-NULL, log messages at the [priority] level and higher * (ie, below) to the specified file stream. * If [identity] is non-NULL, its trailing "filename" component will * be prepended to each message. * The [options] parameter is a bitwise-OR of any "LOG_OPT_" defines * specified above. * Messages can be concurrently logged to syslog and one file stream. * Returns 0 if the file is opened, or -1 on error; * on error, the previous file stream remains open. */ void log_close_file (void); /* * Close the logging file stream (if open). */ int log_open_syslog (const char *identity, int facility); /* * If [identity] is non-NULL, log messages to syslog at the specified * [facility] (cf, syslog(3)) prepending the trailing "filename" component * of [identity] to each message. * Messages can be concurrently logged to syslog and one file stream. * Returns 0 on success, -1 on error. */ void log_close_syslog (void); /* * Closes the file descriptor used to write to the system logger (if open). */ void log_close_all (void); /* * Closes all logging devices that are open. */ void log_err (int status, int priority, const char *format, ...); /* * Logs a fatal message at the specified [priority] level according to * the printf-style [format] string, after which it exits the program * with the specified [status] value. */ void log_errno (int status, int priority, const char *format, ...); /* * Logs a fatal message at the specified [priority] level according to * the printf-style [format] string, after which it exits the program * with the specified [status] value. * An error string will be appended to the message if the format string * is not terminated with a newline and errno is non-zero. */ void log_msg (int priority, const char *format, ...); /* * Logs a non-fatal message at the specified [priority] level according to * the printf-style [format] string. */ void log_err_or_warn (int got_force, const char *format, ...); /* * If [got_force] is false, log a fatal error message with the printf-style * [format] string. * If [got_force] is true, the fatal error is converted into a non-fatal * warning. */ #endif /* !LOG_H */ munge-munge-0.5.15/src/libcommon/m_msg.c000066400000000000000000000733461425467526100200730ustar00rootroot00000000000000/***************************************************************************** * Written by Chris Dunlap . * Copyright (C) 2007-2022 Lawrence Livermore National Security, LLC. * Copyright (C) 2002-2007 The Regents of the University of California. * UCRL-CODE-155910. * * This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE). * For details, see . * * MUNGE 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. Additionally for the MUNGE library (libmunge), you * can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation, * either version 3 of the License, or (at your option) any later version. * * MUNGE 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 * and GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * and GNU Lesser General Public License along with MUNGE. If not, see * . *****************************************************************************/ #if HAVE_CONFIG_H # include "config.h" #endif /* HAVE_CONFIG_H */ #include #include #include #include #include #include #include #include /* gettimeofday */ #include #include #include "fd.h" #include "m_msg.h" #include "munge_defs.h" #include "str.h" /***************************************************************************** * Data Types *****************************************************************************/ typedef void ** vpp; /***************************************************************************** * Prototypes *****************************************************************************/ static void _get_timeval (struct timeval *tv, int msecs); static int _msg_length (m_msg_t m, m_msg_type_t type); static munge_err_t _msg_pack (m_msg_t m, m_msg_type_t type, void *dst, int dstlen); static munge_err_t _msg_unpack (m_msg_t m, m_msg_type_t type, const void *src, int srclen); static int _alloc (void **pdst, int len); static int _copy (void *dst, void *src, int len, const void *first, const void *last, void **pinc); static int _pack (void **pdst, void *src, int len, const void *last); static int _unpack (void *dst, void **psrc, int len, const void *last); /***************************************************************************** * Public Functions *****************************************************************************/ munge_err_t m_msg_create (m_msg_t *pm) { /* Creates a message (passed by reference) for sending over the munge socket. * Returns a standard munge error code. */ m_msg_t m; assert (pm != NULL); if (!(m = calloc (1, sizeof (*m)))) { *pm = NULL; return (EMUNGE_NO_MEMORY); } m->sd = -1; m->type = MUNGE_MSG_UNDEF; *pm = m; return (EMUNGE_SUCCESS); } void m_msg_destroy (m_msg_t m) { /* Destroys the message [m]. */ assert (m != NULL); if (m->sd >= 0) { (void) close (m->sd); } if (m->pkt && !m->pkt_is_copy) { assert (m->pkt_len > 0); free (m->pkt); } if (m->realm_str && !m->realm_is_copy) { assert (m->realm_len > 0); free (m->realm_str); } if (m->data && !m->data_is_copy) { assert (m->data_len > 0); free (m->data); } if (m->error_str && !m->error_is_copy) { assert (m->error_len > 0); free (m->error_str); } if (m->auth_s_str && !m->auth_s_is_copy) { assert (m->auth_s_len > 0); free (m->auth_s_str); } if (m->auth_c_str && !m->auth_c_is_copy) { assert (m->auth_c_len > 0); free (m->auth_c_str); } free (m); return; } void m_msg_reset (m_msg_t m) { /* Reset sensitive fields in the message [m] that could leak information. */ assert (m != NULL); m->cipher = MUNGE_CIPHER_NONE; m->mac = MUNGE_MAC_NONE; m->zip = MUNGE_ZIP_NONE; m->realm_len = 0; if (m->realm_str) { if (!m->realm_is_copy) { free (m->realm_str); } m->realm_str = NULL; } m->ttl = MUNGE_TTL_DEFAULT; m->addr_len = 0; m->time0 = 0; m->time1 = 0; m->cred_uid = MUNGE_UID_ANY; m->cred_gid = MUNGE_GID_ANY; m->auth_uid = MUNGE_UID_ANY; m->auth_gid = MUNGE_GID_ANY; m->data_len = 0; if (m->data) { if (!m->data_is_copy) { free (m->data); } m->data = NULL; } return; } munge_err_t m_msg_bind (m_msg_t m, int sd) { /* Binds the message [m] to the socket [sd]. */ assert (m != NULL); if (m->sd >= 0) { (void) close (m->sd); } m->sd = sd; return (EMUNGE_SUCCESS); } munge_err_t m_msg_send (m_msg_t m, m_msg_type_t type, int maxlen) { /* Sends the message [m] of type [type] to the recipient at the other end * of the already-specified socket. * If [maxlen] > 0, message bodies larger than this value will be discarded * and an error returned. * Returns a standard munge error code. */ munge_err_t e; int n, nsend; uint8_t hdr [MUNGE_MSG_HDR_SIZE]; struct iovec iov [2]; struct timeval tv; assert (m != NULL); assert (m->sd >= 0); assert (type != MUNGE_MSG_UNDEF); assert (type != MUNGE_MSG_HDR); /* If the stored message type [m->type] does not match the given * message type [type], clean up the old packed message body. */ if (m->type != type) { if (m->pkt) { assert (m->pkt_len > 0); if (!m->pkt_is_copy) { free (m->pkt); } m->pkt = NULL; m->pkt_len = 0; m->pkt_is_copy = 0; } } /* If a previously packed message body does not already exist, * create & pack the message body. */ if (!m->pkt) { assert (m->pkt_len == 0); assert (m->pkt_is_copy == 0); if ((n = _msg_length (m, type)) <= 0) { m_msg_set_err (m, EMUNGE_NO_MEMORY, strdupf ("Failed to compute length for message type %d n=%d", type, n)); return (EMUNGE_SNAFU); } if (!(m->pkt = malloc (n))) { m_msg_set_err (m, EMUNGE_NO_MEMORY, strdupf ("Failed to allocate %d bytes for sending message", n)); return (EMUNGE_NO_MEMORY); } m->pkt_len = n; m->type = type; e = _msg_pack (m, type, m->pkt, m->pkt_len); if (e != EMUNGE_SUCCESS) { m_msg_set_err (m, e, strdup ("Failed to pack message body")); return (e); } } /* Check if the message exceeds the maximum allowed length. */ if ((maxlen > 0) && (m->pkt_len > maxlen)) { m_msg_set_err (m, EMUNGE_SOCKET, strdupf ("Failed to send message: " "length of %d exceeds max of %d", m->pkt_len, maxlen)); return (EMUNGE_BAD_LENGTH); } /* Always repack the message header. */ e = _msg_pack (m, MUNGE_MSG_HDR, hdr, sizeof (hdr)); if (e != EMUNGE_SUCCESS) { m_msg_set_err (m, e, strdup ("Failed to pack message header")); return (e); } /* Compute iovec for response header + body. */ nsend = 0; iov[0].iov_base = (void *) hdr; nsend += iov[0].iov_len = sizeof (hdr); iov[1].iov_base = m->pkt; nsend += iov[1].iov_len = m->pkt_len; /* Compute maximum time to wait for transmission of message. */ _get_timeval (&tv, MUNGE_SOCKET_TIMEOUT_MSECS); /* Send the message. */ if ((errno = 0, n = fd_timed_write_iov (m->sd, iov, 2, &tv, 1)) < 0) { m_msg_set_err (m, EMUNGE_SOCKET, strdupf ("Failed to send message: %s", strerror (errno))); return (EMUNGE_SOCKET); } else if (errno == ETIMEDOUT) { m_msg_set_err (m, EMUNGE_SOCKET, strdup ("Failed to send message: Timed-out")); return (EMUNGE_SOCKET); } else if (n != nsend) { m_msg_set_err (m, EMUNGE_SOCKET, strdupf ("Sent incomplete message: %d of %d bytes", n, nsend)); return (EMUNGE_SOCKET); } return (EMUNGE_SUCCESS); } munge_err_t m_msg_recv (m_msg_t m, m_msg_type_t type, int maxlen) { /* Receives a message from the sender at the other end of the * already-specified socket. This message is stored in the * previously-created [m]. * If a [type] is specified (ie, not MUNGE_MSG_UNDEF) and does not match * the header type, the message will be discarded and an error returned. * If [maxlen] > 0, message bodies larger than this value will be discarded * and an error returned. * Returns a standard munge error code. */ int n, nrecv; uint8_t hdr [MUNGE_MSG_HDR_SIZE]; struct timeval tv; assert (m != NULL); assert (m->sd >= 0); assert (m->type != MUNGE_MSG_HDR); assert (m->pkt == NULL); assert (m->pkt_len == 0); assert (m->pkt_is_copy == 0); assert (_msg_length (m, MUNGE_MSG_HDR) == MUNGE_MSG_HDR_SIZE); /* Compute maximum time to wait for receipt of message. */ _get_timeval (&tv, MUNGE_SOCKET_TIMEOUT_MSECS); /* Read and validate the message header. */ nrecv = sizeof (hdr); if ((errno = 0, n = fd_timed_read_n (m->sd, &hdr, nrecv, &tv, 1)) < 0) { m_msg_set_err (m, EMUNGE_SOCKET, strdupf ("Failed to receive message header: %s", strerror (errno))); return (EMUNGE_SOCKET); } else if (errno == ETIMEDOUT) { m_msg_set_err (m, EMUNGE_SOCKET, strdup ("Failed to receive message header: Timed-out")); return (EMUNGE_SOCKET); } else if (n != nrecv) { m_msg_set_err (m, EMUNGE_SOCKET, strdupf ("Received incomplete message header: %d of %d bytes", n, nrecv)); return (EMUNGE_SOCKET); } else if (_msg_unpack (m, MUNGE_MSG_HDR, hdr, sizeof (hdr)) != EMUNGE_SUCCESS) { m_msg_set_err (m, EMUNGE_SOCKET, strdup ("Failed to unpack message header")); return (EMUNGE_SOCKET); } else if ((type != MUNGE_MSG_UNDEF) && (m->type != type)) { m_msg_set_err (m, EMUNGE_SOCKET, strdupf ("Received unexpected message type: wanted %d, got %d", type, m->type)); return (EMUNGE_SOCKET); } else if ((maxlen > 0) && (m->pkt_len > maxlen)) { m_msg_set_err (m, EMUNGE_SOCKET, strdupf ("Failed to receive message: " "length of %d exceeds max of %d", m->pkt_len, maxlen)); return (EMUNGE_BAD_LENGTH); } else if (!(m->pkt = malloc (m->pkt_len))) { m_msg_set_err (m, EMUNGE_NO_MEMORY, strdupf ("Failed to allocate %d bytes for receiving message", n)); return (EMUNGE_NO_MEMORY); } else if ((errno = 0, n = fd_timed_read_n (m->sd, m->pkt, m->pkt_len, &tv, 1)) < 0) { m_msg_set_err (m, EMUNGE_SOCKET, strdupf ("Failed to receive message body: %s", strerror (errno))); return (EMUNGE_SOCKET); } else if (errno == ETIMEDOUT) { m_msg_set_err (m, EMUNGE_SOCKET, strdup ("Failed to receive message body: Timed-out")); return (EMUNGE_SOCKET); } else if (n != m->pkt_len) { m_msg_set_err (m, EMUNGE_SOCKET, strdupf ("Received incomplete message body: %d of %d bytes", n, nrecv)); return (EMUNGE_SOCKET); } else if (_msg_unpack (m, m->type, m->pkt, m->pkt_len) != EMUNGE_SUCCESS) { m_msg_set_err (m, EMUNGE_SOCKET, strdup ("Failed to unpack message body")); return (EMUNGE_SOCKET); } /* The packed message can be discarded now that it's been unpacked. */ free (m->pkt); m->pkt = NULL; m->pkt_len = 0; assert (m->pkt_is_copy == 0); return (EMUNGE_SUCCESS); } int m_msg_set_err (m_msg_t m, munge_err_t e, char *s) { /* Set an error code [e] and string [s] if an error condition * does not already exist (ie, m->error_num == EMUNGE_SUCCESS). * Thus, if multiple errors are set, only the first one is reported. * If [s] is not NULL, that string (and _not_ a copy) will be stored * and later free()'d by the message destructor; if [s] is NULL, * munge_strerror() will be used to obtain a descriptive string. * Always returns -1 and consumes [s]. */ assert (m != NULL); if ((m->error_num == EMUNGE_SUCCESS) && (e != EMUNGE_SUCCESS)) { m->error_num = e; assert (m->error_str == NULL); assert (m->error_len == 0); assert (m->error_is_copy == 0); m->error_str = (s != NULL) ? s : strdup (munge_strerror (e)); m->error_len = strlen (m->error_str) + 1; } else if (s) { free (s); } /* "Screw you guys, I'm goin' home." -ecartman */ return (-1); } /***************************************************************************** * Private Functions *****************************************************************************/ static void _get_timeval (struct timeval *tv, int msecs) { /* Sets [tv] to the current time adjusted forward by [msecs] milliseconds. */ assert (tv != NULL); if (gettimeofday (tv, NULL) < 0) { tv->tv_sec = tv->tv_usec = 0; } if (msecs > 0) { tv->tv_sec += msecs / 1000; tv->tv_usec += (msecs % 1000) * 1000; if (tv->tv_usec >= 1000000) { tv->tv_sec += tv->tv_usec / 1000000; tv->tv_usec %= 1000000; } } return; } static int _msg_length (m_msg_t m, m_msg_type_t type) { /* Returns the length needed to pack the message [m] of type [type]. */ int n = 0; assert (m != NULL); switch (type) { case MUNGE_MSG_HDR: n += sizeof (m_msg_magic_t); n += sizeof (m_msg_version_t); n += sizeof (m->type); n += sizeof (m->retry); n += sizeof (m->pkt_len); break; case MUNGE_MSG_ENC_REQ: n += sizeof (m->cipher); n += sizeof (m->mac); n += sizeof (m->zip); n += sizeof (m->realm_len); n += m->realm_len; n += sizeof (m->ttl); n += sizeof (m->auth_uid); n += sizeof (m->auth_gid); n += sizeof (m->data_len); n += m->data_len; break; case MUNGE_MSG_ENC_RSP: n += sizeof (m->error_num); n += sizeof (m->error_len); n += m->error_len; n += sizeof (m->data_len); n += m->data_len; break; case MUNGE_MSG_DEC_REQ: n += sizeof (m->data_len); n += m->data_len; break; case MUNGE_MSG_DEC_RSP: n += sizeof (m->error_num); n += sizeof (m->error_len); n += m->error_len; n += sizeof (m->cipher); n += sizeof (m->mac); n += sizeof (m->zip); n += sizeof (m->realm_len); n += m->realm_len; n += sizeof (m->ttl); n += sizeof (m->addr_len); n += m->addr_len; n += sizeof (m->time0); n += sizeof (m->time1); n += sizeof (m->cred_uid); n += sizeof (m->cred_gid); n += sizeof (m->auth_uid); n += sizeof (m->auth_gid); n += sizeof (m->data_len); n += m->data_len; break; case MUNGE_MSG_AUTH_FD_REQ: n += sizeof (m->auth_s_len); n += m->auth_s_len; n += sizeof (m->auth_c_len); n += m->auth_c_len; break; default: return (-1); break; } return (n); } static munge_err_t _msg_pack (m_msg_t m, m_msg_type_t type, void *dst, int dstlen) { /* Packs the message [m] of type [type] into the buffer [dst] * of length [dstlen] for transport across the munge socket. */ m_msg_magic_t magic = MUNGE_MSG_MAGIC; m_msg_version_t version = MUNGE_MSG_VERSION; void *p = dst; void *q = (unsigned char *) dst + dstlen; assert (m != NULL); switch (type) { case MUNGE_MSG_HDR: if (!_pack (&p, &magic, sizeof (magic), q)) ; else if (!_pack (&p, &version, sizeof (version), q)) ; else if (!_pack (&p, &(m->type), sizeof (m->type), q)) ; else if (!_pack (&p, &(m->retry), sizeof (m->retry), q)) ; else if (!_pack (&p, &(m->pkt_len), sizeof (m->pkt_len), q)) ; else break; goto err; case MUNGE_MSG_ENC_REQ: if (!_pack (&p, &(m->cipher), sizeof (m->cipher), q)) ; else if (!_pack (&p, &(m->mac), sizeof (m->mac), q)) ; else if (!_pack (&p, &(m->zip), sizeof (m->zip), q)) ; else if (!_pack (&p, &(m->realm_len), sizeof (m->realm_len), q)) ; else if ( _copy (p, m->realm_str, m->realm_len, p, q, &p) < 0) ; else if (!_pack (&p, &(m->ttl), sizeof (m->ttl), q)) ; else if (!_pack (&p, &(m->auth_uid), sizeof (m->auth_uid), q)) ; else if (!_pack (&p, &(m->auth_gid), sizeof (m->auth_gid), q)) ; else if (!_pack (&p, &(m->data_len), sizeof (m->data_len), q)) ; else if ( _copy (p, m->data, m->data_len, p, q, &p) < 0) ; else break; goto err; case MUNGE_MSG_ENC_RSP: if (!_pack (&p, &(m->error_num), sizeof (m->error_num), q)) ; else if (!_pack (&p, &(m->error_len), sizeof (m->error_len), q)) ; else if ( _copy (p, m->error_str, m->error_len, p, q, &p) < 0) ; else if (!_pack (&p, &(m->data_len), sizeof (m->data_len), q)) ; else if ( _copy (p, m->data, m->data_len, p, q, &p) < 0) ; else break; goto err; case MUNGE_MSG_DEC_REQ: if (!_pack (&p, &(m->data_len), sizeof (m->data_len), q)) ; else if ( _copy (p, m->data, m->data_len, p, q, &p) < 0) ; else break; goto err; case MUNGE_MSG_DEC_RSP: if (!_pack (&p, &(m->error_num), sizeof (m->error_num), q)) ; else if (!_pack (&p, &(m->error_len), sizeof (m->error_len), q)) ; else if ( _copy (p, m->error_str, m->error_len, p, q, &p) < 0) ; else if (!_pack (&p, &(m->cipher), sizeof (m->cipher), q)) ; else if (!_pack (&p, &(m->mac), sizeof (m->mac), q)) ; else if (!_pack (&p, &(m->zip), sizeof (m->zip), q)) ; else if (!_pack (&p, &(m->realm_len), sizeof (m->realm_len), q)) ; else if ( _copy (p, m->realm_str, m->realm_len, p, q, &p) < 0) ; else if (!_pack (&p, &(m->ttl), sizeof (m->ttl), q)) ; else if (!_pack (&p, &(m->addr_len), sizeof (m->addr_len), q)) ; else if ( _copy (p, &(m->addr), m->addr_len, p, q, &p) < 0) ; else if (!_pack (&p, &(m->time0), sizeof (m->time0), q)) ; else if (!_pack (&p, &(m->time1), sizeof (m->time1), q)) ; else if (!_pack (&p, &(m->cred_uid), sizeof (m->cred_uid), q)) ; else if (!_pack (&p, &(m->cred_gid), sizeof (m->cred_gid), q)) ; else if (!_pack (&p, &(m->auth_uid), sizeof (m->auth_uid), q)) ; else if (!_pack (&p, &(m->auth_gid), sizeof (m->auth_gid), q)) ; else if (!_pack (&p, &(m->data_len), sizeof (m->data_len), q)) ; else if ( _copy (p, m->data, m->data_len, p, q, &p) < 0) ; else break; goto err; case MUNGE_MSG_AUTH_FD_REQ: if (!_pack (&p, &(m->auth_s_len), sizeof (m->auth_s_len), q)); else if ( _copy (p, m->auth_s_str, m->auth_s_len, p, q, &p) < 0) ; else if (!_pack (&p, &(m->auth_c_len), sizeof (m->auth_c_len), q)); else if ( _copy (p, m->auth_c_str, m->auth_c_len, p, q, &p) < 0) ; else break; goto err; default: goto err; } return (EMUNGE_SUCCESS); err: m_msg_set_err (m, EMUNGE_SNAFU, strdupf ("Failed to pack message type %d", type)); return (EMUNGE_SNAFU); } static munge_err_t _msg_unpack (m_msg_t m, m_msg_type_t type, const void *src, int srclen) { /* Unpacks the message [m] from transport across the munge socket. * Checks to ensure the message is of the expected type [type]. */ m_msg_magic_t magic; m_msg_version_t version; void *p = (void *) src; void *q = (unsigned char *) src + srclen; assert (m != NULL); switch (type) { case MUNGE_MSG_HDR: if (!_unpack (&magic, &p, sizeof (magic), q)) ; else if (!_unpack (&version, &p, sizeof (version), q)) ; else if (!_unpack (&(m->type), &p, sizeof (m->type), q)) ; else if (!_unpack (&(m->retry), &p, sizeof (m->retry), q)) ; else if (!_unpack (&(m->pkt_len), &p, sizeof (m->pkt_len), q)) ; else break; goto err; case MUNGE_MSG_ENC_REQ: if (!_unpack (&(m->cipher), &p, sizeof (m->cipher), q)) ; else if (!_unpack (&(m->mac), &p, sizeof (m->mac), q)) ; else if (!_unpack (&(m->zip), &p, sizeof (m->zip), q)) ; else if (!_unpack (&(m->realm_len), &p, sizeof (m->realm_len), q)); else if (!_alloc ((vpp) &(m->realm_str), m->realm_len)) goto nomem; else if ( _copy (m->realm_str, p, m->realm_len, p, q, &p) < 0) ; else if (!_unpack (&(m->ttl), &p, sizeof (m->ttl), q)) ; else if (!_unpack (&(m->auth_uid), &p, sizeof (m->auth_uid), q)) ; else if (!_unpack (&(m->auth_gid), &p, sizeof (m->auth_gid), q)) ; else if (!_unpack (&(m->data_len), &p, sizeof (m->data_len), q)) ; else if (!_alloc (&(m->data), m->data_len)) goto nomem; else if ( _copy (m->data, p, m->data_len, p, q, &p) < 0) ; else break; goto err; case MUNGE_MSG_ENC_RSP: if (!_unpack (&(m->error_num), &p, sizeof (m->error_num), q)); else if (!_unpack (&(m->error_len), &p, sizeof (m->error_len), q)); else if (!_alloc ((vpp) &(m->error_str), m->error_len)) goto nomem; else if ( _copy (m->error_str, p, m->error_len, p, q, &p) < 0) ; else if (!_unpack (&(m->data_len), &p, sizeof (m->data_len), q)) ; else if (!_alloc (&(m->data), m->data_len)) goto nomem; else if ( _copy (m->data, p, m->data_len, p, q, &p) < 0) ; else break; goto err; case MUNGE_MSG_DEC_REQ: if (!_unpack (&(m->data_len), &p, sizeof (m->data_len), q)) ; else if (!_alloc (&(m->data), m->data_len)) goto nomem; else if ( _copy (m->data, p, m->data_len, p, q, &p) < 0) ; else break; goto err; case MUNGE_MSG_DEC_RSP: if (!_unpack (&(m->error_num), &p, sizeof (m->error_num), q)); else if (!_unpack (&(m->error_len), &p, sizeof (m->error_len), q)); else if (!_alloc ((vpp) &(m->error_str), m->error_len)) goto nomem; else if ( _copy (m->error_str, p, m->error_len, p, q, &p) < 0) ; else if (!_unpack (&(m->cipher), &p, sizeof (m->cipher), q)) ; else if (!_unpack (&(m->mac), &p, sizeof (m->mac), q)) ; else if (!_unpack (&(m->zip), &p, sizeof (m->zip), q)) ; else if (!_unpack (&(m->realm_len), &p, sizeof (m->realm_len), q)); else if (!_alloc ((vpp) &(m->realm_str), m->realm_len)) goto nomem; else if ( _copy (m->realm_str, p, m->realm_len, p, q, &p) < 0) ; else if (!_unpack (&(m->ttl), &p, sizeof (m->ttl), q)) ; else if (!_unpack (&(m->addr_len), &p, sizeof (m->addr_len), q)) ; else if ( _copy (&(m->addr), p, m->addr_len, p, q, &p) < 0) ; else if (!_unpack (&(m->time0), &p, sizeof (m->time0), q)) ; else if (!_unpack (&(m->time1), &p, sizeof (m->time1), q)) ; else if (!_unpack (&(m->cred_uid), &p, sizeof (m->cred_uid), q)) ; else if (!_unpack (&(m->cred_gid), &p, sizeof (m->cred_gid), q)) ; else if (!_unpack (&(m->auth_uid), &p, sizeof (m->auth_uid), q)) ; else if (!_unpack (&(m->auth_gid), &p, sizeof (m->auth_gid), q)) ; else if (!_unpack (&(m->data_len), &p, sizeof (m->data_len), q)) ; else if (!_alloc (&(m->data), m->data_len)) goto nomem; else if ( _copy (m->data, p, m->data_len, p, q, &p) < 0) ; else break; goto err; case MUNGE_MSG_AUTH_FD_REQ: if (!_unpack(&(m->auth_s_len), &p, sizeof(m->auth_s_len), q)); else if (!_alloc((vpp)&(m->auth_s_str), m->auth_s_len)) goto nomem; else if ( _copy (m->auth_s_str, p, m->auth_s_len, p, q, &p) < 0) ; else if (!_unpack(&(m->auth_c_len), &p, sizeof(m->auth_c_len), q)); else if (!_alloc((vpp)&(m->auth_c_str), m->auth_c_len)) goto nomem; else if ( _copy (m->auth_c_str, p, m->auth_c_len, p, q, &p) < 0) ; else break; goto err; default: goto err; } assert (p == (unsigned char *) src + srclen); if (type == MUNGE_MSG_HDR) { if (magic != MUNGE_MSG_MAGIC) { m_msg_set_err (m, EMUNGE_SOCKET, strdupf ("Received invalid message magic %d", magic)); return (EMUNGE_SOCKET); } else if (version != MUNGE_MSG_VERSION) { m_msg_set_err (m, EMUNGE_SOCKET, strdupf ("Received invalid message version %d", version)); return (EMUNGE_SOCKET); } } return (EMUNGE_SUCCESS); err: m_msg_set_err (m, EMUNGE_SNAFU, strdupf ("Failed to unpack message type %d", type)); return (EMUNGE_SNAFU); nomem: m_msg_set_err (m, EMUNGE_NO_MEMORY, NULL); return (EMUNGE_NO_MEMORY); } static int _alloc (void **pdst, int len) { /* Allocates memory for [pdst] of length [len + 1], * NUL-terminating the last byte. * Returns non-zero on success; o/w, returns 0. */ unsigned char *p; assert (pdst != NULL); assert (*pdst == NULL); if (len == 0) { /* valid no-op */ return (1); } if (len < 0) { /* invalid length */ return (0); } /* Allocate an extra byte to NUL-terminate the memory allocation. */ if (!(p = malloc (len + 1))) { return (0); } p[len] = '\0'; *pdst = p; return (1); } static int _copy (void *dst, void *src, int len, const void *first, const void *last, void **pinc) { /* Copies [len] bytes of data from [src] to [dst]. * If [first] and [last] are both non-NULL, checks to ensure * [len] bytes of data resides between [first] and [last]. * Returns the number of bytes copied into [dst], or -1 on error. * On success (ie, >= 0), an optional [inc] ptr is advanced by [len]. */ if (len < 0) { return (-1); } if (len == 0) { return (0); } if ((first != NULL) && (last != NULL) && ((unsigned char *) first + len > (unsigned char *) last)) { return (-1); } if (len > 0) { memcpy (dst, src, len); } if (pinc != NULL) { *pinc = (unsigned char *) *pinc + len; } return (len); } static int _pack (void **pdst, void *src, int len, const void *last) { /* Packs the [src] data of [len] bytes into [dst] using MSBF. * If [last] is non-NULL, checks to ensure [len] bytes * of [dst] data resides prior to the [last] valid byte. * Returns the number of bytes copied into [dst]. * On success (ie, > 0), the [dst] ptr is advanced by [len]. */ void *dst; uint16_t u16; uint32_t u32; assert (pdst != NULL); assert (src != NULL); dst = *pdst; if (last && ((unsigned char *) dst + len > (unsigned char *) last)) { return (0); } switch (len) { case (sizeof (uint8_t)): * (uint8_t *) dst = * (uint8_t *) src; break; case (sizeof (uint16_t)): u16 = htons (* (uint16_t *) src); memcpy (dst, &u16, len); break; case (sizeof (uint32_t)): u32 = htonl (* (uint32_t *) src); memcpy (dst, &u32, len); break; default: return (0); } *pdst = (unsigned char *) dst + len; return (len); } static int _unpack (void *dst, void **psrc, int len, const void *last) { /* Unpacks the MSBF [src] data of [len] bytes into [dst]. * If [last] is non-NULL, checks to ensure [len] bytes * of [src] data resides prior to the [last] valid byte. * Returns the number of bytes copied into [dst]. * On success (ie, > 0), the [src] ptr is advanced by [len]. */ void *src; uint16_t u16; uint32_t u32; assert (dst != NULL); assert (psrc != NULL); src = *psrc; if (last && ((unsigned char *) src + len > (unsigned char *) last)) { return (0); } switch (len) { case (sizeof (uint8_t)): * (uint8_t *) dst = * (uint8_t *) src; break; case (sizeof (uint16_t)): memcpy (&u16, src, len); * (uint16_t *) dst = ntohs (u16); break; case (sizeof (uint32_t)): memcpy (&u32, src, len); * (uint32_t *) dst = ntohl (u32); break; default: return (0); } *psrc = (unsigned char *) src + len; return (len); } munge-munge-0.5.15/src/libcommon/m_msg.h000066400000000000000000000153271425467526100200730ustar00rootroot00000000000000/***************************************************************************** * Written by Chris Dunlap . * Copyright (C) 2007-2022 Lawrence Livermore National Security, LLC. * Copyright (C) 2002-2007 The Regents of the University of California. * UCRL-CODE-155910. * * This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE). * For details, see . * * MUNGE 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. Additionally for the MUNGE library (libmunge), you * can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation, * either version 3 of the License, or (at your option) any later version. * * MUNGE 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 * and GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * and GNU Lesser General Public License along with MUNGE. If not, see * . *****************************************************************************/ #ifndef M_MSG_H #define M_MSG_H #if HAVE_CONFIG_H # include "config.h" #endif /* HAVE_CONFIG_H */ #include #include #include /* for struct in_addr */ /***************************************************************************** * Constants *****************************************************************************/ /* Length of the munge message header (in bytes): * magic + version + type + retry + pkt_len. */ #define MUNGE_MSG_HDR_SIZE 11 /* Sentinel for a valid munge message. * M (13*26^4) + U (21*26^3) + N (14*26^2) + G (7*26^1) + E (5*26^0) */ #define MUNGE_MSG_MAGIC 0x00606D4B /* Current version of the munge client-server message format. * This must be incremented whenever the client/server msg format changes; * otherwise, the message may be parsed incorrectly when decoded. */ #define MUNGE_MSG_VERSION 4 /***************************************************************************** * Data Types *****************************************************************************/ enum m_msg_type { /* message type */ MUNGE_MSG_UNDEF, /* undefined (new) message */ MUNGE_MSG_HDR, /* message header */ MUNGE_MSG_ENC_REQ, /* encode request message */ MUNGE_MSG_ENC_RSP, /* encode response message */ MUNGE_MSG_DEC_REQ, /* decode request message */ MUNGE_MSG_DEC_RSP, /* decode response message */ MUNGE_MSG_AUTH_FD_REQ /* auth via fd request message */ }; struct m_msg { int sd; /* munge socket descriptor */ uint8_t type; /* enum m_msg_type */ uint8_t retry; /* retry count for this transaction */ uint32_t pkt_len; /* length of msg pkt mem allocation */ void *pkt; /* ptr to msg for xfer over socket */ uint8_t cipher; /* munge_cipher_t enum */ uint8_t mac; /* munge_mac_t enum */ uint8_t zip; /* munge_zip_t enum */ uint8_t realm_len; /* length of realm string with NUL */ char *realm_str; /* security realm string with NUL */ uint32_t ttl; /* time-to-live */ uint8_t addr_len; /* length of IP address */ struct in_addr addr; /* IP addr where cred was encoded */ uint32_t time0; /* time at which cred was encoded */ uint32_t time1; /* time at which cred was decoded */ uint32_t client_uid; /* UID of connecting client process */ uint32_t client_gid; /* GID of connecting client process */ uint32_t cred_uid; /* UID of client that requested cred */ uint32_t cred_gid; /* GID of client that requested cred */ uint32_t auth_uid; /* UID of client allowed to decode */ uint32_t auth_gid; /* GID of client allowed to decode */ uint32_t data_len; /* length of data */ void *data; /* ptr to data munged into cred */ uint32_t auth_s_len; /* length of auth srvr string w/ NUL */ char *auth_s_str; /* auth srvr path name string w/ NUL */ uint32_t auth_c_len; /* length of auth clnt string w/ NUL */ char *auth_c_str; /* auth clnt dir name string w/ NUL */ uint8_t error_num; /* munge_err_t for encode/decode op */ uint8_t error_len; /* length of err msg str with NUL */ char *error_str; /* descriptive err msg str with NUL */ unsigned pkt_is_copy:1; /* true if mem for pkt is a copy */ unsigned realm_is_copy:1; /* true if mem for realm is a copy */ unsigned data_is_copy:1; /* true if mem for data is a copy */ unsigned error_is_copy:1; /* true if mem for err str is a copy */ unsigned auth_s_is_copy:1;/* true if mem for auth srvr is copy */ unsigned auth_c_is_copy:1;/* true if mem for auth clnt is copy */ }; typedef struct m_msg * m_msg_t; typedef enum m_msg_type m_msg_type_t; typedef uint32_t m_msg_magic_t; typedef uint8_t m_msg_version_t; /***************************************************************************** * Prototypes *****************************************************************************/ munge_err_t m_msg_create (m_msg_t *pm); void m_msg_destroy (m_msg_t m); void m_msg_reset (m_msg_t m); munge_err_t m_msg_bind (m_msg_t m, int sd); munge_err_t m_msg_send (m_msg_t m, m_msg_type_t type, int maxlen); munge_err_t m_msg_recv (m_msg_t m, m_msg_type_t type, int maxlen); int m_msg_set_err (m_msg_t m, munge_err_t e, char *s); #endif /* !M_MSG_H */ munge-munge-0.5.15/src/libcommon/munge.7.in000066400000000000000000000135161425467526100204260ustar00rootroot00000000000000.\"**************************************************************************** .\" Written by Chris Dunlap . .\" Copyright (C) 2007-2022 Lawrence Livermore National Security, LLC. .\" Copyright (C) 2002-2007 The Regents of the University of California. .\" UCRL-CODE-155910. .\" .\" This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE). .\" For details, see . .\" .\" MUNGE 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. Additionally for the MUNGE library (libmunge), you .\" can redistribute it and/or modify it under the terms of the GNU Lesser .\" General Public License as published by the Free Software Foundation, .\" either version 3 of the License, or (at your option) any later version. .\" .\" MUNGE 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 .\" and GNU Lesser General Public License for more details. .\" .\" You should have received a copy of the GNU General Public License .\" and GNU Lesser General Public License along with MUNGE. If not, see .\" . .\"**************************************************************************** .TH MUNGE 7 "@DATE@" "@PACKAGE@-@VERSION@" "MUNGE Uid 'N' Gid Emporium" .SH NAME munge \- MUNGE overview .SH INTRODUCTION MUNGE (MUNGE Uid 'N' Gid Emporium) is an authentication service for creating and validating user credentials. It is designed to be highly scalable for use in an HPC cluster environment. It provides a portable API for encoding the user's identity into a tamper-proof credential that can be obtained by an untrusted client and forwarded by untrusted intermediaries within a security realm. Clients within this realm can create and validate credentials without the use of root privileges, reserved ports, or platform-specific methods. .SH RATIONALE The need for MUNGE arose out of the HPC cluster environment. Consider the scenario in which a local daemon running on a login node receives a client request and forwards it on to remote daemons running on compute nodes within the cluster. Since the user has already logged on to the login node, the local daemon just needs a reliable means of ascertaining the UID and GID of the client process. Furthermore, the remote daemons need a mechanism to ensure the forwarded authentication data has not been subsequently altered. .PP A common solution to this problem is to use Unix domain sockets to determine the identity of the local client, and then forward this information on to remote hosts via trusted rsh connections. But this presents several new problems. First, there is no portable API for determining the identity of a client over a Unix domain socket. Second, rsh connections must originate from a reserved port; the limited number of reserved ports available on a given host directly limits scalability. Third, root privileges are required in order to bind to a reserved port. Finally, the remote daemons have no means of determining whether the client identity is authentic. MUNGE solves all of these problems. .SH USAGE A process creates a credential by requesting one from the local MUNGE service, either via the \fBmunge_encode\fR() C library call or the \fBmunge\fR executable. The encoded credential contains the UID and GID of the originating process. This process sends the credential to another process within the security realm as a means of proving its identity. The receiving process validates the credential with the use of its local MUNGE service, either via the \fBmunge_decode\fR() C library call or the \fBunmunge\fR executable. The decoded credential provides the receiving process with a reliable means of ascertaining the UID and GID of the originating process. This information can be used for accounting or access control decisions. .SH DETAILS The contents of the credential (including any optional payload data) are encrypted with a key shared by all \fBmunged\fR daemons within the security realm. The integrity of the credential is ensured by a message authentication code (MAC). The credential is valid for a limited time defined by its time-to-live (TTL); this presumes clocks within a security realm are in sync. Unexpired credentials are tracked by the local \fBmunged\fR daemon in order to prevent replay attacks on a given host. Decoding of a credential can be restricted to a particular user and/or group ID. The payload data can be used for purposes such as embedding the destination's address to ensure the credential is only valid on a specific host. The internal format of the credential is encoded in a platform-independent manner. And the credential itself is base64 encoded to allow it to be transmitted over virtually any transport. .SH AUTHOR Chris Dunlap .SH COPYRIGHT Copyright (C) 2007-2022 Lawrence Livermore National Security, LLC. .br Copyright (C) 2002-2007 The Regents of the University of California. .PP MUNGE 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. .PP Additionally for the MUNGE library (libmunge), you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. .SH "SEE ALSO" .BR munge (1), .BR remunge (1), .BR unmunge (1), .BR munge (3), .BR munge_ctx (3), .BR munge_enum (3), .BR munged (8), .BR mungekey (8). .PP \fBhttps://dun.github.io/munge/\fR munge-munge-0.5.15/src/libcommon/munge_defs.h000066400000000000000000000217341425467526100211040ustar00rootroot00000000000000/***************************************************************************** * Written by Chris Dunlap . * Copyright (C) 2007-2022 Lawrence Livermore National Security, LLC. * Copyright (C) 2002-2007 The Regents of the University of California. * UCRL-CODE-155910. * * This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE). * For details, see . * * MUNGE 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. Additionally for the MUNGE library (libmunge), you * can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation, * either version 3 of the License, or (at your option) any later version. * * MUNGE 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 * and GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * and GNU Lesser General Public License along with MUNGE. If not, see * . *****************************************************************************/ #ifndef MUNGE_DEFS_H #define MUNGE_DEFS_H #if HAVE_CONFIG_H # include "config.h" #endif /* HAVE_CONFIG_H */ #include /* MUNGE credential prefix string. */ #define MUNGE_CRED_PREFIX "MUNGE:" /* MUNGE credential suffix string. */ #define MUNGE_CRED_SUFFIX ":" /* Amount of salt (in bytes) encoded into a credential. */ #define MUNGE_CRED_SALT_LEN 8 /* Default munge_cipher_t for encrypting credentials. * * 2009-07-30: Do not default to MUNGE_CIPHER_AES256 since recent attacks show * it has a lower safety margin than AES128. Currently, AES128 has no known * attack which is faster than 2^128. However, the latest attack against * 11-round AES256 requires only 2^70; note that full AES256 has 14 rounds. * */ #if HAVE_OPENSSL && !HAVE_EVP_AES_128_CBC # define MUNGE_DEFAULT_CIPHER MUNGE_CIPHER_CAST5 #else /* !HAVE_OPENSSL || HAVE_EVP_AES_128_CBC */ # define MUNGE_DEFAULT_CIPHER MUNGE_CIPHER_AES128 #endif /* !HAVE_OPENSSL || HAVE_EVP_AES_128_CBC */ /* Default munge_mac_t for validating credentials. * This should NEVER be set to MUNGE_MAC_NONE. */ #if HAVE_OPENSSL && !HAVE_EVP_SHA256 # define MUNGE_DEFAULT_MAC MUNGE_MAC_SHA1 #else /* !HAVE_OPENSSL || HAVE_EVP_SHA256 */ # define MUNGE_DEFAULT_MAC MUNGE_MAC_SHA256 #endif /* !HAVE_OPENSSL || HAVE_EVP_SHA256 */ /* Default munge_zip_t for compressing credentials. * Compression incurs a substantial performance penalty. * Typical payloads are too small to achieve any compression. */ #define MUNGE_DEFAULT_ZIP MUNGE_ZIP_NONE /* Integer for the default number of seconds before a credential expires. */ #define MUNGE_DEFAULT_TTL 300 /* Integer for the maximum number of seconds before a credential expires. */ #define MUNGE_MAXIMUM_TTL 3600 /* Integer for the maximum size (in bytes) of a cipher block. */ #define MUNGE_MAXIMUM_BLK_LEN 16 /* Integer for the maximum size (in bytes) of a cipher key. */ #define MUNGE_MAXIMUM_KEY_LEN 32 /* Integer for the maximum size (in bytes) of a message digest (ie, SHA512). */ #define MUNGE_MAXIMUM_MD_LEN 64 /* Integer for the minimum size (in bytes) of a message digest (ie, MD5). */ #define MUNGE_MINIMUM_MD_LEN 16 /* Integer for the maximum size (in bytes) of a munge request message. */ #define MUNGE_MAXIMUM_REQ_LEN 1048576 /* Flag to denote whether group information comes from "/etc/group". * If set, group information will not be updated unless this file * modification time changes. If not set, the file modification time * will be ignored and group information will be updated via getgrent() * every time the "gids map" update timer expires. */ #define MUNGE_GROUP_STAT_FLAG 1 /* Integer for the number of seconds between updating group information. * If set to 0, the GIDs mapping will be computed initially but never updated. * If set to -1, the GIDs mapping will be disabled altogether. */ #define MUNGE_GROUP_UPDATE_SECS 3600 /* Integer for the number of seconds between purging the replay hash * of expired credentials. */ #define MUNGE_REPLAY_PURGE_SECS 60 /* Maximum number of milliseconds to wait for a process to terminate after * sending a signal. */ #define MUNGE_SIGNAL_WAIT_MSECS 5000 /* Number of milliseconds between checks to see whether a process has * terminated (i.e., kicked the bucket, shuffled off this mortal coil, * run down the curtain, and joined the bleedin' choir invisible). */ #define MUNGE_SIGNAL_CHECK_MSECS 25 /* Socket backlog for the server listening on the unix domain socket. */ #define MUNGE_SOCKET_BACKLOG 256 /* String specifying the unix domain socket pathname for client-server comms. * May be overridden in "config.h". */ #ifndef MUNGE_SOCKET_NAME #define MUNGE_SOCKET_NAME RUNSTATEDIR "/munge/munge.socket.2" #endif /* !MUNGE_SOCKET_NAME */ /* Number of attempts a client makes connecting to the server before failing. */ #define MUNGE_SOCKET_CONNECT_ATTEMPTS 10 /* Number of milliseconds for the start of the linear back-off where the * client sleeps between attempts at retrying a connection to the unix * domain socket. */ #define MUNGE_SOCKET_CONNECT_RETRY_MSECS 50 /* Flag to allow previously-decoded credentials to be retried. * If the client receives a socket error while communicating with the * server, it will retry the transaction up to MUNGE_SOCKET_RETRY_ATTEMPTS. * If such an error occurs after the credential has been inserted into the * replay hash, a subsequent retry will appear as a replayed credential. * If set, a previously-decoded credential will not be marked as being * replayed if the transaction is being retried. */ #define MUNGE_SOCKET_RETRY_FLAG 1 /* Number of attempts a client makes communicating with the server for a * given credential transaction before failing. */ #define MUNGE_SOCKET_RETRY_ATTEMPTS 5 /* Number of milliseconds for the start of the linear back-off where the * client sleeps between attempts at retrying a credential transaction. */ #define MUNGE_SOCKET_RETRY_MSECS 10 /* Number of milliseconds until a socket read/write is timed-out. */ #define MUNGE_SOCKET_TIMEOUT_MSECS 2000 /* Number of threads to create for processing credential requests. */ #define MUNGE_THREADS 2 /* Flag to allow root to decode any credential regardless of its * UID/GID restrictions. */ #define MUNGE_AUTH_ROOT_ALLOW_FLAG 0 /* The directory in which the pipe used to authenticate a particular client * via fd-passing will be created. The server must be able to create files * in this directory, but the client only needs to be able to read a file * from within it. Recommended permissions for this directory are 0711. */ #define MUNGE_AUTH_SERVER_DIR LOCALSTATEDIR "/lib/munge" /* The directory in which the file used to authenticate a particular client * via fd-passing will be created. The client must be able to create files * in this directory. Recommended permissions for this directory are 1733. */ #define MUNGE_AUTH_CLIENT_DIR "/tmp" /* The amount of entropy (in bytes) to place in the filename of the pipe and * file used to authenticate a particular client via fd-passing. */ #define MUNGE_AUTH_RND_BYTES 16 /* Integer for the default length (in bytes) of a key. */ #define MUNGE_KEY_LEN_DFL_BYTES 128 /* Integer for the maximum length (in bytes) of a key. * Note: Update src/mungekey/mungekey.8.in when changing this value. */ #define MUNGE_KEY_LEN_MAX_BYTES 1024 /* Integer for the minimum length (in bytes) of a key. * Note: Update src/mungekey/mungekey.8.in when changing this value. */ #define MUNGE_KEY_LEN_MIN_BYTES 32 /* String specifying the pathname of the daemon's keyfile. */ #define MUNGE_KEYFILE_PATH SYSCONFDIR "/munge/munge.key" /* String specifying the pathname of the daemon's logfile. */ #define MUNGE_LOGFILE_PATH LOCALSTATEDIR "/log/munge/munged.log" /* String specifying the pathname of the daemon's pidfile. */ #define MUNGE_PIDFILE_PATH RUNSTATEDIR "/munge/munged.pid" /* String specifying the pathname of the daemon's PRNG seedfile. */ #define MUNGE_SEEDFILE_PATH LOCALSTATEDIR "/lib/munge/munged.seed" #endif /* !MUNGE_DEFS_H */ munge-munge-0.5.15/src/libcommon/str.c000066400000000000000000000144401425467526100175670ustar00rootroot00000000000000/***************************************************************************** * Written by Chris Dunlap . * Copyright (C) 2007-2022 Lawrence Livermore National Security, LLC. * Copyright (C) 2002-2007 The Regents of the University of California. * UCRL-CODE-155910. * * This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE). * For details, see . * * MUNGE 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. Additionally for the MUNGE library (libmunge), you * can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation, * either version 3 of the License, or (at your option) any later version. * * MUNGE 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 * and GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * and GNU Lesser General Public License along with MUNGE. If not, see * . ***************************************************************************** * Refer to "str.h" for documentation on public functions. *****************************************************************************/ #if HAVE_CONFIG_H # include "config.h" #endif /* HAVE_CONFIG_H */ #include #include #include #include #include #include #include "str.h" #ifndef MAX_STR_SIZE # define MAX_STR_SIZE 1024 #endif /* !MAX_STR_SIZE */ /***************************************************************************** * Functions *****************************************************************************/ char * strdupf (const char *fmt, ...) { va_list vargs; char buf[MAX_STR_SIZE]; char *p; if (!fmt) { return (NULL); } va_start (vargs, fmt); vsnprintf (buf, sizeof (buf), fmt, vargs); va_end (vargs); buf[sizeof (buf) - 1] = '\0'; /* ensure buf is NUL-terminated */ if (!(p = strdup (buf))) { return (NULL); } return (p); } int strcatf (char *dst, size_t size, const char *fmt, ...) { va_list vargs; char *p; char *q; int n; int len; int nleft; if (!dst || !size) { return (0); } p = dst; q = dst + size; while ((*p) && (p < q)) { /* walk dst in case NUL not present */ p++; } len = p - dst; if (len >= size) { /* dst not NUL-terminated */ dst[size - 1] = '\0'; return (-1); } if (!fmt || !*fmt) { /* nothing to concatenate */ return (len); } nleft = size - len; if (nleft <= 1) { /* dst already full */ return (-1); } va_start (vargs, fmt); n = vsnprintf (p, nleft, fmt, vargs); va_end (vargs); if ((n < 0) || (n >= nleft)) { dst[size - 1] = '\0'; /* ensure dst is NUL-terminated */ return (-1); } return (len + n); } int strbin2hex (char *dst, size_t dstlen, const void *src, size_t srclen) { const char bin2hex[] = "0123456789ABCDEF"; char *pdst = dst; const char *psrc = src; int i; if (dstlen < ((srclen * 2) + 1)) { errno = EINVAL; return (0); } for (i = 0; i < srclen; i++) { *pdst++ = bin2hex[(psrc[i] >> 4) & 0x0f]; *pdst++ = bin2hex[(psrc[i] ) & 0x0f]; } *pdst = '\0'; return (pdst - (char *) dst); } int strhex2bin (void *dst, size_t dstlen, const char *src, size_t srclen) { char *pdst = dst; const char *psrc = src; int i; int c; int n; if (dstlen < (srclen + 1) / 2) { errno = EINVAL; return (0); } for (i = 0; i < srclen; i++) { c = psrc[i]; if ((c >= '0') && (c <= '9')) { n = c - '0'; } else if ((c >= 'A') && (c <= 'F')) { n = c - 'A' + 10; } else if ((c >= 'a') && (c <= 'f')) { n = c - 'a' + 10; } else { errno = EINVAL; return (0); } if (i % 2) { *pdst++ |= n & 0x0f; } else { *pdst = (n & 0x0f) << 4; } } return ((srclen + 1) / 2); } int strftimet (char *dst, size_t dstlen, const char *tfmt, time_t t) { #if HAVE_LOCALTIME_R struct tm tm; #endif /* !HAVE_LOCALTIME_R */ struct tm *tm_ptr; int n; if ((dst == NULL) || (dstlen == 0) || (tfmt == NULL)) { errno = EINVAL; return (-1); } if (t == 0) { if (time (&t) == ((time_t) -1)) { return (-1); } } #if HAVE_LOCALTIME_R tm_ptr = localtime_r (&t, &tm); #else /* !HAVE_LOCALTIME_R */ tm_ptr = localtime (&t); /* FIXME: protect with mutex? */ #endif /* !HAVE_LOCALTIME_R */ if (tm_ptr == NULL) { return (-1); } n = strftime (dst, dstlen, tfmt, tm_ptr); if ((n <= 0) || (n >= dstlen)) { /* On strftime() error, contents of 'dst' are undefined. */ return (0); } return (n); } void * memburn (void *v, int c, size_t n) { /* From David A. Wheeler's "Secure Programming for Linux and Unix HOWTO" * (section 11.4): * Many compilers, including many C/C++ compilers, remove writes to stores * that are no longer used -- this is often referred to as "dead store * removal". Unfortunately, if the write is really to overwrite the value * of a secret, this means that code that appears to be correct will be * silently discarded. * One approach that seems to work on all platforms is to write your own * implementation of memset with internal "volatilization" of the first * argument (this code is based on a workaround proposed by Michael Howard): */ volatile char *p = v; while (n--) { *p++ = c; } return (v); } munge-munge-0.5.15/src/libcommon/str.h000066400000000000000000000076261425467526100176040ustar00rootroot00000000000000/***************************************************************************** * Written by Chris Dunlap . * Copyright (C) 2007-2022 Lawrence Livermore National Security, LLC. * Copyright (C) 2002-2007 The Regents of the University of California. * UCRL-CODE-155910. * * This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE). * For details, see . * * MUNGE 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. Additionally for the MUNGE library (libmunge), you * can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation, * either version 3 of the License, or (at your option) any later version. * * MUNGE 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 * and GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * and GNU Lesser General Public License along with MUNGE. If not, see * . *****************************************************************************/ #ifndef STR_H #define STR_H #if HAVE_CONFIG_H # include "config.h" #endif /* HAVE_CONFIG_H */ #include #include char * strdupf (const char *fmt, ...); /* * Duplicates the string specified by the format-string [fmt]. * Returns the new string, or NULL if out of memory. * The caller is responsible for free()ing this new string. */ int strcatf (char *dst, size_t size, const char *fmt, ...); /* * Concatenates the string specified by the format-string [fmt] to * the NUL-terminated string [dst] within a buffer of size [size]. * Note that [size] is the full size of [dst], not the space remaining. * Returns the new length of the NUL-terminated string [dst], or -1 if * truncation occurred. The string in [dst] is guaranteed to be * NUL-terminated. */ int strbin2hex (char *dst, size_t dstlen, const void *src, size_t srclen); /* * Converts the buffer [src] of length [srclen] into a NUL-terminated * hexadecimal string, storing the result in the buffer [dst] of * length [dstlen]. * Returns the length of the NUL-terminated string [dst], or 0 if the * buffer [dst] is too small (ie, less than ((srclen * 2) + 1) bytes). */ int strhex2bin (void *dst, size_t dstlen, const char *src, size_t srclen); /* * Converts the first [srclen] characters of the hexadecimal string [src] * into a binary representation, storing the result in the buffer [dst] * of length [dstlen]. * Returns the number of bytes of binary data in [dst], or 0 on error -- * if the buffer [dst] is too small (ie, less than ((srclen + 1) / 2) bytes) * or contains non-hexadecimal digits. */ int strftimet (char *dst, size_t dstlen, const char *tfmt, time_t t); /* * Formats the time [t] to the local time according to the strftime() * format [tfmt], storing the resulting string in the buffer [dst] of * length [dstlen]. * Returns the length of the NUL-terminated string [dst], -1 on error * (with errno set), or 0 if truncation occurred. Upon success (ie, >0), * the string in [dst] is guaranteed to be NUL-terminated. * If [t] is 0, the current time will be used. */ void * memburn (void *v, int c, size_t n); /* * Implementation of memset to prevent "dead store removal" optimization, * thereby ensuring secrets are overwritten. * Fills the first [n] bytes of the memory area pointed to by [v] * with the constant byte [c]. * Returns a pointer to the memory area [v]. */ #endif /* !STR_H */ munge-munge-0.5.15/src/libcommon/version.c000066400000000000000000000032411425467526100204410ustar00rootroot00000000000000/***************************************************************************** * Written by Chris Dunlap . * Copyright (C) 2007-2022 Lawrence Livermore National Security, LLC. * Copyright (C) 2002-2007 The Regents of the University of California. * UCRL-CODE-155910. * * This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE). * For details, see . * * MUNGE 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. Additionally for the MUNGE library (libmunge), you * can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation, * either version 3 of the License, or (at your option) any later version. * * MUNGE 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 * and GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * and GNU Lesser General Public License along with MUNGE. If not, see * . *****************************************************************************/ #if HAVE_CONFIG_H # include "config.h" #endif /* HAVE_CONFIG_H */ #include #include "version.h" void display_version (void) { printf ("%s-%s (%s)\n", PACKAGE, VERSION, DATE); return; } munge-munge-0.5.15/src/libcommon/version.h000066400000000000000000000031011425467526100204410ustar00rootroot00000000000000/***************************************************************************** * Written by Chris Dunlap . * Copyright (C) 2007-2022 Lawrence Livermore National Security, LLC. * Copyright (C) 2002-2007 The Regents of the University of California. * UCRL-CODE-155910. * * This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE). * For details, see . * * MUNGE 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. Additionally for the MUNGE library (libmunge), you * can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation, * either version 3 of the License, or (at your option) any later version. * * MUNGE 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 * and GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * and GNU Lesser General Public License along with MUNGE. If not, see * . *****************************************************************************/ #ifndef MUNGE_VERSION_H #define MUNGE_VERSION_H void display_version (void); #endif /* !MUNGE_VERSION_H */ munge-munge-0.5.15/src/libmissing/000077500000000000000000000000001425467526100167715ustar00rootroot00000000000000munge-munge-0.5.15/src/libmissing/Makefile.am000066400000000000000000000011221425467526100210210ustar00rootroot00000000000000# MUNGE src/libmissing/Makefile.am # # This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE). # For details, see . include $(top_srcdir)/Make-inc.mk noinst_LTLIBRARIES = \ libmissing.la \ # End of noinst_LTLIBRARIES libmissing_la_LIBADD = \ $(LTLIBOBJS) \ # End of libmissing_la_LIBADD libmissing_la_SOURCES = \ getopt.h \ getopt.c \ getopt1.c \ missing.h \ # End of libmissing_la_SOURCES EXTRA_libmissing_la_SOURCES = \ inet_ntop.h \ strlcat.h \ strlcpy.h \ # End of EXTRA_libmissing_la_SOURCES EXTRA_DIST = \ URL \ # End of EXTRA_DIST munge-munge-0.5.15/src/libmissing/URL000066400000000000000000000000671425467526100173610ustar00rootroot00000000000000ftp://ftp.openbsd.org/pub/OpenBSD/src/lib/libc/string/ munge-munge-0.5.15/src/libmissing/getopt.c000066400000000000000000001033041425467526100204400ustar00rootroot00000000000000/* Getopt for GNU. NOTE: getopt is now part of the C library, so if you don't know what "Keep this file name-space clean" means, talk to drepper@gnu.org before changing it! Copyright (C) 1987,88,89,90,91,92,93,94,95,96,98,99,2000,2001,2002 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. The GNU C Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with the GNU C Library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ /* This tells Alpha OSF/1 not to define a getopt prototype in . Ditto for AIX 3.2 and . */ #ifndef _NO_PROTO # define _NO_PROTO #endif #ifdef HAVE_CONFIG_H # include #endif #if !defined __STDC__ || !__STDC__ /* This is a separate conditional since some stdc systems reject `defined (const)'. */ # ifndef const # define const # endif #endif #include /* Comment out all this code if we are using the GNU C Library, and are not actually compiling the library itself. This code is part of the GNU C Library, but also included in many other GNU distributions. Compiling and linking in this code is a waste when using the GNU C library (especially if it is a shared library). Rather than having every GNU program understand `configure --with-gnu-libc' and omit the object files, it is simpler to just do this in the source for each such file. */ #define GETOPT_INTERFACE_VERSION 2 #if !defined _LIBC && defined __GLIBC__ && __GLIBC__ >= 2 # include # if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION # define ELIDE_CODE # endif #endif #ifndef ELIDE_CODE /* This needs to come after some library #include to get __GNU_LIBRARY__ defined. */ #ifdef __GNU_LIBRARY__ /* Don't include stdlib.h for non-GNU C libraries because some of them contain conflicting prototypes for getopt. */ # include # include #endif /* GNU C library. */ #ifdef VMS # include # if HAVE_STRING_H - 0 # include # endif #endif #ifndef _ /* This is for other GNU distributions with internationalized messages. */ # if (HAVE_LIBINTL_H && ENABLE_NLS) || defined _LIBC # include # ifndef _ # define _(msgid) gettext (msgid) # endif # else # define _(msgid) (msgid) # endif # if defined _LIBC && defined USE_IN_LIBIO # include # endif #endif #ifndef attribute_hidden # define attribute_hidden #endif /* This version of `getopt' appears to the caller like standard Unix `getopt' but it behaves differently for the user, since it allows the user to intersperse the options with the other arguments. As `getopt' works, it permutes the elements of ARGV so that, when it is done, all the options precede everything else. Thus all application programs are extended to handle flexible argument order. Setting the environment variable POSIXLY_CORRECT disables permutation. Then the behavior is completely standard. GNU application programs can use a third alternative mode in which they can distinguish the relative order of options and other arguments. */ #include "getopt.h" /* For communication from `getopt' to the caller. When `getopt' finds an option that takes an argument, the argument value is returned here. Also, when `ordering' is RETURN_IN_ORDER, each non-option ARGV-element is returned here. */ char *optarg; /* Index in ARGV of the next element to be scanned. This is used for communication to and from the caller and for communication between successive calls to `getopt'. On entry to `getopt', zero means this is the first call; initialize. When `getopt' returns -1, this is the index of the first of the non-option elements that the caller should itself scan. Otherwise, `optind' communicates from one call to the next how much of ARGV has been scanned so far. */ /* 1003.2 says this must be 1 before any call. */ int optind = 1; /* Formerly, initialization of getopt depended on optind==0, which causes problems with re-calling getopt as programs generally don't know that. */ int __getopt_initialized attribute_hidden; /* The next char to be scanned in the option-element in which the last option character we returned was found. This allows us to pick up the scan where we left off. If this is zero, or a null string, it means resume the scan by advancing to the next ARGV-element. */ static char *nextchar; /* Callers store zero here to inhibit the error message for unrecognized options. */ int opterr = 1; /* Set to an option character which was unrecognized. This must be initialized on some systems to avoid linking in the system's own getopt implementation. */ int optopt = '?'; /* Describe how to deal with options that follow non-option ARGV-elements. If the caller did not specify anything, the default is REQUIRE_ORDER if the environment variable POSIXLY_CORRECT is defined, PERMUTE otherwise. REQUIRE_ORDER means don't recognize them as options; stop option processing when the first non-option is seen. This is what Unix does. This mode of operation is selected by either setting the environment variable POSIXLY_CORRECT, or using `+' as the first character of the list of option characters. PERMUTE is the default. We permute the contents of ARGV as we scan, so that eventually all the non-options are at the end. This allows options to be given in any order, even with programs that were not written to expect this. RETURN_IN_ORDER is an option available to programs that were written to expect options and other ARGV-elements in any order and that care about the ordering of the two. We describe each non-option ARGV-element as if it were the argument of an option with character code 1. Using `-' as the first character of the list of option characters selects this mode of operation. The special argument `--' forces an end of option-scanning regardless of the value of `ordering'. In the case of RETURN_IN_ORDER, only `--' can cause `getopt' to return -1 with `optind' != ARGC. */ static enum { REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER } ordering; /* Value of POSIXLY_CORRECT environment variable. */ static char *posixly_correct; #ifdef __GNU_LIBRARY__ /* We want to avoid inclusion of string.h with non-GNU libraries because there are many ways it can cause trouble. On some systems, it contains special magic macros that don't work in GCC. */ # include # define my_index strchr #else # if HAVE_STRING_H # include # else # include # endif /* Avoid depending on library functions or files whose names are inconsistent. */ #ifndef getenv extern char *getenv (); #endif static char * my_index (str, chr) const char *str; int chr; { while (*str) { if (*str == chr) return (char *) str; str++; } return 0; } /* If using GCC, we can safely declare strlen this way. If not using GCC, it is ok not to declare it. */ #ifdef __GNUC__ /* Note that Motorola Delta 68k R3V7 comes with GCC but not stddef.h. That was relevant to code that was here before. */ # if (!defined __STDC__ || !__STDC__) && !defined strlen /* gcc with -traditional declares the built-in strlen to return int, and has done so at least since version 2.4.5. -- rms. */ extern int strlen (const char *); # endif /* not __STDC__ */ #endif /* __GNUC__ */ #endif /* not __GNU_LIBRARY__ */ /* Handle permutation of arguments. */ /* Describe the part of ARGV that contains non-options that have been skipped. `first_nonopt' is the index in ARGV of the first of them; `last_nonopt' is the index after the last of them. */ static int first_nonopt; static int last_nonopt; #ifdef _LIBC /* Stored original parameters. XXX This is no good solution. We should rather copy the args so that we can compare them later. But we must not use malloc(3). */ extern int __libc_argc; extern char **__libc_argv; /* Bash 2.0 gives us an environment variable containing flags indicating ARGV elements that should not be considered arguments. */ # ifdef USE_NONOPTION_FLAGS /* Defined in getopt_init.c */ extern char *__getopt_nonoption_flags; static int nonoption_flags_max_len; static int nonoption_flags_len; # endif # ifdef USE_NONOPTION_FLAGS # define SWAP_FLAGS(ch1, ch2) \ if (nonoption_flags_len > 0) \ { \ char __tmp = __getopt_nonoption_flags[ch1]; \ __getopt_nonoption_flags[ch1] = __getopt_nonoption_flags[ch2]; \ __getopt_nonoption_flags[ch2] = __tmp; \ } # else # define SWAP_FLAGS(ch1, ch2) # endif #else /* !_LIBC */ # define SWAP_FLAGS(ch1, ch2) #endif /* _LIBC */ /* Exchange two adjacent subsequences of ARGV. One subsequence is elements [first_nonopt,last_nonopt) which contains all the non-options that have been skipped so far. The other is elements [last_nonopt,optind), which contains all the options processed since those non-options were skipped. `first_nonopt' and `last_nonopt' are relocated so that they describe the new indices of the non-options in ARGV after they are moved. */ #if defined __STDC__ && __STDC__ static void exchange (char **); #endif static void exchange (argv) char **argv; { int bottom = first_nonopt; int middle = last_nonopt; int top = optind; char *tem; /* Exchange the shorter segment with the far end of the longer segment. That puts the shorter segment into the right place. It leaves the longer segment in the right place overall, but it consists of two parts that need to be swapped next. */ #if defined _LIBC && defined USE_NONOPTION_FLAGS /* First make sure the handling of the `__getopt_nonoption_flags' string can work normally. Our top argument must be in the range of the string. */ if (nonoption_flags_len > 0 && top >= nonoption_flags_max_len) { /* We must extend the array. The user plays games with us and presents new arguments. */ char *new_str = malloc (top + 1); if (new_str == NULL) nonoption_flags_len = nonoption_flags_max_len = 0; else { memset (__mempcpy (new_str, __getopt_nonoption_flags, nonoption_flags_max_len), '\0', top + 1 - nonoption_flags_max_len); nonoption_flags_max_len = top + 1; __getopt_nonoption_flags = new_str; } } #endif while (top > middle && middle > bottom) { if (top - middle > middle - bottom) { /* Bottom segment is the short one. */ int len = middle - bottom; register int i; /* Swap it with the top part of the top segment. */ for (i = 0; i < len; i++) { tem = argv[bottom + i]; argv[bottom + i] = argv[top - (middle - bottom) + i]; argv[top - (middle - bottom) + i] = tem; SWAP_FLAGS (bottom + i, top - (middle - bottom) + i); } /* Exclude the moved bottom segment from further swapping. */ top -= len; } else { /* Top segment is the short one. */ int len = top - middle; register int i; /* Swap it with the bottom part of the bottom segment. */ for (i = 0; i < len; i++) { tem = argv[bottom + i]; argv[bottom + i] = argv[middle + i]; argv[middle + i] = tem; SWAP_FLAGS (bottom + i, middle + i); } /* Exclude the moved top segment from further swapping. */ bottom += len; } } /* Update records for the slots the non-options now occupy. */ first_nonopt += (optind - last_nonopt); last_nonopt = optind; } /* Initialize the internal data when the first call is made. */ #if defined __STDC__ && __STDC__ static const char *_getopt_initialize (int, char *const *, const char *); #endif static const char * _getopt_initialize (argc, argv, optstring) int argc; char *const *argv; const char *optstring; { /* Start processing options with ARGV-element 1 (since ARGV-element 0 is the program name); the sequence of previously skipped non-option ARGV-elements is empty. */ first_nonopt = last_nonopt = optind; nextchar = NULL; posixly_correct = getenv ("POSIXLY_CORRECT"); /* Determine how to handle the ordering of options and nonoptions. */ if (optstring[0] == '-') { ordering = RETURN_IN_ORDER; ++optstring; } else if (optstring[0] == '+') { ordering = REQUIRE_ORDER; ++optstring; } else if (posixly_correct != NULL) ordering = REQUIRE_ORDER; else ordering = PERMUTE; #if defined _LIBC && defined USE_NONOPTION_FLAGS if (posixly_correct == NULL && argc == __libc_argc && argv == __libc_argv) { if (nonoption_flags_max_len == 0) { if (__getopt_nonoption_flags == NULL || __getopt_nonoption_flags[0] == '\0') nonoption_flags_max_len = -1; else { const char *orig_str = __getopt_nonoption_flags; int len = nonoption_flags_max_len = strlen (orig_str); if (nonoption_flags_max_len < argc) nonoption_flags_max_len = argc; __getopt_nonoption_flags = (char *) malloc (nonoption_flags_max_len); if (__getopt_nonoption_flags == NULL) nonoption_flags_max_len = -1; else memset (__mempcpy (__getopt_nonoption_flags, orig_str, len), '\0', nonoption_flags_max_len - len); } } nonoption_flags_len = nonoption_flags_max_len; } else nonoption_flags_len = 0; #endif return optstring; } /* Scan elements of ARGV (whose length is ARGC) for option characters given in OPTSTRING. If an element of ARGV starts with '-', and is not exactly "-" or "--", then it is an option element. The characters of this element (aside from the initial '-') are option characters. If `getopt' is called repeatedly, it returns successively each of the option characters from each of the option elements. If `getopt' finds another option character, it returns that character, updating `optind' and `nextchar' so that the next call to `getopt' can resume the scan with the following option character or ARGV-element. If there are no more option characters, `getopt' returns -1. Then `optind' is the index in ARGV of the first ARGV-element that is not an option. (The ARGV-elements have been permuted so that those that are not options now come last.) OPTSTRING is a string containing the legitimate option characters. If an option character is seen that is not listed in OPTSTRING, return '?' after printing an error message. If you set `opterr' to zero, the error message is suppressed but we still return '?'. If a char in OPTSTRING is followed by a colon, that means it wants an arg, so the following text in the same ARGV-element, or the text of the following ARGV-element, is returned in `optarg'. Two colons mean an option that wants an optional arg; if there is text in the current ARGV-element, it is returned in `optarg', otherwise `optarg' is set to zero. If OPTSTRING starts with `-' or `+', it requests different methods of handling the non-option ARGV-elements. See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above. Long-named options begin with `--' instead of `-'. Their names may be abbreviated as long as the abbreviation is unique or is an exact match for some defined option. If they have an argument, it follows the option name in the same ARGV-element, separated from the option name by a `=', or else the in next ARGV-element. When `getopt' finds a long-named option, it returns 0 if that option's `flag' field is nonzero, the value of the option's `val' field if the `flag' field is zero. The elements of ARGV aren't really const, because we permute them. But we pretend they're const in the prototype to be compatible with other systems. LONGOPTS is a vector of `struct option' terminated by an element containing a name which is zero. LONGIND returns the index in LONGOPT of the long-named option found. It is only valid when a long-named option has been found by the most recent call. If LONG_ONLY is nonzero, '-' as well as '--' can introduce long-named options. */ int _getopt_internal (argc, argv, optstring, longopts, longind, long_only) int argc; char *const *argv; const char *optstring; const struct option *longopts; int *longind; int long_only; { int print_errors = opterr; if (optstring[0] == ':') print_errors = 0; if (argc < 1) return -1; optarg = NULL; if (optind == 0 || !__getopt_initialized) { if (optind == 0) optind = 1; /* Don't scan ARGV[0], the program name. */ optstring = _getopt_initialize (argc, argv, optstring); __getopt_initialized = 1; } /* Test whether ARGV[optind] points to a non-option argument. Either it does not have option syntax, or there is an environment flag from the shell indicating it is not an option. The later information is only used when the used in the GNU libc. */ #if defined _LIBC && defined USE_NONOPTION_FLAGS # define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0' \ || (optind < nonoption_flags_len \ && __getopt_nonoption_flags[optind] == '1')) #else # define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0') #endif if (nextchar == NULL || *nextchar == '\0') { /* Advance to the next ARGV-element. */ /* Give FIRST_NONOPT & LAST_NONOPT rational values if OPTIND has been moved back by the user (who may also have changed the arguments). */ if (last_nonopt > optind) last_nonopt = optind; if (first_nonopt > optind) first_nonopt = optind; if (ordering == PERMUTE) { /* If we have just processed some options following some non-options, exchange them so that the options come first. */ if (first_nonopt != last_nonopt && last_nonopt != optind) exchange ((char **) argv); else if (last_nonopt != optind) first_nonopt = optind; /* Skip any additional non-options and extend the range of non-options previously skipped. */ while (optind < argc && NONOPTION_P) optind++; last_nonopt = optind; } /* The special ARGV-element `--' means premature end of options. Skip it like a null option, then exchange with previous non-options as if it were an option, then skip everything else like a non-option. */ if (optind != argc && !strcmp (argv[optind], "--")) { optind++; if (first_nonopt != last_nonopt && last_nonopt != optind) exchange ((char **) argv); else if (first_nonopt == last_nonopt) first_nonopt = optind; last_nonopt = argc; optind = argc; } /* If we have done all the ARGV-elements, stop the scan and back over any non-options that we skipped and permuted. */ if (optind == argc) { /* Set the next-arg-index to point at the non-options that we previously skipped, so the caller will digest them. */ if (first_nonopt != last_nonopt) optind = first_nonopt; return -1; } /* If we have come to a non-option and did not permute it, either stop the scan or describe it to the caller and pass it by. */ if (NONOPTION_P) { if (ordering == REQUIRE_ORDER) return -1; optarg = argv[optind++]; return 1; } /* We have found another option-ARGV-element. Skip the initial punctuation. */ nextchar = (argv[optind] + 1 + (longopts != NULL && argv[optind][1] == '-')); } /* Decode the current option-ARGV-element. */ /* Check whether the ARGV-element is a long option. If long_only and the ARGV-element has the form "-f", where f is a valid short option, don't consider it an abbreviated form of a long option that starts with f. Otherwise there would be no way to give the -f short option. On the other hand, if there's a long option "fubar" and the ARGV-element is "-fu", do consider that an abbreviation of the long option, just like "--fu", and not "-f" with arg "u". This distinction seems to be the most useful approach. */ if (longopts != NULL && (argv[optind][1] == '-' || (long_only && (argv[optind][2] || !my_index (optstring, argv[optind][1]))))) { char *nameend; const struct option *p; const struct option *pfound = NULL; int exact = 0; int ambig = 0; int indfound = -1; int option_index; for (nameend = nextchar; *nameend && *nameend != '='; nameend++) /* Do nothing. */ ; /* Test all long options for either exact match or abbreviated matches. */ for (p = longopts, option_index = 0; p->name; p++, option_index++) if (!strncmp (p->name, nextchar, nameend - nextchar)) { if ((unsigned int) (nameend - nextchar) == (unsigned int) strlen (p->name)) { /* Exact match found. */ pfound = p; indfound = option_index; exact = 1; break; } else if (pfound == NULL) { /* First nonexact match found. */ pfound = p; indfound = option_index; } else if (long_only || pfound->has_arg != p->has_arg || pfound->flag != p->flag || pfound->val != p->val) /* Second or later nonexact match found. */ ambig = 1; } if (ambig && !exact) { if (print_errors) { #if defined _LIBC && defined USE_IN_LIBIO char *buf; if (__asprintf (&buf, _("%s: option `%s' is ambiguous\n"), argv[0], argv[optind]) >= 0) { if (_IO_fwide (stderr, 0) > 0) __fwprintf (stderr, L"%s", buf); else fputs (buf, stderr); free (buf); } #else fprintf (stderr, _("%s: option `%s' is ambiguous\n"), argv[0], argv[optind]); #endif } nextchar += strlen (nextchar); optind++; optopt = 0; return '?'; } if (pfound != NULL) { option_index = indfound; optind++; if (*nameend) { /* Don't test has_arg with >, because some C compilers don't allow it to be used on enums. */ if (pfound->has_arg) optarg = nameend + 1; else { if (print_errors) { #if defined _LIBC && defined USE_IN_LIBIO char *buf; int n; #endif if (argv[optind - 1][1] == '-') { /* --option */ #if defined _LIBC && defined USE_IN_LIBIO n = __asprintf (&buf, _("\ %s: option `--%s' doesn't allow an argument\n"), argv[0], pfound->name); #else fprintf (stderr, _("\ %s: option `--%s' doesn't allow an argument\n"), argv[0], pfound->name); #endif } else { /* +option or -option */ #if defined _LIBC && defined USE_IN_LIBIO n = __asprintf (&buf, _("\ %s: option `%c%s' doesn't allow an argument\n"), argv[0], argv[optind - 1][0], pfound->name); #else fprintf (stderr, _("\ %s: option `%c%s' doesn't allow an argument\n"), argv[0], argv[optind - 1][0], pfound->name); #endif } #if defined _LIBC && defined USE_IN_LIBIO if (n >= 0) { if (_IO_fwide (stderr, 0) > 0) __fwprintf (stderr, L"%s", buf); else fputs (buf, stderr); free (buf); } #endif } nextchar += strlen (nextchar); optopt = pfound->val; return '?'; } } else if (pfound->has_arg == 1) { if (optind < argc) optarg = argv[optind++]; else { if (print_errors) { #if defined _LIBC && defined USE_IN_LIBIO char *buf; if (__asprintf (&buf, _("\ %s: option `%s' requires an argument\n"), argv[0], argv[optind - 1]) >= 0) { if (_IO_fwide (stderr, 0) > 0) __fwprintf (stderr, L"%s", buf); else fputs (buf, stderr); free (buf); } #else fprintf (stderr, _("%s: option `%s' requires an argument\n"), argv[0], argv[optind - 1]); #endif } nextchar += strlen (nextchar); optopt = pfound->val; return optstring[0] == ':' ? ':' : '?'; } } nextchar += strlen (nextchar); if (longind != NULL) *longind = option_index; if (pfound->flag) { *(pfound->flag) = pfound->val; return 0; } return pfound->val; } /* Can't find it as a long option. If this is not getopt_long_only, or the option starts with '--' or is not a valid short option, then it's an error. Otherwise interpret it as a short option. */ if (!long_only || argv[optind][1] == '-' || my_index (optstring, *nextchar) == NULL) { if (print_errors) { #if defined _LIBC && defined USE_IN_LIBIO char *buf; int n; #endif if (argv[optind][1] == '-') { /* --option */ #if defined _LIBC && defined USE_IN_LIBIO n = __asprintf (&buf, _("%s: unrecognized option `--%s'\n"), argv[0], nextchar); #else fprintf (stderr, _("%s: unrecognized option `--%s'\n"), argv[0], nextchar); #endif } else { /* +option or -option */ #if defined _LIBC && defined USE_IN_LIBIO n = __asprintf (&buf, _("%s: unrecognized option `%c%s'\n"), argv[0], argv[optind][0], nextchar); #else fprintf (stderr, _("%s: unrecognized option `%c%s'\n"), argv[0], argv[optind][0], nextchar); #endif } #if defined _LIBC && defined USE_IN_LIBIO if (n >= 0) { if (_IO_fwide (stderr, 0) > 0) __fwprintf (stderr, L"%s", buf); else fputs (buf, stderr); free (buf); } #endif } nextchar = (char *) ""; optind++; optopt = 0; return '?'; } } /* Look at and handle the next short option-character. */ { char c = *nextchar++; char *temp = my_index (optstring, c); /* Increment `optind' when we start to process its last character. */ if (*nextchar == '\0') ++optind; if (temp == NULL || c == ':') { if (print_errors) { #if defined _LIBC && defined USE_IN_LIBIO char *buf; int n; #endif if (posixly_correct) { /* 1003.2 specifies the format of this message. */ #if defined _LIBC && defined USE_IN_LIBIO n = __asprintf (&buf, _("%s: illegal option -- %c\n"), argv[0], c); #else fprintf (stderr, _("%s: illegal option -- %c\n"), argv[0], c); #endif } else { #if defined _LIBC && defined USE_IN_LIBIO n = __asprintf (&buf, _("%s: invalid option -- %c\n"), argv[0], c); #else fprintf (stderr, _("%s: invalid option -- %c\n"), argv[0], c); #endif } #if defined _LIBC && defined USE_IN_LIBIO if (n >= 0) { if (_IO_fwide (stderr, 0) > 0) __fwprintf (stderr, L"%s", buf); else fputs (buf, stderr); free (buf); } #endif } optopt = c; return '?'; } /* Convenience. Treat POSIX -W foo same as long option --foo */ if (temp[0] == 'W' && temp[1] == ';') { char *nameend; const struct option *p; const struct option *pfound = NULL; int exact = 0; int ambig = 0; int indfound = 0; int option_index; /* This is an option that requires an argument. */ if (*nextchar != '\0') { optarg = nextchar; /* If we end this ARGV-element by taking the rest as an arg, we must advance to the next element now. */ optind++; } else if (optind == argc) { if (print_errors) { /* 1003.2 specifies the format of this message. */ #if defined _LIBC && defined USE_IN_LIBIO char *buf; if (__asprintf (&buf, _("%s: option requires an argument -- %c\n"), argv[0], c) >= 0) { if (_IO_fwide (stderr, 0) > 0) __fwprintf (stderr, L"%s", buf); else fputs (buf, stderr); free (buf); } #else fprintf (stderr, _("%s: option requires an argument -- %c\n"), argv[0], c); #endif } optopt = c; if (optstring[0] == ':') c = ':'; else c = '?'; return c; } else /* We already incremented `optind' once; increment it again when taking next ARGV-elt as argument. */ optarg = argv[optind++]; /* optarg is now the argument, see if it's in the table of longopts. */ for (nextchar = nameend = optarg; *nameend && *nameend != '='; nameend++) /* Do nothing. */ ; /* Test all long options for either exact match or abbreviated matches. */ for (p = longopts, option_index = 0; p->name; p++, option_index++) if (!strncmp (p->name, nextchar, nameend - nextchar)) { if ((unsigned int) (nameend - nextchar) == strlen (p->name)) { /* Exact match found. */ pfound = p; indfound = option_index; exact = 1; break; } else if (pfound == NULL) { /* First nonexact match found. */ pfound = p; indfound = option_index; } else /* Second or later nonexact match found. */ ambig = 1; } if (ambig && !exact) { if (print_errors) { #if defined _LIBC && defined USE_IN_LIBIO char *buf; if (__asprintf (&buf, _("%s: option `-W %s' is ambiguous\n"), argv[0], argv[optind]) >= 0) { if (_IO_fwide (stderr, 0) > 0) __fwprintf (stderr, L"%s", buf); else fputs (buf, stderr); free (buf); } #else fprintf (stderr, _("%s: option `-W %s' is ambiguous\n"), argv[0], argv[optind]); #endif } nextchar += strlen (nextchar); optind++; return '?'; } if (pfound != NULL) { option_index = indfound; if (*nameend) { /* Don't test has_arg with >, because some C compilers don't allow it to be used on enums. */ if (pfound->has_arg) optarg = nameend + 1; else { if (print_errors) { #if defined _LIBC && defined USE_IN_LIBIO char *buf; if (__asprintf (&buf, _("\ %s: option `-W %s' doesn't allow an argument\n"), argv[0], pfound->name) >= 0) { if (_IO_fwide (stderr, 0) > 0) __fwprintf (stderr, L"%s", buf); else fputs (buf, stderr); free (buf); } #else fprintf (stderr, _("\ %s: option `-W %s' doesn't allow an argument\n"), argv[0], pfound->name); #endif } nextchar += strlen (nextchar); return '?'; } } else if (pfound->has_arg == 1) { if (optind < argc) optarg = argv[optind++]; else { if (print_errors) { #if defined _LIBC && defined USE_IN_LIBIO char *buf; if (__asprintf (&buf, _("\ %s: option `%s' requires an argument\n"), argv[0], argv[optind - 1]) >= 0) { if (_IO_fwide (stderr, 0) > 0) __fwprintf (stderr, L"%s", buf); else fputs (buf, stderr); free (buf); } #else fprintf (stderr, _("%s: option `%s' requires an argument\n"), argv[0], argv[optind - 1]); #endif } nextchar += strlen (nextchar); return optstring[0] == ':' ? ':' : '?'; } } nextchar += strlen (nextchar); if (longind != NULL) *longind = option_index; if (pfound->flag) { *(pfound->flag) = pfound->val; return 0; } return pfound->val; } nextchar = NULL; return 'W'; /* Let the application handle it. */ } if (temp[1] == ':') { if (temp[2] == ':') { /* This is an option that accepts an argument optionally. */ if (*nextchar != '\0') { optarg = nextchar; optind++; } else optarg = NULL; nextchar = NULL; } else { /* This is an option that requires an argument. */ if (*nextchar != '\0') { optarg = nextchar; /* If we end this ARGV-element by taking the rest as an arg, we must advance to the next element now. */ optind++; } else if (optind == argc) { if (print_errors) { /* 1003.2 specifies the format of this message. */ #if defined _LIBC && defined USE_IN_LIBIO char *buf; if (__asprintf (&buf, _("\ %s: option requires an argument -- %c\n"), argv[0], c) >= 0) { if (_IO_fwide (stderr, 0) > 0) __fwprintf (stderr, L"%s", buf); else fputs (buf, stderr); free (buf); } #else fprintf (stderr, _("%s: option requires an argument -- %c\n"), argv[0], c); #endif } optopt = c; if (optstring[0] == ':') c = ':'; else c = '?'; } else /* We already incremented `optind' once; increment it again when taking next ARGV-elt as argument. */ optarg = argv[optind++]; nextchar = NULL; } } return c; } } int getopt (argc, argv, optstring) int argc; char *const *argv; const char *optstring; { return _getopt_internal (argc, argv, optstring, (const struct option *) 0, (int *) 0, 0); } #endif /* Not ELIDE_CODE. */ #ifdef TEST /* Compile with -DTEST to make an executable for use in testing the above definition of `getopt'. */ int main (argc, argv) int argc; char **argv; { int c; int digit_optind = 0; while (1) { int this_option_optind = optind ? optind : 1; c = getopt (argc, argv, "abc:d:0123456789"); if (c == -1) break; switch (c) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': if (digit_optind != 0 && digit_optind != this_option_optind) printf ("digits occur in two different argv-elements.\n"); digit_optind = this_option_optind; printf ("option %c\n", c); break; case 'a': printf ("option a\n"); break; case 'b': printf ("option b\n"); break; case 'c': printf ("option c with value `%s'\n", optarg); break; case '?': break; default: printf ("?? getopt returned character code 0%o ??\n", c); } } if (optind < argc) { printf ("non-option ARGV-elements: "); while (optind < argc) printf ("%s ", argv[optind++]); printf ("\n"); } exit (0); } #endif /* TEST */ munge-munge-0.5.15/src/libmissing/getopt.h000066400000000000000000000144721425467526100204540ustar00rootroot00000000000000/* Declarations for getopt. Copyright (C) 1989-1994, 1996-1999, 2001 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. The GNU C Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with the GNU C Library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ #ifndef _GETOPT_H #ifndef __need_getopt # define _GETOPT_H 1 #endif /* If __GNU_LIBRARY__ is not already defined, either we are being used standalone, or this is the first header included in the source file. If we are being used with glibc, we need to include , but that does not exist if we are standalone. So: if __GNU_LIBRARY__ is not defined, include , which will pull in for us if it's from glibc. (Why ctype.h? It's guaranteed to exist and it doesn't flood the namespace with stuff the way some other headers do.) */ #if !defined __GNU_LIBRARY__ # include #endif #ifdef __cplusplus extern "C" { #endif /* For communication from `getopt' to the caller. When `getopt' finds an option that takes an argument, the argument value is returned here. Also, when `ordering' is RETURN_IN_ORDER, each non-option ARGV-element is returned here. */ extern char *optarg; /* Index in ARGV of the next element to be scanned. This is used for communication to and from the caller and for communication between successive calls to `getopt'. On entry to `getopt', zero means this is the first call; initialize. When `getopt' returns -1, this is the index of the first of the non-option elements that the caller should itself scan. Otherwise, `optind' communicates from one call to the next how much of ARGV has been scanned so far. */ extern int optind; /* Callers store zero here to inhibit the error message `getopt' prints for unrecognized options. */ extern int opterr; /* Set to an option character which was unrecognized. */ extern int optopt; #ifndef __need_getopt /* Describe the long-named options requested by the application. The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector of `struct option' terminated by an element containing a name which is zero. The field `has_arg' is: no_argument (or 0) if the option does not take an argument, required_argument (or 1) if the option requires an argument, optional_argument (or 2) if the option takes an optional argument. If the field `flag' is not NULL, it points to a variable that is set to the value given in the field `val' when the option is found, but left unchanged if the option is not found. To have a long-named option do something other than set an `int' to a compiled-in constant, such as set a value from `optarg', set the option's `flag' field to zero and its `val' field to a nonzero value (the equivalent single-letter option character, if there is one). For long options that have a zero `flag' field, `getopt' returns the contents of the `val' field. */ struct option { # if (defined __STDC__ && __STDC__) || defined __cplusplus const char *name; # else char *name; # endif /* has_arg can't be an enum because some compilers complain about type mismatches in all the code that assumes it is an int. */ int has_arg; int *flag; int val; }; /* Names for the values of the `has_arg' field of `struct option'. */ # define no_argument 0 # define required_argument 1 # define optional_argument 2 #endif /* need getopt */ /* Get definitions and prototypes for functions to process the arguments in ARGV (ARGC of them, minus the program name) for options given in OPTS. Return the option character from OPTS just read. Return -1 when there are no more options. For unrecognized options, or options missing arguments, `optopt' is set to the option letter, and '?' is returned. The OPTS string is a list of characters which are recognized option letters, optionally followed by colons, specifying that that letter takes an argument, to be placed in `optarg'. If a letter in OPTS is followed by two colons, its argument is optional. This behavior is specific to the GNU `getopt'. The argument `--' causes premature termination of argument scanning, explicitly telling `getopt' that there are no more options. If OPTS begins with `--', then non-option arguments are treated as arguments to the option '\0'. This behavior is specific to the GNU `getopt'. */ #if (defined __STDC__ && __STDC__) || defined __cplusplus # ifdef __GNU_LIBRARY__ /* Many other libraries have conflicting prototypes for getopt, with differences in the consts, in stdlib.h. To avoid compilation errors, only prototype getopt for the GNU C library. */ extern int getopt (int ___argc, char *const *___argv, const char *__shortopts); # else /* not __GNU_LIBRARY__ */ extern int getopt (); # endif /* __GNU_LIBRARY__ */ # ifndef __need_getopt extern int getopt_long (int ___argc, char *const *___argv, const char *__shortopts, const struct option *__longopts, int *__longind); extern int getopt_long_only (int ___argc, char *const *___argv, const char *__shortopts, const struct option *__longopts, int *__longind); /* Internal only. Users should not call this directly. */ extern int _getopt_internal (int ___argc, char *const *___argv, const char *__shortopts, const struct option *__longopts, int *__longind, int __long_only); # endif #else /* not __STDC__ */ extern int getopt (); # ifndef __need_getopt extern int getopt_long (); extern int getopt_long_only (); extern int _getopt_internal (); # endif #endif /* __STDC__ */ #ifdef __cplusplus } #endif /* Make sure we later can get all the definitions and declarations. */ #undef __need_getopt #endif /* getopt.h */ munge-munge-0.5.15/src/libmissing/getopt1.c000066400000000000000000000110571425467526100205240ustar00rootroot00000000000000/* getopt_long and getopt_long_only entry points for GNU getopt. Copyright (C) 1987,88,89,90,91,92,93,94,96,97,98 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. The GNU C Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with the GNU C Library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ #ifdef HAVE_CONFIG_H #include #endif #ifdef _LIBC # include #else # include "getopt.h" #endif #if !defined __STDC__ || !__STDC__ /* This is a separate conditional since some stdc systems reject `defined (const)'. */ #ifndef const #define const #endif #endif #include /* Comment out all this code if we are using the GNU C Library, and are not actually compiling the library itself. This code is part of the GNU C Library, but also included in many other GNU distributions. Compiling and linking in this code is a waste when using the GNU C library (especially if it is a shared library). Rather than having every GNU program understand `configure --with-gnu-libc' and omit the object files, it is simpler to just do this in the source for each such file. */ #define GETOPT_INTERFACE_VERSION 2 #if !defined _LIBC && defined __GLIBC__ && __GLIBC__ >= 2 #include #if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION #define ELIDE_CODE #endif #endif #ifndef ELIDE_CODE /* This needs to come after some library #include to get __GNU_LIBRARY__ defined. */ #ifdef __GNU_LIBRARY__ #include #endif #ifndef NULL #define NULL 0 #endif int getopt_long (argc, argv, options, long_options, opt_index) int argc; char *const *argv; const char *options; const struct option *long_options; int *opt_index; { return _getopt_internal (argc, argv, options, long_options, opt_index, 0); } /* Like getopt_long, but '-' as well as '--' can indicate a long option. If an option that starts with '-' (not '--') doesn't match a long option, but does match a short option, it is parsed as a short option instead. */ int getopt_long_only (argc, argv, options, long_options, opt_index) int argc; char *const *argv; const char *options; const struct option *long_options; int *opt_index; { return _getopt_internal (argc, argv, options, long_options, opt_index, 1); } # ifdef _LIBC libc_hidden_def (getopt_long) libc_hidden_def (getopt_long_only) # endif #endif /* Not ELIDE_CODE. */ #ifdef TEST #include int main (argc, argv) int argc; char **argv; { int c; int digit_optind = 0; while (1) { int this_option_optind = optind ? optind : 1; int option_index = 0; static struct option long_options[] = { {"add", 1, 0, 0}, {"append", 0, 0, 0}, {"delete", 1, 0, 0}, {"verbose", 0, 0, 0}, {"create", 0, 0, 0}, {"file", 1, 0, 0}, {0, 0, 0, 0} }; c = getopt_long (argc, argv, "abc:d:0123456789", long_options, &option_index); if (c == -1) break; switch (c) { case 0: printf ("option %s", long_options[option_index].name); if (optarg) printf (" with arg %s", optarg); printf ("\n"); break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': if (digit_optind != 0 && digit_optind != this_option_optind) printf ("digits occur in two different argv-elements.\n"); digit_optind = this_option_optind; printf ("option %c\n", c); break; case 'a': printf ("option a\n"); break; case 'b': printf ("option b\n"); break; case 'c': printf ("option c with value `%s'\n", optarg); break; case 'd': printf ("option d with value `%s'\n", optarg); break; case '?': break; default: printf ("?? getopt returned character code 0%o ??\n", c); } } if (optind < argc) { printf ("non-option ARGV-elements: "); while (optind < argc) printf ("%s ", argv[optind++]); printf ("\n"); } exit (0); } #endif /* TEST */ munge-munge-0.5.15/src/libmissing/inet_ntop.c000066400000000000000000000041541425467526100211400ustar00rootroot00000000000000/***************************************************************************** * Written by Chris Dunlap . * Copyright (C) 2007-2022 Lawrence Livermore National Security, LLC. * Copyright (C) 2002-2007 The Regents of the University of California. * UCRL-CODE-155910. * * This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE). * For details, see . * * MUNGE 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. Additionally for the MUNGE library (libmunge), you * can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation, * either version 3 of the License, or (at your option) any later version. * * MUNGE 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 * and GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * and GNU Lesser General Public License along with MUNGE. If not, see * . *****************************************************************************/ #if HAVE_CONFIG_H # include "config.h" #endif /* HAVE_CONFIG_H */ #ifndef HAVE_INET_NTOP #include #include #include #include "inet_ntop.h" const char * inet_ntop (int af, const void *src, char *dst, socklen_t cnt) { const unsigned char *p = src; int n; if (af != AF_INET) { errno = EAFNOSUPPORT; return (NULL); } if (!src || !dst) { errno = EINVAL; return (NULL); } n = snprintf (dst, cnt, "%d.%d.%d.%d", p[0], p[1], p[2], p[3]); if ((n < 0) || (n >= cnt)) { errno = ENOSPC; return (NULL); } return (dst); } #endif /* !HAVE_INET_NTOP */ munge-munge-0.5.15/src/libmissing/inet_ntop.h000066400000000000000000000035711425467526100211470ustar00rootroot00000000000000/***************************************************************************** * Written by Chris Dunlap . * Copyright (C) 2007-2022 Lawrence Livermore National Security, LLC. * Copyright (C) 2002-2007 The Regents of the University of California. * UCRL-CODE-155910. * * This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE). * For details, see . * * MUNGE 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. Additionally for the MUNGE library (libmunge), you * can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation, * either version 3 of the License, or (at your option) any later version. * * MUNGE 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 * and GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * and GNU Lesser General Public License along with MUNGE. If not, see * . *****************************************************************************/ #ifndef INET_NTOP_H #define INET_NTOP_H #if HAVE_CONFIG_H # include "config.h" #endif /* HAVE_CONFIG_H */ #ifndef INET_ADDRSTRLEN # define INET_ADDRSTRLEN 16 #endif /* !INET_ADDRSTRLEN */ #if HAVE_INET_NTOP # include #else /* !HAVE_INET_NTOP */ # include const char *inet_ntop (int af, const void *src, char *dst, socklen_t cnt); #endif /* !HAVE_INET_NTOP */ #endif /* !INET_NTOP_H */ munge-munge-0.5.15/src/libmissing/missing.h000066400000000000000000000032401425467526100206120ustar00rootroot00000000000000/***************************************************************************** * Written by Chris Dunlap . * Copyright (C) 2007-2022 Lawrence Livermore National Security, LLC. * Copyright (C) 2002-2007 The Regents of the University of California. * UCRL-CODE-155910. * * This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE). * For details, see . * * MUNGE 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. Additionally for the MUNGE library (libmunge), you * can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation, * either version 3 of the License, or (at your option) any later version. * * MUNGE 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 * and GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * and GNU Lesser General Public License along with MUNGE. If not, see * . *****************************************************************************/ #ifndef MUNGE_MISSING_H #define MUNGE_MISSING_H /* These contain prototypes and whatnot for libmissing. */ #include "inet_ntop.h" #include "strlcat.h" #include "strlcpy.h" #endif /* !MUNGE_MISSING_H */ munge-munge-0.5.15/src/libmissing/strlcat.c000066400000000000000000000035231425467526100206140ustar00rootroot00000000000000/* $OpenBSD: strlcat.c,v 1.11 2003/06/17 21:56:24 millert Exp $ */ /* * Copyright (c) 1998 Todd C. Miller * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #if defined(LIBC_SCCS) && !defined(lint) static char *rcsid = "$OpenBSD: strlcat.c,v 1.11 2003/06/17 21:56:24 millert Exp $"; #endif /* LIBC_SCCS and not lint */ #include #include /* * Appends src to string dst of size siz (unlike strncat, siz is the * full size of dst, not space left). At most siz-1 characters * will be copied. Always NUL terminates (unless siz <= strlen(dst)). * Returns strlen(src) + MIN(siz, strlen(initial dst)). * If retval >= siz, truncation occurred. */ size_t strlcat(char *dst, const char *src, size_t siz) { register char *d = dst; register const char *s = src; register size_t n = siz; size_t dlen; /* Find the end of dst and adjust bytes left but don't go past end */ while (n-- != 0 && *d != '\0') d++; dlen = d - dst; n = siz - dlen; if (n == 0) return(dlen + strlen(s)); while (*s != '\0') { if (n != 1) { *d++ = *s; n--; } s++; } *d = '\0'; return(dlen + (s - src)); /* count does not include NUL */ } munge-munge-0.5.15/src/libmissing/strlcat.h000066400000000000000000000007471425467526100206260ustar00rootroot00000000000000#if HAVE_CONFIG_H # include "config.h" #endif /* HAVE_CONFIG_H */ #if !HAVE_STRLCAT size_t strlcat(char *dst, const char *src, size_t siz); /* * Appends src to string dst of size siz (unlike strncat, siz is the * full size of dst, not space left). At most siz-1 characters * will be copied. Always NUL terminates (unless siz <= strlen(dst)). * Returns strlen(src) + MIN(siz, strlen(initial dst)). * If retval >= siz, truncation occurred. */ #endif /* !HAVE_STRLCAT */ munge-munge-0.5.15/src/libmissing/strlcpy.c000066400000000000000000000033421425467526100206370ustar00rootroot00000000000000/* $OpenBSD: strlcpy.c,v 1.8 2003/06/17 21:56:24 millert Exp $ */ /* * Copyright (c) 1998 Todd C. Miller * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #if defined(LIBC_SCCS) && !defined(lint) static char *rcsid = "$OpenBSD: strlcpy.c,v 1.8 2003/06/17 21:56:24 millert Exp $"; #endif /* LIBC_SCCS and not lint */ #include #include /* * Copy src to string dst of size siz. At most siz-1 characters * will be copied. Always NUL terminates (unless siz == 0). * Returns strlen(src); if retval >= siz, truncation occurred. */ size_t strlcpy(char *dst, const char *src, size_t siz) { register char *d = dst; register const char *s = src; register size_t n = siz; /* Copy as many bytes as will fit */ if (n != 0 && --n != 0) { do { if ((*d++ = *s++) == 0) break; } while (--n != 0); } /* Not enough room in dst, add NUL and traverse rest of src */ if (n == 0) { if (siz != 0) *d = '\0'; /* NUL-terminate dst */ while (*s++) ; } return(s - src - 1); /* count does not include NUL */ } munge-munge-0.5.15/src/libmissing/strlcpy.h000066400000000000000000000005621425467526100206450ustar00rootroot00000000000000#if HAVE_CONFIG_H # include "config.h" #endif /* HAVE_CONFIG_H */ #if !HAVE_STRLCPY size_t strlcpy(char *dst, const char *src, size_t siz); /* * Copy src to string dst of size siz. At most siz-1 characters * will be copied. Always NUL terminates (unless siz == 0). * Returns strlen(src); if retval >= siz, truncation occurred. */ #endif /* !HAVE_STRLCPY */ munge-munge-0.5.15/src/libmunge/000077500000000000000000000000001425467526100164335ustar00rootroot00000000000000munge-munge-0.5.15/src/libmunge/Makefile.am000066400000000000000000000057031425467526100204740ustar00rootroot00000000000000# MUNGE src/libmunge/Makefile.am # # This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE). # For details, see . include $(top_srcdir)/Make-inc.mk TEMPLATE_FILES = \ munge.3.in \ munge_ctx.3.in \ munge_enum.3.in \ # End of TEMPLATE_FILES SUBSTITUTE_FILES = \ munge.3 \ munge_ctx.3 \ munge_enum.3 \ # End of SUBSTITUTE_FILES EXTRA_DIST = \ $(TEMPLATE_FILES) \ # End of EXTRA_DIST CLEANFILES = \ $(SUBSTITUTE_FILES) \ # End of CLEANFILES $(SUBSTITUTE_FILES): Makefile $(AM_V_GEN)$(substitute) < '$(srcdir)/$@.in' > '$(builddir)/$@' munge.3: munge.3.in munge_ctx.3: munge_ctx.3.in munge_enum.3: munge_enum.3.in include_HEADERS = \ munge.h \ # End of include_HEADERS lib_LTLIBRARIES = \ libmunge.la \ # End of lib_LTLIBRARIES LT_CURRENT = 2 LT_REVISION = 0 LT_AGE = 0 libmunge_la_CPPFLAGS = \ -DRUNSTATEDIR='"$(runstatedir)"' \ -DSYSCONFDIR='"$(sysconfdir)"' \ -I$(top_srcdir)/src/libcommon \ # End of libmunge_la_CPPFLAGS libmunge_la_LDFLAGS = \ -export-symbols-regex "^munge_.*" \ -version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE) \ # End of libmunge_la_LDFLAGS libmunge_la_LIBADD = \ $(top_builddir)/src/libcommon/libcommon.la \ # End of libmunge_la_LIBADD libmunge_la_SOURCES = \ auth_send.c \ auth_send.h \ ctx.c \ ctx.h \ decode.c \ encode.c \ enum.c \ m_msg_client.c \ m_msg_client.h \ strerror.c \ munge.h \ # End of libmunge_la_SOURCES # For dependencies on RUNSTATEDIR via the #define for MUNGE_SOCKET_NAME. # $(srcdir)/libmunge_la-ctx.lo: Makefile $(srcdir)/libmunge_la-m_msg_client.lo: Makefile man_MANS = \ munge.3 \ munge_ctx.3 \ munge_enum.3 \ # End of man_MANS install-data-hook: uninstall-local $(MKDIR_P) '$(DESTDIR)$(mandir)/man3/' ( cd '$(DESTDIR)$(mandir)/man3/' \ && $(LN_S) munge.3 munge_decode.3 \ && $(LN_S) munge.3 munge_encode.3 \ && $(LN_S) munge.3 munge_strerror.3 \ && $(LN_S) munge_ctx.3 munge_ctx_copy.3 \ && $(LN_S) munge_ctx.3 munge_ctx_create.3 \ && $(LN_S) munge_ctx.3 munge_ctx_destroy.3 \ && $(LN_S) munge_ctx.3 munge_ctx_get.3 \ && $(LN_S) munge_ctx.3 munge_ctx_set.3 \ && $(LN_S) munge_ctx.3 munge_ctx_strerror.3 \ && $(LN_S) munge_enum.3 munge_enum_int_to_str.3 \ && $(LN_S) munge_enum.3 munge_enum_is_valid.3 \ && $(LN_S) munge_enum.3 munge_enum_str_to_int.3 ) uninstall-local: rm -f '$(DESTDIR)$(mandir)/man3/munge_ctx_copy.3' rm -f '$(DESTDIR)$(mandir)/man3/munge_ctx_create.3' rm -f '$(DESTDIR)$(mandir)/man3/munge_ctx_destroy.3' rm -f '$(DESTDIR)$(mandir)/man3/munge_ctx_get.3' rm -f '$(DESTDIR)$(mandir)/man3/munge_ctx_set.3' rm -f '$(DESTDIR)$(mandir)/man3/munge_ctx_strerror.3' rm -f '$(DESTDIR)$(mandir)/man3/munge_decode.3' rm -f '$(DESTDIR)$(mandir)/man3/munge_encode.3' rm -f '$(DESTDIR)$(mandir)/man3/munge_enum_int_to_str.3' rm -f '$(DESTDIR)$(mandir)/man3/munge_enum_is_valid.3' rm -f '$(DESTDIR)$(mandir)/man3/munge_enum_str_to_int.3' rm -f '$(DESTDIR)$(mandir)/man3/munge_strerror.3' munge-munge-0.5.15/src/libmunge/auth_send.c000066400000000000000000000221411425467526100205510ustar00rootroot00000000000000/***************************************************************************** * Written by Chris Dunlap . * Copyright (C) 2007-2022 Lawrence Livermore National Security, LLC. * Copyright (C) 2002-2007 The Regents of the University of California. * UCRL-CODE-155910. * * This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE). * For details, see . * * MUNGE 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. Additionally for the MUNGE library (libmunge), you * can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation, * either version 3 of the License, or (at your option) any later version. * * MUNGE 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 * and GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * and GNU Lesser General Public License along with MUNGE. If not, see * . *****************************************************************************/ #if HAVE_CONFIG_H # include #endif /* HAVE_CONFIG_H */ #include #include "m_msg.h" /***************************************************************************** * null client *****************************************************************************/ #if !defined(AUTH_METHOD_RECVFD_MKFIFO) && !defined(AUTH_METHOD_RECVFD_MKNOD) int auth_send (m_msg_t m) { return (EMUNGE_SUCCESS); } #endif /* !AUTH_METHOD_RECVFD_MKFIFO && !AUTH_METHOD_RECVFD_MKNOD */ /***************************************************************************** * strrecvfd struct (common) *****************************************************************************/ #if defined(AUTH_METHOD_RECVFD_MKFIFO) || defined(AUTH_METHOD_RECVFD_MKNOD) #include #include #include /* open, O_RDONLY, etc. */ #include /* snprintf */ #include #include /* strdup, strerror, strrchr */ #include /* I_SENDFD */ #include /* ioctl */ #include /* I_IRUSR */ #include /* unlink, close */ #include "munge_defs.h" #include "str.h" static int _recv_auth_req (int sd, char **pipe_name_p, char **file_dir_p); static int _name_auth_file (const char *pipe_name, const char *file_dir, char **file_name_p); int auth_send (m_msg_t m) { char *pipe_name = NULL; char *file_dir = NULL; char *file_name = NULL; int file_fd = -1; int pipe_fd = -1; char *estr; if (_recv_auth_req (m->sd, &pipe_name, &file_dir) < 0) { estr = strdup ("Failed to receive auth request"); goto err; } assert (pipe_name != NULL); if (_name_auth_file (pipe_name, file_dir, &file_name) < 0) { estr = strdup ("Failed to name auth file"); goto err; } assert (file_name != NULL); unlink (file_name); /* in case it already exists */ if ((file_fd= open (file_name, O_RDONLY | O_CREAT | O_EXCL, S_IRUSR)) <0) { estr = strdupf ("Failed to open auth file \"%s\": %s", file_name, strerror (errno)); goto err; } if (unlink (file_name) < 0) { estr = strdupf ("Failed to remove auth file \"%s\": %s", file_name, strerror (errno)); goto err; } if ((pipe_fd = open (pipe_name, O_WRONLY)) < 0) { estr = strdupf ("Failed to open auth pipe \"%s\": %s", pipe_name, strerror (errno)); goto err; } if (ioctl (pipe_fd, I_SENDFD, file_fd) < 0) { estr = strdupf ("Failed to send client identity: %s", strerror (errno)); goto err; } if (close (pipe_fd) < 0) { estr = strdupf ("Failed to close auth pipe \"%s\": %s", pipe_name, strerror (errno)); goto err; } if (close (file_fd) < 0) { estr = strdupf ("Failed to close auth file \"%s\": %s", file_name, strerror (errno)); goto err; } free (pipe_name); free (file_dir); free (file_name); return (0); err: if (pipe_fd >= 0) { (void) close (pipe_fd); } if (pipe_name != NULL) { free (pipe_name); } if (file_fd >= 0) { (void) close (file_fd); } if (file_name != NULL) { (void) unlink (file_name); free (file_name); } if (file_dir != NULL) { free (file_dir); } return (m_msg_set_err (m, EMUNGE_SNAFU, estr)); } static int _recv_auth_req (int sd, char **pipe_name_p, char **file_dir_p) { /* Receives an authentication request from the server on the established * socket [sd], storing the path name of the authentication pipe to use for * sending an fd across in a newly-allocated string referenced by * [pipe_name_p], as well as the directory name in which to create the * authentication file [file_dir_p] corresponding to the fd to be sent. * The caller is responsible for freeing these strings. * Returns 0 on success, -1 on error. */ m_msg_t m; munge_err_t e; *pipe_name_p = NULL; *file_dir_p = NULL; if ((e = m_msg_create (&m)) != EMUNGE_SUCCESS) { goto end; } if ((e = m_msg_bind (m, sd)) != EMUNGE_SUCCESS) { goto end; } if ((e = m_msg_recv (m, MUNGE_MSG_AUTH_FD_REQ, 0)) != EMUNGE_SUCCESS) { goto end; } /* Note that error_str will be set if the received message is an error * message, whereas m_msg_recv()'s return code (e) will be set * according to how that message is received. */ if (m->error_str != NULL) { e = EMUNGE_SOCKET; goto end; } *pipe_name_p = m->auth_s_str; m->auth_s_is_copy = 1; *file_dir_p = m->auth_c_str; m->auth_c_is_copy = 1; end: if (m) { m->sd = -1; /* prevent close by m_msg_destroy() */ m_msg_destroy (m); } return (e == EMUNGE_SUCCESS ? 0 : -1); } static int _name_auth_file (const char *pipe_name, const char *file_dir, char **file_name_p) { /* Creates a unique filename based on the name of authentication pipe * [pipe_name] and authentication file directory [file_dir], storing the * result in a newly-allocated string referenced by [file_name_p]. * The caller is responsible for freeing the string returned by [file_name_p]. * The auth pipe name is of the form "AUTH_PIPE_DIR/.munge-RANDOM.pipe". * The auth file name is of the form "AUTH_FILE_DIR/.munge-RANDOM.file". * Returns 0 on success, -1 on error. * * The random component of the authentication file is computed by XORing the * first half of the random component of the authentication pipe with the * second half. Consequently, it is half the length. * The random component of the client is based off that of the server because * the client does not have access to the PRNG. At the same time, we don't * want to allow an attacker to derive the name of the authentication pipe * from that of the authentication file (assuming the directory containing * the authentication pipe is unreadable). */ char *p; char *q; int rnd_bin_len; char *rnd_bin = NULL; int rnd_asc_len; char *rnd_asc = NULL; int m; int i; int dst_len; char *dst = NULL; int n; *file_name_p = NULL; if (!pipe_name || !file_dir) { goto err; } p = (p = strrchr (pipe_name, '-')) ? p + 1 : NULL; q = strrchr (pipe_name, '.'); if (!p || !q) { goto err; } rnd_bin_len = (q - p) / 2; if (!(rnd_bin = malloc (rnd_bin_len))) { goto err; } rnd_asc_len = rnd_bin_len + 1; if (!(rnd_asc = malloc (rnd_asc_len))) { goto err; } if (!(strhex2bin (rnd_bin, rnd_bin_len, p, q - p))) { goto err; } m = rnd_bin_len / 2; for (i = 0; i < m; i++) { rnd_bin [i] ^= rnd_bin [i + m]; } if (!(strbin2hex (rnd_asc, rnd_asc_len, rnd_bin, m))) { goto err; } dst_len = strlen (file_dir) + 8 /* strlen ("/.munge-") */ + strlen (rnd_asc) + 6; /* strlen (".file") + "\0" */ if (!(dst = malloc (dst_len))) { goto err; } n = snprintf (dst, dst_len, "%s/.munge-%s.file", file_dir, rnd_asc); if ((n < 0) || (n >= dst_len)) { goto err; } free (rnd_bin); free (rnd_asc); *file_name_p = dst; return (0); err: if (rnd_bin) { free (rnd_bin); } if (rnd_asc) { free (rnd_asc); } if (dst) { free (dst); } return (-1); } #endif /* AUTH_METHOD_RECVFD_MKFIFO || AUTH_METHOD_RECVFD_MKNOD */ munge-munge-0.5.15/src/libmunge/auth_send.h000066400000000000000000000033161425467526100205610ustar00rootroot00000000000000/***************************************************************************** * Written by Chris Dunlap . * Copyright (C) 2007-2022 Lawrence Livermore National Security, LLC. * Copyright (C) 2002-2007 The Regents of the University of California. * UCRL-CODE-155910. * * This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE). * For details, see . * * MUNGE 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. Additionally for the MUNGE library (libmunge), you * can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation, * either version 3 of the License, or (at your option) any later version. * * MUNGE 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 * and GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * and GNU Lesser General Public License along with MUNGE. If not, see * . *****************************************************************************/ #ifndef MUNGE_AUTH_SEND_H #define MUNGE_AUTH_SEND_H #include "m_msg.h" int auth_send (m_msg_t m); /* * Sends data needed to prove the identity of the client to the server * that sent the auth req msg [m]. */ #endif /* !MUNGE_AUTH_SEND_H */ munge-munge-0.5.15/src/libmunge/ctx.c000066400000000000000000000230201425467526100173720ustar00rootroot00000000000000/***************************************************************************** * Written by Chris Dunlap . * Copyright (C) 2007-2022 Lawrence Livermore National Security, LLC. * Copyright (C) 2002-2007 The Regents of the University of California. * UCRL-CODE-155910. * * This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE). * For details, see . * * MUNGE 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. Additionally for the MUNGE library (libmunge), you * can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation, * either version 3 of the License, or (at your option) any later version. * * MUNGE 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 * and GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * and GNU Lesser General Public License along with MUNGE. If not, see * . *****************************************************************************/ #if HAVE_CONFIG_H # include #endif /* HAVE_CONFIG_H */ #include #include /* include before in.h for bsd */ #include #include #include #include #include #include "ctx.h" #include "munge_defs.h" /***************************************************************************** * Extern Functions *****************************************************************************/ munge_ctx_t munge_ctx_create (void) { munge_ctx_t ctx; if (!(ctx = malloc (sizeof (*ctx)))) { return (NULL); } ctx->cipher = MUNGE_CIPHER_DEFAULT; ctx->mac = MUNGE_MAC_DEFAULT; ctx->zip = MUNGE_ZIP_DEFAULT; ctx->realm_str = NULL; ctx->ttl = MUNGE_TTL_DEFAULT; ctx->addr.s_addr = 0; ctx->time0 = 0; ctx->time1 = 0; ctx->auth_uid = MUNGE_UID_ANY; ctx->auth_gid = MUNGE_GID_ANY; ctx->socket_str = strdup (MUNGE_SOCKET_NAME); ctx->error_num = EMUNGE_SUCCESS; ctx->error_str = NULL; if (!ctx->socket_str) { munge_ctx_destroy (ctx); return (NULL); } return (ctx); } munge_ctx_t munge_ctx_copy (munge_ctx_t src) { munge_ctx_t dst; if (!src) { return (NULL); } if (!(dst = malloc (sizeof (*dst)))) { return (NULL); } *dst = *src; /* * Since struct assignment is a shallow copy, first reset all strings. * This protects against calling munge_ctx_destroy (dst) on error. * If any of these still referenced the src strings at that time, * those strings would erroneously be free()d -- thereby corrupting * the src ctx by mistake. */ dst->realm_str = NULL; dst->socket_str = NULL; dst->error_str = NULL; /* * Reset the error condition. */ dst->error_num = EMUNGE_SUCCESS; /* * Copy the src strings. */ if ((src->realm_str) && !(dst->realm_str = strdup (src->realm_str))) { goto err; } if (!(dst->socket_str = strdup (src->socket_str))) { goto err; } return (dst); err: munge_ctx_destroy (dst); return (NULL); } void munge_ctx_destroy (munge_ctx_t ctx) { if (!ctx) { return; } if (ctx->realm_str) { free (ctx->realm_str); } if (ctx->socket_str) { free (ctx->socket_str); } if (ctx->error_str) { free (ctx->error_str); } free (ctx); return; } const char * munge_ctx_strerror (munge_ctx_t ctx) { if (!ctx) { return (NULL); } if (ctx->error_num == EMUNGE_SUCCESS) { return (NULL); } if (ctx->error_str != NULL) { return (ctx->error_str); } return (munge_strerror (ctx->error_num)); } munge_err_t munge_ctx_get (munge_ctx_t ctx, int opt, ...) { int *p2int; char **p2str; struct in_addr *p2addr; time_t *p2time; uid_t *p2uid; gid_t *p2gid; va_list vargs; if (!ctx) { return (EMUNGE_BAD_ARG); } ctx->error_num = EMUNGE_SUCCESS; if (ctx->error_str) { free (ctx->error_str); ctx->error_str = NULL; } va_start (vargs, opt); switch (opt) { case MUNGE_OPT_CIPHER_TYPE: p2int = va_arg (vargs, int *); *p2int = ctx->cipher; break; case MUNGE_OPT_MAC_TYPE: p2int = va_arg (vargs, int *); *p2int = ctx->mac; break; case MUNGE_OPT_ZIP_TYPE: p2int = va_arg (vargs, int *); *p2int = ctx->zip; break; case MUNGE_OPT_REALM: p2str = va_arg (vargs, char **); *p2str = ctx->realm_str; break; case MUNGE_OPT_TTL: p2int = va_arg (vargs, int *); *p2int = ctx->ttl; break; case MUNGE_OPT_ADDR4: p2addr = va_arg (vargs, struct in_addr *); *p2addr = ctx->addr; break; case MUNGE_OPT_ENCODE_TIME: p2time = va_arg (vargs, time_t *); *p2time = ctx->time0; break; case MUNGE_OPT_DECODE_TIME: p2time = va_arg (vargs, time_t *); *p2time = ctx->time1; break; case MUNGE_OPT_SOCKET: p2str = va_arg (vargs, char **); *p2str = ctx->socket_str; break; case MUNGE_OPT_UID_RESTRICTION: p2uid = va_arg (vargs, uid_t *); *p2uid = ctx->auth_uid; break; case MUNGE_OPT_GID_RESTRICTION: p2gid = va_arg (vargs, gid_t *); *p2gid = ctx->auth_gid; break; default: ctx->error_num = EMUNGE_BAD_ARG; break; } va_end (vargs); return (ctx->error_num); } munge_err_t munge_ctx_set (munge_ctx_t ctx, int opt, ...) { char *str; char *p; int i; va_list vargs; if (!ctx) { return (EMUNGE_BAD_ARG); } ctx->error_num = EMUNGE_SUCCESS; if (ctx->error_str) { free (ctx->error_str); ctx->error_str = NULL; } va_start (vargs, opt); switch (opt) { case MUNGE_OPT_CIPHER_TYPE: ctx->cipher = va_arg (vargs, int); break; case MUNGE_OPT_MAC_TYPE: ctx->mac = va_arg (vargs, int); break; case MUNGE_OPT_ZIP_TYPE: ctx->zip = va_arg (vargs, int); break; case MUNGE_OPT_REALM: str = va_arg (vargs, char *); if (!str) { p = NULL; } else if (strlen (str) > 255) { ctx->error_num = EMUNGE_BAD_LENGTH; break; } else if (!(p = strdup (str))) { ctx->error_num = EMUNGE_NO_MEMORY; break; } if (ctx->realm_str) { free (ctx->realm_str); } ctx->realm_str = p; break; case MUNGE_OPT_TTL: i = va_arg (vargs, int); ctx->ttl = (i == -1) ? MUNGE_TTL_MAXIMUM : i; break; case MUNGE_OPT_SOCKET: str = va_arg (vargs, char *); if (!str) { p = NULL; } else if (!(p = strdup (str))) { ctx->error_num = EMUNGE_NO_MEMORY; break; } if (ctx->socket_str) { free (ctx->socket_str); } ctx->socket_str = p; break; case MUNGE_OPT_UID_RESTRICTION: ctx->auth_uid = va_arg (vargs, uid_t); break; case MUNGE_OPT_GID_RESTRICTION: ctx->auth_gid = va_arg (vargs, gid_t); break; case MUNGE_OPT_ADDR4: /* this option cannot be set; fall through to error case */ case MUNGE_OPT_ENCODE_TIME: /* this option cannot be set; fall through to error case */ case MUNGE_OPT_DECODE_TIME: /* this option cannot be set; fall through to error case */ default: ctx->error_num = EMUNGE_BAD_ARG; break; } va_end (vargs); return (ctx->error_num); } /***************************************************************************** * Internal (but still "Extern") Functions *****************************************************************************/ munge_err_t _munge_ctx_set_err (munge_ctx_t ctx, munge_err_t e, char *s) { /* If an error condition does not already exist, sets an error code [e] * and string [s] to be returned via the munge context [ctx]. * If [s] is not NULL, that string (and _not_ a copy) will be stored * and later free()'d by the context destructor. * Returns the [ctx] error code and consumes the string [s]. */ if (ctx) { if ((ctx->error_num == EMUNGE_SUCCESS) && (e != EMUNGE_SUCCESS)) { ctx->error_num = e; assert (ctx->error_str == NULL); ctx->error_str = s; s = NULL; } else { e = ctx->error_num; } } if (s) { free (s); } return (e); } munge-munge-0.5.15/src/libmunge/ctx.h000066400000000000000000000065101425467526100174040ustar00rootroot00000000000000/***************************************************************************** * Written by Chris Dunlap . * Copyright (C) 2007-2022 Lawrence Livermore National Security, LLC. * Copyright (C) 2002-2007 The Regents of the University of California. * UCRL-CODE-155910. * * This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE). * For details, see . * * MUNGE 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. Additionally for the MUNGE library (libmunge), you * can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation, * either version 3 of the License, or (at your option) any later version. * * MUNGE 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 * and GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * and GNU Lesser General Public License along with MUNGE. If not, see * . *****************************************************************************/ #ifndef MUNGE_CTX_H #define MUNGE_CTX_H #include /* for struct in_addr */ #include /* for uid_t, gid_t */ #include /* for time_t */ #include /* for munge_ctx_t, munge_err_t */ /***************************************************************************** * Data Types *****************************************************************************/ struct munge_ctx { int cipher; /* symmetric cipher type */ int mac; /* message authentication code type */ int zip; /* compression type */ char *realm_str; /* security realm string with NUL */ int ttl; /* time-to-live */ struct in_addr addr; /* IP addr where cred was encoded */ time_t time0; /* time at which cred was encoded */ time_t time1; /* time at which cred was decoded */ uid_t auth_uid; /* UID of client allowed to decode */ gid_t auth_gid; /* GID of client allowed to decode */ char *socket_str; /* munge domain sock filename w/ NUL */ munge_err_t error_num; /* munge error status */ char *error_str; /* munge error string with NUL */ }; /***************************************************************************** * Internal (but still "Extern") Prototypes *****************************************************************************/ munge_err_t _munge_ctx_set_err (munge_ctx_t ctx, munge_err_t e, char *s); #endif /* !MUNGE_CTX_H */ munge-munge-0.5.15/src/libmunge/decode.c000066400000000000000000000147771425467526100200420ustar00rootroot00000000000000/***************************************************************************** * Written by Chris Dunlap . * Copyright (C) 2007-2022 Lawrence Livermore National Security, LLC. * Copyright (C) 2002-2007 The Regents of the University of California. * UCRL-CODE-155910. * * This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE). * For details, see . * * MUNGE 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. Additionally for the MUNGE library (libmunge), you * can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation, * either version 3 of the License, or (at your option) any later version. * * MUNGE 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 * and GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * and GNU Lesser General Public License along with MUNGE. If not, see * . *****************************************************************************/ #if HAVE_CONFIG_H # include #endif /* HAVE_CONFIG_H */ #include #include #include #include #include #include #include "common.h" #include "ctx.h" #include "m_msg.h" #include "m_msg_client.h" #include "str.h" /***************************************************************************** * Static Prototypes *****************************************************************************/ static void _decode_init (munge_ctx_t ctx, void **buf, int *len, uid_t *uid, gid_t *gid); static munge_err_t _decode_req (m_msg_t m, munge_ctx_t ctx, const char *cred); static munge_err_t _decode_rsp (m_msg_t m, munge_ctx_t ctx, void **buf, int *len, uid_t *uid, gid_t *gid); /***************************************************************************** * Public Functions *****************************************************************************/ munge_err_t munge_decode (const char *cred, munge_ctx_t ctx, void **buf, int *len, uid_t *uid, gid_t *gid) { munge_err_t e; m_msg_t m; /* Init output parms in case of early return. */ _decode_init (ctx, buf, len, uid, gid); /* * Ensure a credential exists for decoding. */ if ((cred == NULL) || (*cred == '\0')) { return (_munge_ctx_set_err (ctx, EMUNGE_BAD_ARG, strdup ("No credential specified"))); } /* Ask the daemon to decode a credential. */ if ((e = m_msg_create (&m)) != EMUNGE_SUCCESS) ; else if ((e = _decode_req (m, ctx, cred)) != EMUNGE_SUCCESS) ; else if ((e = m_msg_client_xfer (&m, MUNGE_MSG_DEC_REQ, ctx)) != EMUNGE_SUCCESS) ; else if ((e = _decode_rsp (m, ctx, buf, len, uid, gid)) != EMUNGE_SUCCESS) ; /* Clean up and return. */ if (ctx) { _munge_ctx_set_err (ctx, e, m->error_str); m->error_is_copy = 1; } m_msg_destroy (m); return (e); } /***************************************************************************** * Private Functions *****************************************************************************/ static void _decode_init (munge_ctx_t ctx, void **buf, int *len, uid_t *uid, gid_t *gid) { /* Initialize output parms in case of early return. */ if (ctx) { ctx->cipher = -1; ctx->mac = -1; ctx->zip = -1; if (ctx->realm_str) { free (ctx->realm_str); ctx->realm_str = NULL; } ctx->ttl = -1; ctx->addr.s_addr = 0; ctx->time0 = -1; ctx->time1 = -1; ctx->auth_uid = UID_SENTINEL; ctx->auth_gid = GID_SENTINEL; ctx->error_num = EMUNGE_SUCCESS; if (ctx->error_str) { free (ctx->error_str); ctx->error_str = NULL; } } if (buf) { *buf = NULL; } if (len) { *len = 0; } if (uid) { *uid = UID_SENTINEL; } if (gid) { *gid = GID_SENTINEL; } return; } static munge_err_t _decode_req (m_msg_t m, munge_ctx_t ctx, const char *cred) { /* Creates a Decode Request message to be sent to the local munge daemon. * The inputs to this message are as follows: * data_len, data. */ assert (m != NULL); assert (cred != NULL); assert (strlen (cred) > 0); /* Pass the NUL-terminated credential to be decoded. */ m->data_len = strlen (cred) + 1; m->data = (void *) cred; m->data_is_copy = 1; return (EMUNGE_SUCCESS); } static munge_err_t _decode_rsp (m_msg_t m, munge_ctx_t ctx, void **buf, int *len, uid_t *uid, gid_t *gid) { /* Extracts a Decode Response message received from the local munge daemon. * The outputs from this message are as follows: * cipher, mac, zip, realm, ttl, addr, time0, time1, cred_uid, cred_gid, * auth_uid, auth_gid, data_len, data, error_num, error_len, error_str. * Note that error_num and error_str are set by _munge_ctx_set_err() * called from munge_decode() (ie, the parent of this stack frame). */ assert (m != NULL); /* Perform sanity checks. */ if (m->type != MUNGE_MSG_DEC_RSP) { m_msg_set_err (m, EMUNGE_SNAFU, strdupf ("Client received invalid message type %d", m->type)); return (EMUNGE_SNAFU); } /* Return the result. */ if (ctx) { ctx->cipher = m->cipher; ctx->mac = m->mac; ctx->zip = m->zip; if ((ctx->realm_str = m->realm_str) != NULL) { m->realm_is_copy = 1; } ctx->ttl = m->ttl; ctx->addr.s_addr = m->addr.s_addr;; ctx->time0 = m->time0; ctx->time1 = m->time1; ctx->auth_uid = m->auth_uid; ctx->auth_gid = m->auth_gid; } if (buf && len && (m->data_len > 0)) { assert (* ((unsigned char *) m->data + m->data_len) == '\0'); *buf = m->data; m->data_is_copy = 1; } if (len) { *len = m->data_len; } if (uid) { *uid = m->cred_uid; } if (gid) { *gid = m->cred_gid; } return (m->error_num); } munge-munge-0.5.15/src/libmunge/encode.c000066400000000000000000000142441425467526100200410ustar00rootroot00000000000000/***************************************************************************** * Written by Chris Dunlap . * Copyright (C) 2007-2022 Lawrence Livermore National Security, LLC. * Copyright (C) 2002-2007 The Regents of the University of California. * UCRL-CODE-155910. * * This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE). * For details, see . * * MUNGE 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. Additionally for the MUNGE library (libmunge), you * can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation, * either version 3 of the License, or (at your option) any later version. * * MUNGE 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 * and GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * and GNU Lesser General Public License along with MUNGE. If not, see * . *****************************************************************************/ #if HAVE_CONFIG_H # include #endif /* HAVE_CONFIG_H */ #include #include #include #include #include #include #include "ctx.h" #include "m_msg.h" #include "m_msg_client.h" #include "str.h" /***************************************************************************** * Static Prototypes *****************************************************************************/ static void _encode_init (char **cred, munge_ctx_t ctx); static munge_err_t _encode_req (m_msg_t m, munge_ctx_t ctx, const void *buf, int len); static munge_err_t _encode_rsp (m_msg_t m, char **cred); /***************************************************************************** * Public Functions *****************************************************************************/ munge_err_t munge_encode (char **cred, munge_ctx_t ctx, const void *buf, int len) { munge_err_t e; m_msg_t m; /* Init output parms in case of early return. */ _encode_init (cred, ctx); /* * Ensure a ptr exists for returning the credential to the caller. */ if (!cred) { return (_munge_ctx_set_err (ctx, EMUNGE_BAD_ARG, strdup ("No address specified for returning the credential"))); } /* Ask the daemon to encode a credential. */ if ((e = m_msg_create (&m)) != EMUNGE_SUCCESS) ; else if ((e = _encode_req (m, ctx, buf, len)) != EMUNGE_SUCCESS) ; else if ((e = m_msg_client_xfer (&m, MUNGE_MSG_ENC_REQ, ctx)) != EMUNGE_SUCCESS) ; else if ((e = _encode_rsp (m, cred)) != EMUNGE_SUCCESS) ; /* Clean up and return. */ if (ctx) { _munge_ctx_set_err (ctx, e, m->error_str); m->error_is_copy = 1; } m_msg_destroy (m); return (e); } /***************************************************************************** * Private Functions *****************************************************************************/ static void _encode_init (char **cred, munge_ctx_t ctx) { /* Initialize output parms in case of early return. */ if (cred) { *cred = NULL; } if (ctx) { ctx->error_num = EMUNGE_SUCCESS; if (ctx->error_str) { free (ctx->error_str); ctx->error_str = NULL; } } return; } static munge_err_t _encode_req (m_msg_t m, munge_ctx_t ctx, const void *buf, int len) { /* Creates an Encode Request message to be sent to the local munge daemon. * The inputs to this message are as follows: * cipher, mac, zip, realm_len, realm_str, ttl, auth_uid, auth_gid, * data_len, data. */ assert (m != NULL); /* Set opts from ctx (if present); o/w, use defaults. */ if (ctx) { m->cipher = ctx->cipher; m->mac = ctx->mac; m->zip = ctx->zip; if (ctx->realm_str) { m->realm_len = strlen (ctx->realm_str) + 1; m->realm_str = ctx->realm_str; m->realm_is_copy = 1; } else { m->realm_len = 0; m->realm_str = NULL; } m->ttl = ctx->ttl; m->auth_uid = ctx->auth_uid; m->auth_gid = ctx->auth_gid; } else { m->cipher = MUNGE_CIPHER_DEFAULT; m->zip = MUNGE_ZIP_DEFAULT; m->mac = MUNGE_MAC_DEFAULT; m->realm_len = 0; m->realm_str = NULL; m->ttl = MUNGE_TTL_DEFAULT; m->auth_uid = MUNGE_UID_ANY; m->auth_gid = MUNGE_GID_ANY; } /* Pass optional data to be encoded into the credential. */ m->data_len = len; m->data = (void *) buf; m->data_is_copy = 1; return (EMUNGE_SUCCESS); } static munge_err_t _encode_rsp (m_msg_t m, char **cred) { /* Extracts an Encode Response message received from the local munge daemon. * The outputs from this message are as follows: * error_num, error_len, error_str, data_len, data. * Note that error_num and error_str are set by _munge_ctx_set_err() * called from munge_encode() (ie, the parent of this stack frame). * Note that the [cred] is NUL-terminated. */ assert (m != NULL); assert (cred != NULL); /* Perform sanity checks. */ if (m->type != MUNGE_MSG_ENC_RSP) { m_msg_set_err (m, EMUNGE_SNAFU, strdupf ("Client received invalid message type %d", m->type)); return (EMUNGE_SNAFU); } if (m->data_len <= 0) { m_msg_set_err (m, EMUNGE_SNAFU, strdupf ("Client received invalid data length %d", m->data_len)); return (EMUNGE_SNAFU); } /* Return the credential to the caller. */ assert (* ((unsigned char *) m->data + m->data_len) == '\0'); *cred = m->data; m->data_is_copy = 1; return (m->error_num); } munge-munge-0.5.15/src/libmunge/enum.c000066400000000000000000000175331425467526100175540ustar00rootroot00000000000000/***************************************************************************** * Written by Chris Dunlap . * Copyright (C) 2007-2022 Lawrence Livermore National Security, LLC. * Copyright (C) 2002-2007 The Regents of the University of California. * UCRL-CODE-155910. * * This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE). * For details, see . * * MUNGE 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. Additionally for the MUNGE library (libmunge), you * can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation, * either version 3 of the License, or (at your option) any later version. * * MUNGE 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 * and GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * and GNU Lesser General Public License along with MUNGE. If not, see * . *****************************************************************************/ #if HAVE_CONFIG_H # include #endif /* HAVE_CONFIG_H */ #include #include #include #include #include #include "common.h" /***************************************************************************** * Constants *****************************************************************************/ #if HAVE_LIBGCRYPT || HAVE_EVP_AES_128_CBC # define MUNGE_CIPHER_AES128_FLAG 1 #else # define MUNGE_CIPHER_AES128_FLAG 0 #endif #if HAVE_LIBGCRYPT || (HAVE_EVP_AES_256_CBC && HAVE_EVP_SHA256) # define MUNGE_CIPHER_AES256_FLAG 1 #else # define MUNGE_CIPHER_AES256_FLAG 0 #endif #if HAVE_LIBGCRYPT || HAVE_EVP_SHA256 # define MUNGE_MAC_SHA256_FLAG 1 #else # define MUNGE_MAC_SHA256_FLAG 0 #endif #if HAVE_LIBGCRYPT || HAVE_EVP_SHA512 # define MUNGE_MAC_SHA512_FLAG 1 #else # define MUNGE_MAC_SHA512_FLAG 0 #endif #if HAVE_PKG_BZLIB # define MUNGE_ZIP_BZLIB_FLAG 1 #else # define MUNGE_ZIP_BZLIB_FLAG 0 #endif #if HAVE_PKG_ZLIB # define MUNGE_ZIP_ZLIB_FLAG 1 #else # define MUNGE_ZIP_ZLIB_FLAG 0 #endif /***************************************************************************** * Data Types *****************************************************************************/ struct munge_enum_table { int value; /* munge enumeration or -1 */ const char *string; /* descriptive string or NULL */ int is_valid; /* true (1), false (0), error (-1) */ }; typedef struct munge_enum_table * munge_enum_table_t; /***************************************************************************** * Variables *****************************************************************************/ static struct munge_enum_table _munge_cipher_table[] = { { MUNGE_CIPHER_NONE, "none", 1 }, { MUNGE_CIPHER_DEFAULT, "default", 1 }, { MUNGE_CIPHER_BLOWFISH, "blowfish", 1 }, { MUNGE_CIPHER_CAST5, "cast5", 1 }, { MUNGE_CIPHER_AES128, "aes128", MUNGE_CIPHER_AES128_FLAG }, { MUNGE_CIPHER_AES256, "aes256", MUNGE_CIPHER_AES256_FLAG }, { -1, NULL, -1 } }; static struct munge_enum_table _munge_mac_table[] = { { MUNGE_MAC_NONE, "none", 0 }, { MUNGE_MAC_DEFAULT, "default", 1 }, { MUNGE_MAC_MD5, "md5", 1 }, { MUNGE_MAC_SHA1, "sha1", 1 }, { MUNGE_MAC_RIPEMD160, "ripemd160", 1 }, { MUNGE_MAC_SHA256, "sha256", MUNGE_MAC_SHA256_FLAG }, { MUNGE_MAC_SHA512, "sha512", MUNGE_MAC_SHA512_FLAG }, { -1, NULL, -1 } }; static struct munge_enum_table _munge_zip_table[] = { { MUNGE_ZIP_NONE, "none", 1 }, { MUNGE_ZIP_DEFAULT, "default", 1 }, { MUNGE_ZIP_BZLIB, "bzlib", MUNGE_ZIP_BZLIB_FLAG }, { MUNGE_ZIP_ZLIB, "zlib", MUNGE_ZIP_ZLIB_FLAG }, { -1, NULL, -1 } }; /***************************************************************************** * Prototypes *****************************************************************************/ static munge_enum_table_t _munge_enum_lookup (munge_enum_t type); /***************************************************************************** * Public Functions *****************************************************************************/ int munge_enum_is_valid (munge_enum_t type, int val) { munge_enum_table_t tp; int i; if (!(tp = _munge_enum_lookup (type))) { return (0); } for (i = 0; tp[i].string != NULL; i++) { if (val == tp[i].value) { return (tp[i].is_valid); } } return (0); } const char * munge_enum_int_to_str (munge_enum_t type, int val) { munge_enum_table_t tp; int i; if (!(tp = _munge_enum_lookup (type))) { return (NULL); } for (i = 0; tp[i].string != NULL; i++) { if (val == tp[i].value) { return (tp[i].string); } } return (NULL); } int munge_enum_str_to_int (munge_enum_t type, const char *str) { munge_enum_table_t tp; int i; int n; char *p; int errno_bak, errno_sav; if (!str || !*str) { return (-1); } if (!(tp = _munge_enum_lookup (type))) { return (-1); } /* Check if the given string matches a valid string. * Also determine the number of strings in the array. */ for (i = 0; tp[i].string != NULL; i++) { if (!strcasecmp (str, tp[i].string)) { return (tp[i].value); } } /* Check if the given string matches a valid enum. * Save & restore errno in order to check for strtol() errors. * This check is technically unnecessary since (str == p) should check * for no digits and (*p != '\0') should check for trailing non-digits. * ERANGE is not compared against LONG_MIN or LONG_MAX since these enums * can never get that large. It's just an extra check for the paranoid. */ errno_bak = errno; errno = 0; n = strtol (str, &p, 10); errno_sav = errno; errno = errno_bak; if ((errno_sav != 0) || (str == p) || (*p != '\0')) { return (-1); } if ((n < 0) || (n >= i)) { return (-1); } return (n); } /***************************************************************************** * Private Functions *****************************************************************************/ static munge_enum_table_t _munge_enum_lookup (munge_enum_t type) { switch (type) { case MUNGE_ENUM_CIPHER: return (_munge_cipher_table); case MUNGE_ENUM_MAC: return (_munge_mac_table); case MUNGE_ENUM_ZIP: return (_munge_zip_table); default: return (NULL); } return (NULL); } munge-munge-0.5.15/src/libmunge/m_msg_client.c000066400000000000000000000214171425467526100212440ustar00rootroot00000000000000/***************************************************************************** * Written by Chris Dunlap . * Copyright (C) 2007-2022 Lawrence Livermore National Security, LLC. * Copyright (C) 2002-2007 The Regents of the University of California. * UCRL-CODE-155910. * * This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE). * For details, see . * * MUNGE 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. Additionally for the MUNGE library (libmunge), you * can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation, * either version 3 of the License, or (at your option) any later version. * * MUNGE 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 * and GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * and GNU Lesser General Public License along with MUNGE. If not, see * . *****************************************************************************/ #if HAVE_CONFIG_H # include "config.h" #endif /* HAVE_CONFIG_H */ #include #include #include #include /* include before socket.h for bsd */ #include #include #include #include #include #include #include "auth_send.h" #include "ctx.h" #include "fd.h" #include "m_msg.h" #include "m_msg_client.h" #include "munge_defs.h" #include "str.h" /***************************************************************************** * Prototypes *****************************************************************************/ static munge_err_t _m_msg_client_connect (m_msg_t m, char *path); static munge_err_t _m_msg_client_disconnect (m_msg_t m); static munge_err_t _m_msg_client_millisleep (m_msg_t m, unsigned long msecs); /***************************************************************************** * Public Functions *****************************************************************************/ munge_err_t m_msg_client_xfer (m_msg_t *pm, m_msg_type_t mreq_type, munge_ctx_t ctx) { char *socket; int i; munge_err_t e; m_msg_t mreq, mrsp; m_msg_type_t mrsp_type; if (!pm || !*pm) { return (EMUNGE_SNAFU); } if (!ctx || !(socket = ctx->socket_str)) { socket = MUNGE_SOCKET_NAME; } mreq = *pm; mrsp = NULL; if (mreq_type == MUNGE_MSG_ENC_REQ) { mrsp_type = MUNGE_MSG_ENC_RSP; } else if (mreq_type == MUNGE_MSG_DEC_REQ) { mrsp_type = MUNGE_MSG_DEC_RSP; } else { return (EMUNGE_SNAFU); } i = 1; while (1) { if ((e = _m_msg_client_connect (mreq, socket)) != EMUNGE_SUCCESS) { break; } else if ((e = m_msg_send (mreq, mreq_type, MUNGE_MAXIMUM_REQ_LEN)) != EMUNGE_SUCCESS) { ; /* empty */ } else if (auth_send (mreq) < 0) { e = EMUNGE_SOCKET; } else if ((e = m_msg_create (&mrsp)) != EMUNGE_SUCCESS) { break; } else if ((e = m_msg_bind (mrsp, mreq->sd)) != EMUNGE_SUCCESS) { break; } else if ((e = m_msg_recv (mrsp, mrsp_type, 0)) != EMUNGE_SUCCESS) { ; /* empty */ } else if ((e = _m_msg_client_disconnect (mrsp)) != EMUNGE_SUCCESS) { break; } else if (e == EMUNGE_SUCCESS) { break; } if (i >= MUNGE_SOCKET_RETRY_ATTEMPTS) { break; } if (e == EMUNGE_BAD_LENGTH) { break; } if (mrsp != NULL) { mrsp->sd = -1; /* prevent socket close by destroy() */ m_msg_destroy (mrsp); mrsp = NULL; } if (mreq->sd >= 0) { (void) close (mreq->sd); mreq->sd = -1; } mreq->retry = i; e = _m_msg_client_millisleep (mreq, i * MUNGE_SOCKET_RETRY_MSECS); if (e != EMUNGE_SUCCESS) { break; } i++; } if (mrsp) { *pm = mrsp; mreq->sd = -1; /* prevent socket close by destroy() */ m_msg_destroy (mreq); } return (e); } /***************************************************************************** * Private Functions *****************************************************************************/ static munge_err_t _m_msg_client_connect (m_msg_t m, char *path) { struct stat st; struct sockaddr_un addr; int sd; int n; int i; unsigned long delay_msecs; assert (m != NULL); assert (m->sd < 0); if ((path == NULL) || (*path == '\0')) { m_msg_set_err (m, EMUNGE_SOCKET, strdup ("MUNGE socket name is undefined")); return (EMUNGE_SOCKET); } if (stat (path, &st) < 0) { m_msg_set_err (m, EMUNGE_SOCKET, strdupf ("Failed to access \"%s\": %s (%s)", path, strerror (errno), "Did you start munged?")); return (EMUNGE_SOCKET); } if (!S_ISSOCK (st.st_mode)) { m_msg_set_err (m, EMUNGE_SOCKET, strdupf ("Invalid file type for socket \"%s\"", path)); return (EMUNGE_SOCKET); } if ((sd = socket (PF_UNIX, SOCK_STREAM, 0)) < 0) { m_msg_set_err (m, EMUNGE_SOCKET, strdupf ("Failed to create socket: %s", strerror (errno))); return (EMUNGE_SOCKET); } if (fd_set_nonblocking (sd) < 0) { close (sd); m_msg_set_err (m, EMUNGE_SOCKET, strdupf ("Failed to set nonblocking socket: %s", strerror (errno))); return (EMUNGE_SOCKET); } memset (&addr, 0, sizeof (addr)); addr.sun_family = AF_UNIX; addr.sun_path[ sizeof (addr.sun_path) - 1 ] = '\0'; strncpy (addr.sun_path, path, sizeof (addr.sun_path)); if (addr.sun_path[ sizeof (addr.sun_path) - 1 ] != '\0') { close (sd); m_msg_set_err (m, EMUNGE_OVERFLOW, strdupf ("Exceeded maximum length of %lu bytes " "for socket pathname", sizeof (addr.sun_path))); return (EMUNGE_OVERFLOW); } i = 1; while (1) { /* * If a call to connect() for a Unix domain stream socket finds that * the listening socket's queue is full, ECONNREFUSED is returned * immediately. (cf, Stevens UNPv1, s14.4, p378) * If ECONNREFUSED, try again up to MUNGE_SOCKET_CONNECT_ATTEMPTS. */ n = connect (sd, (struct sockaddr *) &addr, sizeof (addr)); if (n == 0) { break; } if (errno == EINTR) { continue; } if (errno != ECONNREFUSED) { break; } if (i >= MUNGE_SOCKET_CONNECT_ATTEMPTS) { break; } delay_msecs = i * MUNGE_SOCKET_CONNECT_RETRY_MSECS; if (_m_msg_client_millisleep (m, delay_msecs) != EMUNGE_SUCCESS) { break; } i++; } if (n < 0) { close (sd); m_msg_set_err (m, EMUNGE_SOCKET, strdupf ("Failed to connect to \"%s\": %s", path, strerror (errno))); return (EMUNGE_SOCKET); } m->sd = sd; return (EMUNGE_SUCCESS); } static munge_err_t _m_msg_client_disconnect (m_msg_t m) { munge_err_t e; assert (m != NULL); assert (m->sd >= 0); if (close (m->sd) < 0) { m_msg_set_err (m, EMUNGE_SOCKET, strdupf ("Failed to close socket: %s", strerror (errno))); e = EMUNGE_SOCKET; } else { e = EMUNGE_SUCCESS; } m->sd = -1; return (e); } static munge_err_t _m_msg_client_millisleep (m_msg_t m, unsigned long msecs) { /* Sleeps for 'msecs' milliseconds. * Returns EMUNGE_SUCCESS on success, * or EMUNGE_SNAFU on error (with additional info if 'm' is not NULL). */ struct timespec ts; int rv; ts.tv_sec = msecs / 1000; ts.tv_nsec = (msecs % 1000) * 1000 * 1000; while (1) { rv = nanosleep (&ts, &ts); if (rv == 0) { break; } else if (errno == EINTR) { continue; } else if (m != NULL) { m_msg_set_err (m, EMUNGE_SNAFU, strdupf ("Failed nanosleep: %s", strerror (errno))); } return (EMUNGE_SNAFU); } return (EMUNGE_SUCCESS); } munge-munge-0.5.15/src/libmunge/m_msg_client.h000066400000000000000000000032501425467526100212440ustar00rootroot00000000000000/***************************************************************************** * Written by Chris Dunlap . * Copyright (C) 2007-2022 Lawrence Livermore National Security, LLC. * Copyright (C) 2002-2007 The Regents of the University of California. * UCRL-CODE-155910. * * This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE). * For details, see . * * MUNGE 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. Additionally for the MUNGE library (libmunge), you * can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation, * either version 3 of the License, or (at your option) any later version. * * MUNGE 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 * and GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * and GNU Lesser General Public License along with MUNGE. If not, see * . *****************************************************************************/ #ifndef M_MSG_CLIENT_H #define M_MSG_CLIENT_H #include #include "m_msg.h" munge_err_t m_msg_client_xfer ( m_msg_t *pm, m_msg_type_t mreq_type, munge_ctx_t ctx); #endif /* !M_MSG_CLIENT_H */ munge-munge-0.5.15/src/libmunge/munge.3.in000066400000000000000000000174571425467526100202550ustar00rootroot00000000000000.\"**************************************************************************** .\" Written by Chris Dunlap . .\" Copyright (C) 2007-2022 Lawrence Livermore National Security, LLC. .\" Copyright (C) 2002-2007 The Regents of the University of California. .\" UCRL-CODE-155910. .\" .\" This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE). .\" For details, see . .\" .\" MUNGE 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. Additionally for the MUNGE library (libmunge), you .\" can redistribute it and/or modify it under the terms of the GNU Lesser .\" General Public License as published by the Free Software Foundation, .\" either version 3 of the License, or (at your option) any later version. .\" .\" MUNGE 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 .\" and GNU Lesser General Public License for more details. .\" .\" You should have received a copy of the GNU General Public License .\" and GNU Lesser General Public License along with MUNGE. If not, see .\" . .\"**************************************************************************** .TH MUNGE 3 "@DATE@" "@PACKAGE@-@VERSION@" "MUNGE Uid 'N' Gid Emporium" .SH NAME munge_encode, munge_decode, munge_strerror \- MUNGE core functions .SH SYNOPSIS .nf .B #include .sp .BI "munge_err_t munge_encode (char **" cred ", munge_ctx_t " ctx , .BI " const void *" buf ", int " len ); .sp .BI "munge_err_t munge_decode (const char *" cred ", munge_ctx_t " ctx , .BI " void **" buf ", int *" len ", uid_t *" uid ", gid_t *" gid ); .sp .BI "const char * munge_strerror (munge_err_t " e ); .sp .B cc `pkg\-config \-\-cflags \-\-libs munge` \-o foo foo.c .fi .SH DESCRIPTION The \fBmunge_encode\fR() function creates a credential contained in a NUL-terminated base64 string. A payload specified by a buffer \fIbuf\fR of length \fIlen\fR can be encapsulated in as well. If the MUNGE context \fIctx\fR is NULL, the default context will be used. A pointer to the resulting credential is returned via \fIcred\fR; on error, it is set to NULL. The caller is responsible for freeing the memory referenced by \fIcred\fR. .PP The \fBmunge_decode\fR() function validates the NUL-terminated credential \fIcred\fR. If the MUNGE context \fIctx\fR is not NULL, it will be set to that used to encode the credential. If \fIbuf\fR and \fIlen\fR are not NULL, memory will be allocated for the encapsulated payload, \fIbuf\fR will be set to point to this data, and \fIlen\fR will be set to its length. An additional NUL character will be appended to this payload data but not included in its length. If no payload exists, \fIbuf\fR will be set to NULL and \fIlen\fR will be set to 0. For certain errors (i.e., \fBEMUNGE_CRED_EXPIRED\fR, \fBEMUNGE_CRED_REWOUND\fR, \fBEMUNGE_CRED_REPLAYED\fR), payload memory will still be allocated if necessary. The caller is responsible for freeing the memory referenced by \fIbuf\fR. If \fIuid\fR or \fIgid\fR is not NULL, they will be set to the UID/GID of the process that created the credential. .PP The \fBmunge_strerror\fR() function returns a descriptive text string describing the MUNGE error number \fIe\fR. .SH RETURN VALUE The \fBmunge_encode\fR() and \fBmunge_decode\fR() functions return \fBEMUNGE_SUCCESS\fR on success, or a MUNGE error otherwise. If a MUNGE context was used, it may contain a more detailed error message accessible via \fBmunge_ctx_strerror\fR(). .PP The \fBmunge_strerror\fR() function returns a pointer to a NUL-terminated constant text string; this string should not be freed or modified by the caller. .SH ERRORS .TP .B EMUNGE_SUCCESS Success. .TP .B EMUNGE_SNAFU Internal error. .TP .B EMUNGE_BAD_ARG Invalid argument. .TP .B EMUNGE_BAD_LENGTH Exceeded the maximum message length as specified by the \fBmunged\fR configuration. .TP .B EMUNGE_OVERFLOW Exceeded the maximum length of a buffer. .TP .B EMUNGE_NO_MEMORY Unable to allocate the requisite memory. .TP .B EMUNGE_SOCKET Unable to communicate with the daemon on the domain socket. .TP .B EMUNGE_BAD_CRED The credential does not match the specified format. .TP .B EMUNGE_BAD_VERSION The credential contains an unsupported version number. .TP .B EMUNGE_BAD_CIPHER The credential contains an unsupported cipher type. .TP .B EMUNGE_BAD_MAC The credential contains an unsupported MAC type. .TP .B EMUNGE_BAD_ZIP The credential contains an unsupported compression type. .TP .B EMUNGE_BAD_REALM The credential contains an unrecognized security realm. .TP .B EMUNGE_CRED_INVALID The credential is invalid. This means the credential could not be successfully decoded. More than likely, the secret keys on the encoding and decoding hosts do not match. Another possibility is that the credential has been altered since it was encoded. .TP .B EMUNGE_CRED_EXPIRED The credential has expired. This means more than TTL seconds have elapsed since the credential was encoded. Another possibility is that the clocks on the encoding and decoding hosts are out of sync. .TP .B EMUNGE_CRED_REWOUND The credential appears to have been encoded at some point in the future. This means the clock on the decoding host is slower than that of the encoding host by more than the allowable clock skew. More than likely, the clocks on the encoding and decoding hosts are out of sync. .TP .B EMUNGE_CRED_REPLAYED The credential has been previously decoded on this host. .TP .B EMUNGE_CRED_UNAUTHORIZED The client is not authorized to decode the credential based upon the effective user and/or group ID of the process. .SH EXAMPLE The following example program illustrates the use of a MUNGE credential to ascertain the effective user and group ID of the encoding process. .PP .nf #include /* for printf() */ #include /* for exit() & free() */ #include /* for uid_t & gid_t */ #include .sp int main (int argc, char *argv[]) { char *cred; munge_err_t err; uid_t uid; gid_t gid; .sp err = munge_encode (&cred, NULL, NULL, 0); .sp if (err != EMUNGE_SUCCESS) { fprintf (stderr, "ERROR: %s\\n", munge_strerror (err)); exit (1); } err = munge_decode (cred, NULL, NULL, NULL, &uid, &gid); .sp if (err != EMUNGE_SUCCESS) { fprintf (stderr, "ERROR: %s\\n", munge_strerror (err)); exit (1); } printf ("uid=%d gid=%d\\n", uid, gid); free (cred); exit (0); } .fi .SH NOTES Both \fBmunge_encode\fR() and \fBmunge_decode\fR() may allocate memory that the caller is responsible for freeing. Failure to do so will result in a memory leak. .SH AUTHOR Chris Dunlap .SH COPYRIGHT Copyright (C) 2007-2022 Lawrence Livermore National Security, LLC. .br Copyright (C) 2002-2007 The Regents of the University of California. .PP MUNGE 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. .PP Additionally for the MUNGE library (libmunge), you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. .SH "SEE ALSO" .BR munge (1), .BR remunge (1), .BR unmunge (1), .BR munge_ctx (3), .BR munge_enum (3), .BR munge (7), .BR munged (8), .BR mungekey (8). .PP \fBhttps://dun.github.io/munge/\fR munge-munge-0.5.15/src/libmunge/munge.h000066400000000000000000000327001425467526100177210ustar00rootroot00000000000000/***************************************************************************** * Written by Chris Dunlap . * Copyright (C) 2007-2022 Lawrence Livermore National Security, LLC. * Copyright (C) 2002-2007 The Regents of the University of California. * UCRL-CODE-155910. * * This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE). * For details, see . * * MUNGE 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. Additionally for the MUNGE library (libmunge), you * can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation, * either version 3 of the License, or (at your option) any later version. * * MUNGE 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 * and GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * and GNU Lesser General Public License along with MUNGE. If not, see * . *****************************************************************************/ #ifndef MUNGE_H #define MUNGE_H #include /***************************************************************************** * Got C++? *****************************************************************************/ #undef BEGIN_C_DECLS #undef END_C_DECLS #ifdef __cplusplus # define BEGIN_C_DECLS extern "C" { # define END_C_DECLS } #else /* !__cplusplus */ # define BEGIN_C_DECLS /* empty */ # define END_C_DECLS /* empty */ #endif /* !__cplusplus */ /***************************************************************************** * Data Types *****************************************************************************/ /* MUNGE context opaque data type */ typedef struct munge_ctx * munge_ctx_t; /* MUNGE context options */ typedef enum munge_opt { MUNGE_OPT_CIPHER_TYPE = 0, /* symmetric cipher type (int) */ MUNGE_OPT_MAC_TYPE = 1, /* message auth code type (int) */ MUNGE_OPT_ZIP_TYPE = 2, /* compression type (int) */ MUNGE_OPT_REALM = 3, /* security realm (str) */ MUNGE_OPT_TTL = 4, /* time-to-live (int) */ MUNGE_OPT_ADDR4 = 5, /* src IPv4 addr (struct in_addr) */ MUNGE_OPT_ENCODE_TIME = 6, /* time when cred encoded (time_t) */ MUNGE_OPT_DECODE_TIME = 7, /* time when cred decoded (time_t) */ MUNGE_OPT_SOCKET = 8, /* socket for comm w/ daemon (str) */ MUNGE_OPT_UID_RESTRICTION = 9, /* UID able to decode cred (uid_t) */ MUNGE_OPT_GID_RESTRICTION = 10 /* GID able to decode cred (gid_t) */ } munge_opt_t; /* MUNGE symmetric cipher types */ typedef enum munge_cipher { MUNGE_CIPHER_NONE = 0, /* encryption disabled */ MUNGE_CIPHER_DEFAULT = 1, /* default ciphr specified by daemon */ MUNGE_CIPHER_BLOWFISH = 2, /* Blowfish CBC w/ 64b-blk/128b-key */ MUNGE_CIPHER_CAST5 = 3, /* CAST5 CBC w/ 64b-blk/128b-key */ MUNGE_CIPHER_AES128 = 4, /* AES CBC w/ 128b-blk/128b-key */ MUNGE_CIPHER_AES256 = 5, /* AES CBC w/ 128b-blk/256b-key */ MUNGE_CIPHER_LAST_ITEM } munge_cipher_t; /* MUNGE message authentication code types */ typedef enum munge_mac { MUNGE_MAC_NONE = 0, /* mac disabled -- invalid, btw */ MUNGE_MAC_DEFAULT = 1, /* default mac specified by daemon */ MUNGE_MAC_MD5 = 2, /* MD5 w/ 128b-digest */ MUNGE_MAC_SHA1 = 3, /* SHA-1 w/ 160b-digest */ MUNGE_MAC_RIPEMD160 = 4, /* RIPEMD-160 w/ 160b-digest */ MUNGE_MAC_SHA256 = 5, /* SHA-256 w/ 256b-digest */ MUNGE_MAC_SHA512 = 6, /* SHA-512 w/ 512b-digest */ MUNGE_MAC_LAST_ITEM } munge_mac_t; /* MUNGE compression types */ typedef enum munge_zip { MUNGE_ZIP_NONE = 0, /* compression disabled */ MUNGE_ZIP_DEFAULT = 1, /* default zip specified by daemon */ MUNGE_ZIP_BZLIB = 2, /* bzip2 by Julian Seward */ MUNGE_ZIP_ZLIB = 3, /* zlib "deflate" by Gailly & Adler */ MUNGE_ZIP_LAST_ITEM } munge_zip_t; /* MUNGE credential time-to-live (in seconds) */ typedef enum munge_ttl { MUNGE_TTL_MAXIMUM = -1, /* maximum ttl allowed by daemon */ MUNGE_TTL_DEFAULT = 0 /* default ttl specified by daemon */ } munge_ttl_t; /* MUNGE UID restrictions for credential decoding */ typedef enum munge_uid { MUNGE_UID_ANY = -1 /* do not restrict decode via uid */ } munge_uid_t; /* MUNGE GID restrictions for credential decoding */ typedef enum munge_gid { MUNGE_GID_ANY = -1 /* do not restrict decode via gid */ } munge_gid_t; /* MUNGE enum types for str/int conversions */ typedef enum munge_enum { MUNGE_ENUM_CIPHER = 0, /* cipher enum type */ MUNGE_ENUM_MAC = 1, /* mac enum type */ MUNGE_ENUM_ZIP = 2 /* zip enum type */ } munge_enum_t; /* MUNGE error codes * * Error codes are in the range [1..255] in order to provide * a meaningful return status when returned via exit(). */ typedef enum munge_err { EMUNGE_SUCCESS = 0, /* Success: Whoohoo! */ EMUNGE_SNAFU = 1, /* Internal error: Doh! */ EMUNGE_BAD_ARG = 2, /* Invalid argument */ EMUNGE_BAD_LENGTH = 3, /* Exceeded maximum message length */ EMUNGE_OVERFLOW = 4, /* Buffer overflow */ EMUNGE_NO_MEMORY = 5, /* Out of memory */ EMUNGE_SOCKET = 6, /* Socket communication error */ EMUNGE_TIMEOUT = 7, /* Socket timeout (NOT USED) */ EMUNGE_BAD_CRED = 8, /* Invalid credential format */ EMUNGE_BAD_VERSION = 9, /* Invalid credential version */ EMUNGE_BAD_CIPHER = 10, /* Invalid cipher type */ EMUNGE_BAD_MAC = 11, /* Invalid MAC type */ EMUNGE_BAD_ZIP = 12, /* Invalid compression type */ EMUNGE_BAD_REALM = 13, /* Unrecognized security realm */ EMUNGE_CRED_INVALID = 14, /* Invalid credential */ EMUNGE_CRED_EXPIRED = 15, /* Expired credential */ EMUNGE_CRED_REWOUND = 16, /* Rewound credential, future ctime */ EMUNGE_CRED_REPLAYED = 17, /* Replayed credential */ EMUNGE_CRED_UNAUTHORIZED = 18 /* Unauthorized credential decode */ } munge_err_t; /* MUNGE defines for backwards-compatibility */ #define MUNGE_CIPHER_AES_128 MUNGE_CIPHER_AES128 /***************************************************************************** * Primary Functions *****************************************************************************/ BEGIN_C_DECLS munge_err_t munge_encode (char **cred, munge_ctx_t ctx, const void *buf, int len); /* * Creates a credential contained in a NUL-terminated base64 string. * A payload specified by a buffer [buf] of length [len] can be * encapsulated in as well. * If the munge context [ctx] is NULL, the default context will be used. * A pointer to the resulting credential is returned via [cred]; the caller * is responsible for freeing this memory. * Returns EMUNGE_SUCCESS if the credential is successfully created; * o/w, sets [cred] to NULL and returns the munge error number. * If a [ctx] was specified, it may contain a more detailed error * message accessible via munge_ctx_strerror(). */ munge_err_t munge_decode (const char *cred, munge_ctx_t ctx, void **buf, int *len, uid_t *uid, gid_t *gid); /* * Validates the NUL-terminated credential [cred]. * If the munge context [ctx] is not NULL, it will be set to that used * to encode the credential. * If [buf] and [len] are not NULL, memory will be allocated for the * encapsulated payload, [buf] will be set to point to this data, and [len] * will be set to its length. An additional NUL character will be appended * to this payload data but not included in its length. If no payload * exists, [buf] will be set to NULL and [len] will be set to 0. * For certain errors (ie, EMUNGE_CRED_EXPIRED, EMUNGE_CRED_REWOUND, * EMUNGE_CRED_REPLAYED), payload memory will still be allocated if * necessary. The caller is responsible for freeing this memory. * If [uid] or [gid] is not NULL, they will be set to the UID/GID of the * process that created the credential. * Returns EMUNGE_SUCCESS if the credential is valid; o/w, returns the * munge error number. If a [ctx] was specified, it may contain a * more detailed error message accessible via munge_ctx_strerror(). */ const char * munge_strerror (munge_err_t e); /* * Returns a descriptive string describing the munge errno [e]. * This string should not be freed or modified by the caller. */ END_C_DECLS /***************************************************************************** * Context Functions ***************************************************************************** * The context passed to munge_encode() is treated read-only except for the * error message that is set when an error is returned. * The context passed to munge_decode() is set according to the context used * to encode the credential; however, on error, its settings may be in a * state which is invalid for encoding. * Consequently, separate contexts should be used for encoding and decoding. * A context should not be shared between threads unless it is protected by * a mutex; however, a better alternative is to use a separate context * (or two) for each thread, either by creating a new one or copying an * existing one. *****************************************************************************/ BEGIN_C_DECLS munge_ctx_t munge_ctx_create (void); /* * Creates and returns a new munge context or NULL on error. * Abandoning a context without calling munge_ctx_destroy() will result * in a memory leak. */ munge_ctx_t munge_ctx_copy (munge_ctx_t ctx); /* * Copies the context [ctx], returning a new munge context or NULL on error. * Abandoning a context without calling munge_ctx_destroy() will result * in a memory leak. */ void munge_ctx_destroy (munge_ctx_t ctx); /* * Destroys the context [ctx]. */ const char * munge_ctx_strerror (munge_ctx_t ctx); /* * Returns a descriptive text string describing the munge error number * according to the context [ctx], or NULL if no error condition exists. * This message may be more detailed than that returned by munge_strerror(). * This string should not be freed or modified by the caller. */ munge_err_t munge_ctx_get (munge_ctx_t ctx, int opt, ...); /* * Gets the value for the option [opt] (of munge_opt_t) associated with the * munge context [ctx], storing the result in the subsequent pointer * argument. Refer to the munge_opt_t enum comments for argument types. * If the result is a string, that string should not be freed or modified * by the caller. * Returns EMUNGE_SUCCESS on success; o/w, returns the munge error number. */ munge_err_t munge_ctx_set (munge_ctx_t ctx, int opt, ...); /* * Sets the value for the option [opt] (of munge_opt_t) associated with the * munge context [ctx], using the value of the subsequent argument. * Refer to the munge_opt_t enum comments for argument types. * Returns EMUNGE_SUCCESS on success; o/w, returns the munge error number. */ END_C_DECLS /***************************************************************************** * Enumeration Functions *****************************************************************************/ BEGIN_C_DECLS int munge_enum_is_valid (munge_enum_t type, int val); /* * Returns non-zero if the given value [val] is a valid enumeration of * the specified type [type] in the software configuration as currently * compiled; o/w, returns 0. * Some enumerations corresond to options that can only be enabled at * compile-time. */ const char * munge_enum_int_to_str (munge_enum_t type, int val); /* * Converts the munge enumeration [val] of the specified type [type] * into a text string. * Returns a NUL-terminated constant text string, or NULL on error; * this string should not be freed or modified by the caller. */ int munge_enum_str_to_int (munge_enum_t type, const char *str); /* * Converts the NUL-terminated case-insensitive string [str] into the * corresponding munge enumeration of the specified type [type]. * Returns a munge enumeration on success (>=0), or -1 on error. */ END_C_DECLS #endif /* !MUNGE_H */ munge-munge-0.5.15/src/libmunge/munge_ctx.3.in000066400000000000000000000343401425467526100211210ustar00rootroot00000000000000.\"**************************************************************************** .\" Written by Chris Dunlap . .\" Copyright (C) 2007-2022 Lawrence Livermore National Security, LLC. .\" Copyright (C) 2002-2007 The Regents of the University of California. .\" UCRL-CODE-155910. .\" .\" This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE). .\" For details, see . .\" .\" MUNGE 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. Additionally for the MUNGE library (libmunge), you .\" can redistribute it and/or modify it under the terms of the GNU Lesser .\" General Public License as published by the Free Software Foundation, .\" either version 3 of the License, or (at your option) any later version. .\" .\" MUNGE 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 .\" and GNU Lesser General Public License for more details. .\" .\" You should have received a copy of the GNU General Public License .\" and GNU Lesser General Public License along with MUNGE. If not, see .\" . .\"**************************************************************************** .TH MUNGE_CTX 3 "@DATE@" "@PACKAGE@-@VERSION@" "MUNGE Uid 'N' Gid Emporium" .SH NAME munge_ctx_create, munge_ctx_copy, munge_ctx_destroy, munge_ctx_strerror, munge_ctx_get, munge_ctx_set \- MUNGE context functions .SH SYNOPSIS .nf .B #include .sp .BI "munge_ctx_t munge_ctx_create (void);" .sp .BI "munge_ctx_t munge_ctx_copy (munge_ctx_t " ctx ); .sp .BI "void munge_ctx_destroy (munge_ctx_t " ctx ); .sp .BI "const char * munge_ctx_strerror (munge_ctx_t " ctx ); .sp .BI "munge_err_t munge_ctx_get (munge_ctx_t " ctx ", munge_opt_t " opt ", ...);" .sp .BI "munge_err_t munge_ctx_set (munge_ctx_t " ctx ", munge_opt_t " opt ", ...);" .sp .B cc `pkg\-config \-\-cflags \-\-libs munge` \-o foo foo.c .fi .SH DESCRIPTION The \fBmunge_ctx_create\fR() function creates and returns a new MUNGE context, or NULL on error. .PP The \fBmunge_ctx_copy\fR() function copies the context \fIctx\fR and returns a new MUNGE context, or NULL on error. .PP The \fBmunge_ctx_destroy\fR() function destroys the context \fIctx\fR. .PP The \fBmunge_ctx_strerror\fR() function returns a descriptive text string describing the MUNGE error number according to the context \fIctx\fR, or NULL if no error condition exists. This may provide a more detailed error message than that returned by \fBmunge_strerror\fR(). .PP The \fBmunge_ctx_get\fR() function gets the value for the option \fIopt\fR associated with the MUNGE context \fIctx\fR, storing the result in the subsequent pointer argument. If the result is a string, that string should not be freed or modified by the caller. .PP The \fBmunge_ctx_set\fR() function sets the value for the option \fIopt\fR associated with the MUNGE context \fIctx\fR, using the value of the subsequent argument. .SH RETURN VALUE The \fBmunge_ctx_create\fR() and \fBmunge_ctx_copy\fR() functions return a newly allocated MUNGE context, or NULL on error. .PP The \fBmunge_ctx_strerror\fR() function returns a pointer to a NUL-terminated constant text string, or NULL if no error condition exists. This string should not be freed or modified by the caller. .PP The \fBmunge_ctx_get\fR() and \fBmunge_ctx_set\fR() functions return \fBEMUNGE_SUCCESS\fR on success, or a MUNGE error number otherwise. .SH "CONTEXT OPTIONS" The following context options can be queried via \fBmunge_ctx_get\fR() or specified via \fBmunge_ctx_set\fR(). The type following each enumeration is the variable type used for the subsequent argument in \fBmunge_ctx_set\fR(), or the variable type of a pointer used for the subsequent argument in \fBmunge_ctx_get\fR(). .TP \fBMUNGE_OPT_CIPHER_TYPE\fR , \fIint\fR Get or set the cipher type (see \fBCIPHER TYPES\fR). .TP \fBMUNGE_OPT_MAC_TYPE\fR , \fIint\fR Get or set the MAC type (see \fBMAC TYPES\fR). .TP \fBMUNGE_OPT_ZIP_TYPE\fR , \fIint\fR Get or set the compression type (see \fBCOMPRESSION TYPES\fR). .TP \fBMUNGE_OPT_REALM\fR , \fIchar *\fR Get or set the security realm, where the \fIchar *\fR type is a NUL-terminated character string. The string returned by \fBmunge_ctx_get\fR() should not be freed or modified by the caller. \fBNOT CURRENTLY SUPPORTED\fR. .TP \fBMUNGE_OPT_TTL\fR , \fIint\fR Get or set the time-to-live (in seconds) (see \fBTTL TYPES\fR). This value controls how long the credential is valid once it has been encoded. .TP \fBMUNGE_OPT_ADDR4\fR , \fIstruct in_addr\fR Get the IPv4 address of the host where the credential was encoded. This option cannot be explicitly set. .TP \fBMUNGE_OPT_ENCODE_TIME\fR , \fItime_t\fR Get the time (in seconds since the epoch) at which the credential was encoded. This option cannot be explicitly set. .TP \fBMUNGE_OPT_DECODE_TIME\fR , \fItime_t\fR Get the time (in seconds since the epoch) at which the credential was decoded. This option cannot be explicitly set. .TP \fBMUNGE_OPT_SOCKET\fR , \fIchar *\fR Get or set the local domain socket for connecting with \fBmunged\fR, where the \fIchar *\fR type is a NUL-terminated character string. The string returned by \fBmunge_ctx_get\fR() should not be freed or modified by the caller. .TP \fBMUNGE_OPT_UID_RESTRICTION\fR , \fIuid_t\fR Get or set the UID allowed to decode the credential (see \fBUID & GID TYPES\fR). This value will be matched against the effective user ID of the process requesting the credential decode. .TP \fBMUNGE_OPT_GID_RESTRICTION\fR , \fIgid_t\fR Get or set the GID allowed to decode the credential (see \fBUID & GID TYPES\fR). This value will be matched against the effective group ID of the process requesting the credential decode, as well as each supplementary group of which the effective user ID of that process is a member. .SH "CIPHER TYPES" Credentials can be encrypted using the secret key shared by all \fBmunged\fR daemons within a security realm. Anyone having access to this key can use it to decrypt a credential, thereby bypassing any restrictions being imposed by \fBmunged\fR. .TP .B MUNGE_CIPHER_NONE Specify that encryption is to be disabled. .TP .B MUNGE_CIPHER_DEFAULT Specify the default according to the \fBmunged\fR configuration. .TP .B MUNGE_CIPHER_BLOWFISH Specify the Blowfish cipher designed by Bruce Schneier. This cipher has a 64-bit block-size and a variable key length. MUNGE uses it with a 128-bit key in CBC mode. It is a fast block cipher but suffers from a slow key setup time. Consequently, it underperforms when generating small credentials. .TP .B MUNGE_CIPHER_CAST5 Specify the CAST5 cipher designed by Carlisle Adams and Stafford Tavares. This cipher has a 64-bit block-size and a variable key length. MUNGE uses it with a 128-bit key in CBC mode. .TP .B MUNGE_CIPHER_AES128 Specify the AES (Advanced Encryption Standard) cipher, also known as Rijndael. It was designed by Joan Daemen and Vincent Rijmen. This cipher has a 128-bit block-size and a key length of 128, 192, or 256 bits. MUNGE uses it here with a 128-bit key in CBC mode. .TP .B MUNGE_CIPHER_AES256 Specify the AES (Advanced Encryption Standard) cipher, also known as Rijndael. It was designed by Joan Daemen and Vincent Rijmen. This cipher has a 128-bit block-size and a key length of 128, 192, or 256 bits. MUNGE uses it here with a 256-bit key in CBC mode. Currently, \fBMUNGE_CIPHER_AES256\fR requires the use of \fBMUNGE_MAC_SHA256\fR. .SH "MAC TYPES" The message authentication code (MAC) is a required component of the credential; consequently, it cannot be disabled. .TP .B MUNGE_MAC_DEFAULT Specify the default according to the \fBmunged\fR configuration. .TP .B MUNGE_MAC_MD5 Specify the MD5 algorithm designed by Ron Rivest and published in 1991. This algorithm has a 128-bit message digest. In 2004, a successful collision attack against MD5 was demonstrated. In 2009, a theoretical pre-image attack against MD5 was published. Consequently, use of MD5 is not recommended due to its lower security margin. .TP .B MUNGE_MAC_SHA1 Specify the SHA-1 algorithm designed by the National Security Agency and published in 1995; this is the successor to the original Secure Hash Algorithm (now called SHA-0) published in 1993. This algorithm has a 160-bit message digest. In 2005, successful collision attacks were demonstrated against SHA-1. In 2017, a successful identical-prefix collision attack (SHAttered) was announced. In 2020, a successful chosen-prefix collision attack (SHA-1 is a Shambles) was announced. Since a pre-image attack has not yet been demonstrated, SHA-1 should still be safe to use within MUNGE; however, use of a SHA-2 hash function (such as SHA-256 or SHA-512) should be preferred. .TP .B MUNGE_MAC_RIPEMD160 Specify the RIPEMD-160 (RACE Integrity Primitives Evaluation Message Digest) algorithm designed in Europe by Hans Dobbertin, Antoon Bosselaers, and Bart Preneel, and published in 1996. This algorithm has a 160-bit message digest. It is somewhat less popular than SHA-1 and correspondingly less well studied. While slower than SHA-1, it is believed to have a slightly better security margin. .TP .B MUNGE_MAC_SHA256 Specify the SHA-256 algorithm designed by the National Security Agency and published in 2002; this is one of the SHA-2 variants in the Secure Hash Algorithm family. This algorithm has a 256-bit message digest. In 2006, NIST began encouraging the use of the SHA-2 family of hash functions for all new applications and protocols. .TP .B MUNGE_MAC_SHA512 Specify the SHA-512 algorithm designed by the National Security Agency and published in 2002; this is one of the SHA-2 variants in the Secure Hash Algorithm family. This algorithm has a 512-bit message digest. In 2006, NIST began encouraging the use of the SHA-2 family of hash functions for all new applications and protocols. .SH "COMPRESSION TYPES" If a compression type is specified, a payload-bearing credential will be compressed accordingly. However, if the resulting compressed data is larger than the original uncompressed data, the uncompressed data will be restored and compression will be disabled for that credential. .TP .B MUNGE_ZIP_NONE Specify that compression is to be disabled. This is the recommended setting unless there is a payload of sufficient size to compress. .TP .B MUNGE_ZIP_DEFAULT Specify the default according to the \fBmunged\fR configuration. .TP .B MUNGE_ZIP_BZLIB Specify the bzip2 library developed by Julian Seward. This is slower and uses more memory, but generally gets better compression on larger payloads. .TP .B MUNGE_ZIP_ZLIB Specify the zlib library developed by Jean-loup Gailly and Mark Adler. This is faster and uses less memory, but gets pretty good compression nonetheless. .SH "TTL TYPES" The time-to-live value specifies the number of seconds after the encode-time that the credential is considered valid. In addition to specifying an integer value, the following types are available. .TP .B MUNGE_TTL_MAXIMUM Specify the maximum allowed by the \fBmunged\fR configuration. .TP .B MUNGE_TTL_DEFAULT Specify the default according to the \fBmunged\fR configuration. .SH "UID & GID TYPES" The UID and GID restrictions can be used to restrict the decoding of the credential based on the effective user and group ID of the requesting process. In addition to specifying an integer value, the following types are available. .TP .B MUNGE_UID_ANY Specify that no UID restriction is to take effect; this is the default behavior. .TP .B MUNGE_GID_ANY Specify that no GID restriction is to take effect; this is the default behavior. .SH ERRORS Refer to \fBmunge\fR(3) for a complete list of errors. .SH EXAMPLE The following example program illustrates the use of the MUNGE context to query the location of the \fBmunged\fR domain socket. .PP .nf #include /* for printf() */ #include /* for exit() */ #include .sp int main (int argc, char *argv[]) { munge_ctx_t ctx; munge_err_t err; char *str; .sp if (!(ctx = munge_ctx_create ())) { fprintf (stderr, "ERROR: Unable to create MUNGE context\\n"); exit (1); } err = munge_ctx_get (ctx, MUNGE_OPT_SOCKET, &str); .sp if (err != EMUNGE_SUCCESS) { fprintf (stderr, "ERROR: %s\\n", munge_ctx_strerror (ctx)); exit (1); } printf ("socket=%s\\n", str); /* * Note that 'str' is not to be free()d since * it points to a string within the 'ctx'. */ munge_ctx_destroy (ctx); exit (0); } .fi .SH NOTES Abandoning a new or copied MUNGE context without destroying it will result in a memory leak. .PP The context passed to \fBmunge_encode\fR() is treated read-only except for the error message that is set when an error is returned. The context passed to \fBmunge_decode\fR() is set according to the context used to encode the credential; however, on error, its settings may be in a state which is invalid for encoding. Consequently, separate contexts should be used for encoding and decoding. .PP A context should not be shared between threads unless it is protected by a mutex; however, a better alternative is to use a separate context (or two) for each thread, either by creating a new one via \fBmunge_ctx_create\fR() or copying an existing one via \fBmunge_ctx_copy\fR(). .SH AUTHOR Chris Dunlap .SH COPYRIGHT Copyright (C) 2007-2022 Lawrence Livermore National Security, LLC. .br Copyright (C) 2002-2007 The Regents of the University of California. .PP MUNGE 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. .PP Additionally for the MUNGE library (libmunge), you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. .SH "SEE ALSO" .BR munge (1), .BR remunge (1), .BR unmunge (1), .BR munge (3), .BR munge_enum (3), .BR munge (7), .BR munged (8), .BR mungekey (8). .PP \fBhttps://dun.github.io/munge/\fR munge-munge-0.5.15/src/libmunge/munge_enum.3.in000066400000000000000000000114071425467526100212660ustar00rootroot00000000000000.\"**************************************************************************** .\" Written by Chris Dunlap . .\" Copyright (C) 2007-2022 Lawrence Livermore National Security, LLC. .\" Copyright (C) 2002-2007 The Regents of the University of California. .\" UCRL-CODE-155910. .\" .\" This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE). .\" For details, see . .\" .\" MUNGE 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. Additionally for the MUNGE library (libmunge), you .\" can redistribute it and/or modify it under the terms of the GNU Lesser .\" General Public License as published by the Free Software Foundation, .\" either version 3 of the License, or (at your option) any later version. .\" .\" MUNGE 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 .\" and GNU Lesser General Public License for more details. .\" .\" You should have received a copy of the GNU General Public License .\" and GNU Lesser General Public License along with MUNGE. If not, see .\" . .\"**************************************************************************** .TH MUNGE_ENUM 3 "@DATE@" "@PACKAGE@-@VERSION@" "MUNGE Uid 'N' Gid Emporium" .SH NAME munge_enum_is_valid, munge_enum_int_to_str, munge_enum_str_to_int \- MUNGE enumeration functions .SH SYNOPSIS .nf .B #include .sp .BI "int munge_enum_is_valid (munge_enum_t " type ", int " val ); .sp .BI "const char * munge_enum_int_to_str (munge_enum_t " type ", int " val ); .sp .BI "int munge_enum_str_to_int (munge_enum_t " type ", const char *" str ); .sp .B cc `pkg\-config \-\-cflags \-\-libs munge` \-o foo foo.c .fi .SH DESCRIPTION The \fBmunge_enum_is_valid\fR() function checks if the given value \fIval\fR is a valid MUNGE enumeration of the specified type \fItype\fR in the software configuration as currently compiled. Some enumerations correspond to options that can only be enabled at compile-time. .PP The \fBmunge_enum_int_to_str\fR() function converts the MUNGE enumeration \fIval\fR of the specified type \fItype\fR into a text string. .PP The \fBmunge_enum_str_to_int\fR() function converts the NUL-terminated case-insensitive string \fIstr\fR into the corresponding MUNGE enumeration of the specified type \fItype\fR. .SH RETURN VALUE The \fBmunge_enum_is_valid\fR() function returns non-zero if the given value \fIval\fR is a valid enumeration. .PP The \fBmunge_enum_int_to_str\fR() function returns a NUL-terminated constant text string, or NULL on error; this string should not be freed or modified by the caller. .PP The \fBmunge_enum_str_to_int\fR() function returns a MUNGE enumeration on success (i.e., >= 0), or \-1 on error. .SH "ENUM TYPES" The following enumeration types can be specified. .TP .B MUNGE_ENUM_CIPHER Specify enumerations for the available cipher types. .TP .B MUNGE_ENUM_MAC Specify enumerations for the available MAC types. .TP .B MUNGE_ENUM_ZIP Specify enumerations for the available compression types. .SH ERRORS Refer to \fBmunge\fR(3) for a complete list of errors. .SH EXAMPLE The following example program illustrates how a list of available cipher types can be queried. .PP .nf #include /* for printf() */ #include /* for exit() */ #include .sp int main (int argc, char *argv[]) { int i; const char *p; munge_enum_t t = MUNGE_ENUM_CIPHER; .sp for (i = 0; (p = munge_enum_int_to_str (t, i)) != NULL; i++) { if (munge_enum_is_valid (t, i)) { printf ("%2d = %s\\n", i, p); } } exit (0); } .fi .SH AUTHOR Chris Dunlap .SH COPYRIGHT Copyright (C) 2007-2022 Lawrence Livermore National Security, LLC. .br Copyright (C) 2002-2007 The Regents of the University of California. .PP MUNGE 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. .PP Additionally for the MUNGE library (libmunge), you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. .SH "SEE ALSO" .BR munge (1), .BR remunge (1), .BR unmunge (1), .BR munge (3), .BR munge_ctx (3), .BR munge (7), .BR munged (8), .BR mungekey (8). .PP \fBhttps://dun.github.io/munge/\fR munge-munge-0.5.15/src/libmunge/strerror.c000066400000000000000000000061351425467526100204660ustar00rootroot00000000000000/***************************************************************************** * Written by Chris Dunlap . * Copyright (C) 2007-2022 Lawrence Livermore National Security, LLC. * Copyright (C) 2002-2007 The Regents of the University of California. * UCRL-CODE-155910. * * This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE). * For details, see . * * MUNGE 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. Additionally for the MUNGE library (libmunge), you * can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation, * either version 3 of the License, or (at your option) any later version. * * MUNGE 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 * and GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * and GNU Lesser General Public License along with MUNGE. If not, see * . *****************************************************************************/ #if HAVE_CONFIG_H # include #endif /* HAVE_CONFIG_H */ #include const char * munge_strerror (munge_err_t errnum) { switch (errnum) { case EMUNGE_SUCCESS: return ("Success"); case EMUNGE_SNAFU: return ("Internal error"); case EMUNGE_BAD_ARG: return ("Invalid argument"); case EMUNGE_BAD_LENGTH: return ("Exceeded maximum message length"); case EMUNGE_OVERFLOW: return ("Buffer overflow"); case EMUNGE_NO_MEMORY: return ("Out of memory"); case EMUNGE_SOCKET: return ("Socket communication error"); case EMUNGE_TIMEOUT: return ("Socket timeout"); case EMUNGE_BAD_CRED: return ("Invalid credential format"); case EMUNGE_BAD_VERSION: return ("Invalid credential version"); case EMUNGE_BAD_CIPHER: return ("Invalid cipher type"); case EMUNGE_BAD_MAC: return ("Invalid MAC type"); case EMUNGE_BAD_ZIP: return ("Invalid compression type"); case EMUNGE_BAD_REALM: return ("Unrecognized security realm"); case EMUNGE_CRED_INVALID: return ("Invalid credential"); case EMUNGE_CRED_EXPIRED: return ("Expired credential"); case EMUNGE_CRED_REWOUND: return ("Rewound credential"); case EMUNGE_CRED_REPLAYED: return ("Replayed credential"); case EMUNGE_CRED_UNAUTHORIZED: return ("Unauthorized credential"); default: break; } return ("Unknown error"); } munge-munge-0.5.15/src/libtap/000077500000000000000000000000001425467526100161045ustar00rootroot00000000000000munge-munge-0.5.15/src/libtap/Makefile.am000066400000000000000000000005751425467526100201470ustar00rootroot00000000000000# MUNGE src/libtap/Makefile.am # # This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE). # For details, see . include $(top_srcdir)/Make-inc.mk check_LTLIBRARIES = \ libtap.la \ # End of check_LTLIBRARIES libtap_la_CFLAGS = \ -D_BSD_SOURCE \ # End of libtap_la_CFLAGS libtap_la_SOURCES = \ tap.c \ tap.h \ # End of libtap_la_SOURCES munge-munge-0.5.15/src/libtap/URL000066400000000000000000000000421425467526100164650ustar00rootroot00000000000000https://github.com/zorgnax/libtap munge-munge-0.5.15/src/libtap/tap.c000066400000000000000000000205361425467526100170420ustar00rootroot00000000000000/* libtap - Write tests in C Copyright 2012 Jake Gelbman This file is licensed under the LGPL */ #define _DEFAULT_SOURCE 1 #include #include #include #include #include "tap.h" static int expected_tests = NO_PLAN; static int failed_tests; static int current_test; static char *todo_mesg; static char * vstrdupf (const char *fmt, va_list args) { char *str; int size; va_list args2; va_copy(args2, args); if (!fmt) fmt = ""; size = vsnprintf(NULL, 0, fmt, args2) + 2; str = malloc(size); if (!str) { perror("malloc error"); exit(1); } vsprintf(str, fmt, args); va_end(args2); return str; } void tap_plan (int tests, const char *fmt, ...) { expected_tests = tests; if (tests == SKIP_ALL) { char *why; va_list args; va_start(args, fmt); why = vstrdupf(fmt, args); va_end(args); printf("1..0 "); diag("SKIP %s\n", why); exit(0); } if (tests != NO_PLAN) { printf("1..%d\n", tests); } } int vok_at_loc (const char *file, int line, int test, const char *fmt, va_list args) { char *name = vstrdupf(fmt, args); if (!test) { printf("not "); } printf("ok %d", ++current_test); if (*name) printf(" - %s", name); if (todo_mesg) { printf(" # TODO"); if (*todo_mesg) printf(" %s", todo_mesg); } printf("\n"); if (!test) { printf("# Failed "); if (todo_mesg) printf("(TODO) "); printf("test "); if (*name) printf("'%s'\n# ", name); printf("at %s line %d.\n", file, line); if (!todo_mesg) failed_tests++; } free(name); return test; } int ok_at_loc (const char *file, int line, int test, const char *fmt, ...) { va_list args; va_start(args, fmt); vok_at_loc(file, line, test, fmt, args); va_end(args); return test; } static int mystrcmp (const char *a, const char *b) { return a == b ? 0 : !a ? -1 : !b ? 1 : strcmp(a, b); } #define eq(a, b) (!mystrcmp(a, b)) #define ne(a, b) (mystrcmp(a, b)) int is_at_loc (const char *file, int line, const char *got, const char *expected, const char *fmt, ...) { int test = eq(got, expected); va_list args; va_start(args, fmt); vok_at_loc(file, line, test, fmt, args); va_end(args); if (!test) { diag(" got: '%s'", got); diag(" expected: '%s'", expected); } return test; } int isnt_at_loc (const char *file, int line, const char *got, const char *expected, const char *fmt, ...) { int test = ne(got, expected); va_list args; va_start(args, fmt); vok_at_loc(file, line, test, fmt, args); va_end(args); if (!test) { diag(" got: '%s'", got); diag(" expected: anything else"); } return test; } int cmp_ok_at_loc (const char *file, int line, int a, const char *op, int b, const char *fmt, ...) { int test = eq(op, "||") ? a || b : eq(op, "&&") ? a && b : eq(op, "|") ? a | b : eq(op, "^") ? a ^ b : eq(op, "&") ? a & b : eq(op, "==") ? a == b : eq(op, "!=") ? a != b : eq(op, "<") ? a < b : eq(op, ">") ? a > b : eq(op, "<=") ? a <= b : eq(op, ">=") ? a >= b : eq(op, "<<") ? a << b : eq(op, ">>") ? a >> b : eq(op, "+") ? a + b : eq(op, "-") ? a - b : eq(op, "*") ? a * b : eq(op, "/") ? a / b : eq(op, "%") ? a % b : diag("unrecognized operator '%s'", op); va_list args; va_start(args, fmt); vok_at_loc(file, line, test, fmt, args); va_end(args); if (!test) { diag(" %d", a); diag(" %s", op); diag(" %d", b); } return test; } static int find_mem_diff (const char *a, const char *b, size_t n, size_t *offset) { size_t i; if (a == b) return 0; if (!a || !b) return 2; for (i = 0; i < n; i++) { if (a[i] != b[i]) { *offset = i; return 1; } } return 0; } int cmp_mem_at_loc (const char *file, int line, const void *got, const void *expected, size_t n, const char *fmt, ...) { size_t offset; int diff = find_mem_diff(got, expected, n, &offset); va_list args; va_start(args, fmt); vok_at_loc(file, line, !diff, fmt, args); va_end(args); if (diff == 1) { diag(" Difference starts at offset %d", offset); diag(" got: 0x%02x", ((unsigned char *)got)[offset]); diag(" expected: 0x%02x", ((unsigned char *)expected)[offset]); } else if (diff == 2) { diag(" got: %s", got ? "not NULL" : "NULL"); diag(" expected: %s", expected ? "not NULL" : "NULL"); } return !diff; } int diag (const char *fmt, ...) { va_list args; char *mesg, *line; int i; va_start(args, fmt); if (!fmt) return 0; mesg = vstrdupf(fmt, args); line = mesg; for (i = 0; *line; i++) { char c = mesg[i]; if (!c || c == '\n') { mesg[i] = '\0'; printf("# %s\n", line); if (!c) break; mesg[i] = c; line = mesg + i + 1; } } free(mesg); va_end(args); return 0; } int exit_status () { int retval = 0; if (expected_tests == NO_PLAN) { printf("1..%d\n", current_test); } else if (current_test != expected_tests) { diag("Looks like you planned %d test%s but ran %d.", expected_tests, expected_tests > 1 ? "s" : "", current_test); retval = 2; } if (failed_tests) { diag("Looks like you failed %d test%s of %d run.", failed_tests, failed_tests > 1 ? "s" : "", current_test); retval = 1; } return retval; } int bail_out (int ignore, const char *fmt, ...) { va_list args; va_start(args, fmt); printf("Bail out! "); vprintf(fmt, args); printf("\n"); va_end(args); exit(255); return 0; } void tap_skip (int n, const char *fmt, ...) { char *why; va_list args; va_start(args, fmt); why = vstrdupf(fmt, args); va_end(args); while (n --> 0) { printf("ok %d ", ++current_test); diag("skip %s\n", why); } free(why); } void tap_todo (int ignore, const char *fmt, ...) { va_list args; va_start(args, fmt); todo_mesg = vstrdupf(fmt, args); va_end(args); } void tap_end_todo () { free(todo_mesg); todo_mesg = NULL; } #ifndef _WIN32 #include #include #include #ifndef MAP_ANONYMOUS #ifdef MAP_ANON #define MAP_ANONYMOUS MAP_ANON #else #error "System does not support mapping anonymous pages" #endif #endif /* Create a shared memory int to keep track of whether a piece of code executed dies. to be used in the dies_ok and lives_ok macros. */ int tap_test_died (int status) { static int *test_died = NULL; int prev; if (!test_died) { test_died = mmap(0, sizeof (int), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); *test_died = 0; } prev = *test_died; *test_died = status; return prev; } int like_at_loc (int for_match, const char *file, int line, const char *got, const char *expected, const char *fmt, ...) { int test; regex_t re; va_list args; int err = regcomp(&re, expected, REG_EXTENDED); if (err) { char errbuf[256]; regerror(err, &re, errbuf, sizeof errbuf); fprintf(stderr, "Unable to compile regex '%s': %s at %s line %d\n", expected, errbuf, file, line); exit(255); } err = regexec(&re, got, 0, NULL, 0); regfree(&re); test = for_match ? !err : err; va_start(args, fmt); vok_at_loc(file, line, test, fmt, args); va_end(args); if (!test) { if (for_match) { diag(" '%s'", got); diag(" doesn't match: '%s'", expected); } else { diag(" '%s'", got); diag(" matches: '%s'", expected); } } return test; } #endif munge-munge-0.5.15/src/libtap/tap.h000066400000000000000000000113711425467526100170440ustar00rootroot00000000000000/* libtap - Write tests in C Copyright 2012 Jake Gelbman This file is licensed under the LGPL */ #ifndef __TAP_H__ #define __TAP_H__ #ifdef __cplusplus extern "C" { #endif #ifndef va_copy #ifdef __va_copy #define va_copy __va_copy #else #define va_copy(d, s) ((d) = (s)) #endif #endif #include #include #include int vok_at_loc (const char *file, int line, int test, const char *fmt, va_list args); int ok_at_loc (const char *file, int line, int test, const char *fmt, ...); int is_at_loc (const char *file, int line, const char *got, const char *expected, const char *fmt, ...); int isnt_at_loc (const char *file, int line, const char *got, const char *expected, const char *fmt, ...); int cmp_ok_at_loc (const char *file, int line, int a, const char *op, int b, const char *fmt, ...); int cmp_mem_at_loc (const char *file, int line, const void *got, const void *expected, size_t n, const char *fmt, ...); int bail_out (int ignore, const char *fmt, ...); void tap_plan (int tests, const char *fmt, ...); int diag (const char *fmt, ...); int exit_status (void); void tap_skip (int n, const char *fmt, ...); void tap_todo (int ignore, const char *fmt, ...); void tap_end_todo (void); #define NO_PLAN -1 #define SKIP_ALL -2 #define ok(...) ok_at_loc(__FILE__, __LINE__, __VA_ARGS__, NULL) #define is(...) is_at_loc(__FILE__, __LINE__, __VA_ARGS__, NULL) #define isnt(...) isnt_at_loc(__FILE__, __LINE__, __VA_ARGS__, NULL) #define cmp_ok(...) cmp_ok_at_loc(__FILE__, __LINE__, __VA_ARGS__, NULL) #define cmp_mem(...) cmp_mem_at_loc(__FILE__, __LINE__, __VA_ARGS__, NULL) #define plan(...) tap_plan(__VA_ARGS__, NULL) #define done_testing() return exit_status() #define BAIL_OUT(...) bail_out(0, "" __VA_ARGS__, NULL) #define pass(...) ok(1, "" __VA_ARGS__) #define fail(...) ok(0, "" __VA_ARGS__) #define skip(test, ...) do {if (test) {tap_skip(__VA_ARGS__, NULL); break;} #define end_skip } while (0) #define todo(...) tap_todo(0, "" __VA_ARGS__, NULL) #define end_todo tap_end_todo() #define dies_ok(...) dies_ok_common(1, __VA_ARGS__) #define lives_ok(...) dies_ok_common(0, __VA_ARGS__) #ifdef _WIN32 #define like(...) tap_skip(1, "like is not implemented on Windows") #define unlike tap_skip(1, "unlike is not implemented on Windows") #define dies_ok_common(...) \ tap_skip(1, "Death detection is not supported on Windows") #else #define like(...) like_at_loc(1, __FILE__, __LINE__, __VA_ARGS__, NULL) #define unlike(...) like_at_loc(0, __FILE__, __LINE__, __VA_ARGS__, NULL) int like_at_loc (int for_match, const char *file, int line, const char *got, const char *expected, const char *fmt, ...); #include #include #include int tap_test_died (int status); #define dies_ok_common(for_death, code, ...) \ do { \ int cpid; \ int it_died; \ tap_test_died(1); \ cpid = fork(); \ switch (cpid) { \ case -1: \ perror("fork error"); \ exit(1); \ case 0: \ close(1); \ close(2); \ code \ tap_test_died(0); \ exit(0); \ } \ if (waitpid(cpid, NULL, 0) < 0) { \ perror("waitpid error"); \ exit(1); \ } \ it_died = tap_test_died(0); \ if (!it_died) \ {code} \ ok(for_death ? it_died : !it_died, "" __VA_ARGS__); \ } while (0) #endif #ifdef __cplusplus } #endif #endif munge-munge-0.5.15/src/munge/000077500000000000000000000000001425467526100157445ustar00rootroot00000000000000munge-munge-0.5.15/src/munge/Makefile.am000066400000000000000000000053221425467526100200020ustar00rootroot00000000000000# MUNGE src/munge/Makefile.am # # This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE). # For details, see . include $(top_srcdir)/Make-inc.mk TEMPLATE_FILES = \ munge.1.in \ remunge.1.in \ unmunge.1.in \ # End of TEMPLATE_FILES SUBSTITUTE_FILES = \ munge.1 \ remunge.1 \ unmunge.1 \ # End of SUBSTITUTE_FILES EXTRA_DIST = \ $(TEMPLATE_FILES) \ # End of EXTRA_DIST CLEANFILES = \ $(SUBSTITUTE_FILES) \ # End of CLEANFILES $(SUBSTITUTE_FILES): Makefile $(AM_V_GEN)$(substitute) < '$(srcdir)/$@.in' > '$(builddir)/$@' munge.1: munge.1.in remunge.1: remunge.1.in unmunge.1: unmunge.1.in bin_PROGRAMS = \ munge \ remunge \ unmunge \ # End of bin_PROGRAMS munge_CPPFLAGS = \ -I$(top_srcdir)/src/common \ -I$(top_srcdir)/src/libcommon \ -I$(top_srcdir)/src/libmissing \ -I$(top_srcdir)/src/libmunge \ # End of munge_CPPFLAGS munge_LDADD = \ $(top_builddir)/src/libcommon/libcommon.la \ $(top_builddir)/src/libmissing/libmissing.la \ $(top_builddir)/src/libmunge/libmunge.la \ # End of munge_LDADD munge_SOURCES = \ munge.c \ read.c \ read.h \ $(top_srcdir)/src/common/query.c \ $(top_srcdir)/src/common/query.h \ $(top_srcdir)/src/common/xgetgr.c \ $(top_srcdir)/src/common/xgetgr.h \ $(top_srcdir)/src/common/xgetpw.c \ $(top_srcdir)/src/common/xgetpw.h \ $(top_srcdir)/src/common/xsignal.c \ $(top_srcdir)/src/common/xsignal.h \ # End of munge_SOURCES remunge_CPPFLAGS = \ -DWITH_PTHREADS \ -I$(top_srcdir)/src/common \ -I$(top_srcdir)/src/libcommon \ -I$(top_srcdir)/src/libmissing \ -I$(top_srcdir)/src/libmunge \ # End of remunge_CPPFLAGS remunge_LDADD = \ $(top_builddir)/src/libcommon/libcommon.la \ $(top_builddir)/src/libmissing/libmissing.la \ $(top_builddir)/src/libmunge/libmunge.la \ $(LIBPTHREAD) \ # End of remunge_LDADD remunge_SOURCES = \ remunge.c \ $(top_srcdir)/src/common/query.c \ $(top_srcdir)/src/common/query.h \ $(top_srcdir)/src/common/xgetgr.c \ $(top_srcdir)/src/common/xgetgr.h \ $(top_srcdir)/src/common/xgetpw.c \ $(top_srcdir)/src/common/xgetpw.h \ $(top_srcdir)/src/common/xsignal.c \ $(top_srcdir)/src/common/xsignal.h \ # End of remunge_SOURCES unmunge_CPPFLAGS = \ -I$(top_srcdir)/src/common \ -I$(top_srcdir)/src/libcommon \ -I$(top_srcdir)/src/libmissing \ -I$(top_srcdir)/src/libmunge \ # End of unmunge_CPPFLAGS unmunge_LDADD = \ $(top_builddir)/src/libcommon/libcommon.la \ $(top_builddir)/src/libmissing/libmissing.la \ $(top_builddir)/src/libmunge/libmunge.la \ # End of unmunge_LDADD unmunge_SOURCES = \ unmunge.c \ read.c \ read.h \ $(top_srcdir)/src/common/xsignal.c \ $(top_srcdir)/src/common/xsignal.h \ # End of unmunge_SOURCES man_MANS = \ munge.1 \ remunge.1 \ unmunge.1 \ # End of man_MANS munge-munge-0.5.15/src/munge/munge.1.in000066400000000000000000000125311425467526100175500ustar00rootroot00000000000000.\"**************************************************************************** .\" Written by Chris Dunlap . .\" Copyright (C) 2007-2022 Lawrence Livermore National Security, LLC. .\" Copyright (C) 2002-2007 The Regents of the University of California. .\" UCRL-CODE-155910. .\" .\" This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE). .\" For details, see . .\" .\" MUNGE 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. Additionally for the MUNGE library (libmunge), you .\" can redistribute it and/or modify it under the terms of the GNU Lesser .\" General Public License as published by the Free Software Foundation, .\" either version 3 of the License, or (at your option) any later version. .\" .\" MUNGE 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 .\" and GNU Lesser General Public License for more details. .\" .\" You should have received a copy of the GNU General Public License .\" and GNU Lesser General Public License along with MUNGE. If not, see .\" . .\"**************************************************************************** .TH MUNGE 1 "@DATE@" "@PACKAGE@-@VERSION@" "MUNGE Uid 'N' Gid Emporium" .SH NAME munge \- MUNGE credential encoder .SH SYNOPSIS .B munge [\fIOPTION\fR]... .SH DESCRIPTION The \fBmunge\fR program creates an MUNGE credential containing the UID and GID of the calling process. Additional payload data can be encapsulated in as well. The returned credential can be passed to another process which can validate its contents (e.g., via the \fBunmunge\fR program). This allows an unrelated and potentially remote process to ascertain the identity of the calling process. .PP By default, payload input is read from stdin and the credential is written to stdout. .SH OPTIONS .TP .BI "\-h, \-\-help" Display a summary of the command-line options. .TP .BI "\-L, \-\-license" Display license information. .TP .BI "\-V, \-\-version" Display version information. .TP .BI "\-n, \-\-no\-input" Discard all input for the payload. .TP .BI "\-s, \-\-string " string Input payload from the specified string. .TP .BI "\-i, \-\-input " path Input payload from the specified file. .TP .BI "\-o, \-\-output " path Output the credential to the specified file. .TP .BI "\-c, \-\-cipher " string Specify the cipher type, either by name or number. .TP .BI "\-C, \-\-list\-ciphers" Display a list of supported cipher types. .TP .BI "\-m, \-\-mac " string Specify the MAC type, either by name or number. .TP .BI "\-M, \-\-list\-macs" Display a list of supported MAC types. .TP .BI "\-z, \-\-zip " string Specify the compression type, either by name or number. .TP .BI "\-Z, \-\-list\-zips" Display a list of supported compression types. .TP .BI "\-u, \-\-restrict\-uid " uid Specify the user name or UID allowed to decode the credential. This will be matched against the effective user ID of the process requesting the credential decode. .TP .BI "\-U, \-\-uid " uid Specify the user name or UID under which to request the credential. This requires root privileges or the CAP_SETUID capability. .TP .BI "\-g, \-\-restrict\-gid " gid Specify the group name or GID allowed to decode the credential. This will be matched against the effective group ID of the process requesting the credential decode, as well as each supplementary group of which the effective user ID of that process is a member. .TP .BI "\-G, \-\-gid " gid Specify the group name or GID under which to request the credential. This requires root privileges or the CAP_SETGID capability. .TP .BI "\-t, \-\-ttl " seconds Specify the time-to-live (in seconds). This controls how long the credential is valid once it has been encoded. A value of 0 selects the default TTL. A value of \-1 selects the maximum allowed TTL. Note that \fBmunged\fR can impose a maximum allowable TTL for all credentials which may be smaller than this value. .TP .BI "\-S, \-\-socket " path Specify the local socket for connecting with \fBmunged\fR. .SH "EXIT STATUS" The \fBmunge\fR program returns a zero exit code when the credential is successfully created and returned. On error, it prints an error message to stderr and returns a non-zero exit code. .SH AUTHOR Chris Dunlap .SH COPYRIGHT Copyright (C) 2007-2022 Lawrence Livermore National Security, LLC. .br Copyright (C) 2002-2007 The Regents of the University of California. .PP MUNGE 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. .PP Additionally for the MUNGE library (libmunge), you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. .SH "SEE ALSO" .BR remunge (1), .BR unmunge (1), .BR munge (3), .BR munge_ctx (3), .BR munge_enum (3), .BR munge (7), .BR munged (8), .BR mungekey (8). .PP \fBhttps://dun.github.io/munge/\fR munge-munge-0.5.15/src/munge/munge.c000066400000000000000000000506541425467526100172350ustar00rootroot00000000000000/***************************************************************************** * Written by Chris Dunlap . * Copyright (C) 2007-2022 Lawrence Livermore National Security, LLC. * Copyright (C) 2002-2007 The Regents of the University of California. * UCRL-CODE-155910. * * This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE). * For details, see . * * MUNGE 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. Additionally for the MUNGE library (libmunge), you * can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation, * either version 3 of the License, or (at your option) any later version. * * MUNGE 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 * and GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * and GNU Lesser General Public License along with MUNGE. If not, see * . *****************************************************************************/ #if HAVE_CONFIG_H # include "config.h" #endif /* HAVE_CONFIG_H */ #include /* include before grp.h for bsd */ #include #include #include #include #include #include #include #include #include #include #include "common.h" #include "license.h" #include "log.h" #include "query.h" #include "read.h" #include "version.h" #include "xsignal.h" /***************************************************************************** * Command-Line Options *****************************************************************************/ const char * const short_opts = ":hLVns:i:o:c:Cm:Mz:Zu:U:g:G:t:S:"; #include struct option long_opts[] = { { "help", no_argument, NULL, 'h' }, { "license", no_argument, NULL, 'L' }, { "version", no_argument, NULL, 'V' }, { "no-input", no_argument, NULL, 'n' }, { "string", required_argument, NULL, 's' }, { "input", required_argument, NULL, 'i' }, { "output", required_argument, NULL, 'o' }, { "cipher", required_argument, NULL, 'c' }, { "list-ciphers", no_argument, NULL, 'C' }, { "mac", required_argument, NULL, 'm' }, { "list-macs", no_argument, NULL, 'M' }, { "zip", required_argument, NULL, 'z' }, { "list-zips", no_argument, NULL, 'Z' }, { "restrict-uid", required_argument, NULL, 'u' }, { "uid", required_argument, NULL, 'U' }, { "restrict-gid", required_argument, NULL, 'g' }, { "gid", required_argument, NULL, 'G' }, { "ttl", required_argument, NULL, 't' }, { "socket", required_argument, NULL, 'S' }, { NULL, 0, NULL, 0 } }; /***************************************************************************** * Configuration *****************************************************************************/ struct conf { munge_ctx_t ctx; /* munge context */ munge_err_t status; /* error status munging the cred */ uid_t cuid; /* credential UID */ gid_t cgid; /* credential GID */ char *string; /* input from string instead of file */ char *fn_in; /* input filename, '-' for stdin */ char *fn_out; /* output filename, '-' for stdout */ FILE *fp_in; /* input file pointer */ FILE *fp_out; /* output file pointer */ int dlen; /* payload data length */ void *data; /* payload data */ int clen; /* munged credential length */ char *cred; /* munged credential nul-terminated */ }; typedef struct conf * conf_t; /***************************************************************************** * Prototypes *****************************************************************************/ conf_t create_conf (void); void destroy_conf (conf_t conf); void parse_cmdline (conf_t conf, int argc, char **argv); void display_help (char *prog); void display_strings (const char *header, munge_enum_t type); void open_files (conf_t conf); int encode_cred (conf_t conf); void display_cred (conf_t conf); /***************************************************************************** * Functions *****************************************************************************/ int main (int argc, char *argv[]) { conf_t conf; const char *p; xsignal_ignore (SIGHUP); xsignal_ignore (SIGPIPE); log_open_file (stderr, argv[0], LOG_INFO, LOG_OPT_PRIORITY); conf = create_conf (); parse_cmdline (conf, argc, argv); open_files (conf); if (conf->string) { read_data_from_string (conf->string, &conf->data, &conf->dlen); } else if (conf->fn_in) { read_data_from_file (conf->fp_in, &conf->data, &conf->dlen); } if (encode_cred (conf) < 0) { if (!(p = munge_ctx_strerror (conf->ctx))) { p = munge_strerror (conf->status); } log_err (conf->status, LOG_ERR, "%s", p); } conf->clen = strlen (conf->cred); display_cred (conf); destroy_conf (conf); log_close_file (); exit (EMUNGE_SUCCESS); } conf_t create_conf (void) { conf_t conf; if (!(conf = malloc (sizeof (struct conf)))) { log_errno (EMUNGE_NO_MEMORY, LOG_ERR, "Failed to allocate conf"); } if (!(conf->ctx = munge_ctx_create ())) { log_errno (EMUNGE_NO_MEMORY, LOG_ERR, "Failed to create conf ctx"); } conf->status = -1; conf->cuid = geteuid (); conf->cgid = getegid (); conf->string = NULL; conf->fn_in = "-"; conf->fn_out = "-"; conf->fp_in = NULL; conf->fp_out = NULL; conf->dlen = 0; conf->data = NULL; conf->clen = 0; conf->cred = NULL; return (conf); } void destroy_conf (conf_t conf) { /* XXX: Don't free conf's string/fn_in/fn_out * since they point inside argv[]. */ if (conf->fp_in != NULL) { if (fclose (conf->fp_in) < 0) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to close input file"); } conf->fp_in = NULL; } if (conf->fp_out != NULL) { if ((fclose (conf->fp_out) < 0) && (errno != EPIPE)) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to close output file"); } conf->fp_out = NULL; } if (conf->data != NULL) { memburn (conf->data, 0, conf->dlen); free (conf->data); conf->data = NULL; } if (conf->cred != NULL) { memburn (conf->cred, 0, conf->clen); free (conf->cred); conf->cred = NULL; } munge_ctx_destroy (conf->ctx); free (conf); return; } void parse_cmdline (conf_t conf, int argc, char **argv) { char *prog; int c; char *p; munge_err_t e; int i; long int l; opterr = 0; /* suppress default getopt err msgs */ prog = (prog = strrchr (argv[0], '/')) ? prog + 1 : argv[0]; for (;;) { c = getopt_long (argc, argv, short_opts, long_opts, NULL); if (c == -1) { /* reached end of option list */ break; } switch (c) { case 'h': display_help (prog); exit (EMUNGE_SUCCESS); break; case 'L': display_license (); exit (EMUNGE_SUCCESS); break; case 'V': display_version (); exit (EMUNGE_SUCCESS); break; case 'n': conf->fn_in = NULL; conf->string = NULL; break; case 's': conf->fn_in = NULL; conf->string = optarg; break; case 'i': conf->fn_in = optarg; conf->string = NULL; break; case 'o': conf->fn_out = optarg; break; case 'c': i = munge_enum_str_to_int (MUNGE_ENUM_CIPHER, optarg); if ((i < 0) || !munge_enum_is_valid (MUNGE_ENUM_CIPHER, i)) { log_err (EMUNGE_SNAFU, LOG_ERR, "Invalid cipher type \"%s\"", optarg); } e = munge_ctx_set (conf->ctx, MUNGE_OPT_CIPHER_TYPE, i); if (e != EMUNGE_SUCCESS) { log_err (EMUNGE_SNAFU, LOG_ERR, "Failed to set cipher type: %s", munge_ctx_strerror (conf->ctx)); } break; case 'C': display_strings ("Cipher types", MUNGE_ENUM_CIPHER); exit (EMUNGE_SUCCESS); break; case 'm': i = munge_enum_str_to_int (MUNGE_ENUM_MAC, optarg); if ((i < 0) || !munge_enum_is_valid (MUNGE_ENUM_MAC, i)) { log_err (EMUNGE_SNAFU, LOG_ERR, "Invalid MAC type \"%s\"", optarg); } e = munge_ctx_set (conf->ctx, MUNGE_OPT_MAC_TYPE, i); if (e != EMUNGE_SUCCESS) { log_err (EMUNGE_SNAFU, LOG_ERR, "Failed to set MAC type: %s", munge_ctx_strerror (conf->ctx)); } break; case 'M': display_strings ("MAC types", MUNGE_ENUM_MAC); exit (EMUNGE_SUCCESS); break; case 'z': i = munge_enum_str_to_int (MUNGE_ENUM_ZIP, optarg); if ((i < 0) || !munge_enum_is_valid (MUNGE_ENUM_ZIP, i)) { log_err (EMUNGE_SNAFU, LOG_ERR, "Invalid compression type \"%s\"", optarg); } e = munge_ctx_set (conf->ctx, MUNGE_OPT_ZIP_TYPE, i); if (e != EMUNGE_SUCCESS) { log_err (EMUNGE_SNAFU, LOG_ERR, "Failed to set compression type: %s", munge_ctx_strerror (conf->ctx)); } break; case 'Z': display_strings ("Compression types", MUNGE_ENUM_ZIP); exit (EMUNGE_SUCCESS); break; case 'u': if (query_uid (optarg, (uid_t *) &i) < 0) { log_err (EMUNGE_SNAFU, LOG_ERR, "Unrecognized user \"%s\"", optarg); } e = munge_ctx_set (conf->ctx, MUNGE_OPT_UID_RESTRICTION, i); if (e != EMUNGE_SUCCESS) { log_err (EMUNGE_SNAFU, LOG_ERR, "Failed to set UID restriction: %s", munge_ctx_strerror (conf->ctx)); } break; case 'U': if (query_uid (optarg, (uid_t *) &i) < 0) { log_err (EMUNGE_SNAFU, LOG_ERR, "Unrecognized user \"%s\"", optarg); } conf->cuid = (uid_t) i; break; case 'g': if (query_gid (optarg, (gid_t *) &i) < 0) { log_err (EMUNGE_SNAFU, LOG_ERR, "Unrecognized group \"%s\"", optarg); } e = munge_ctx_set (conf->ctx, MUNGE_OPT_GID_RESTRICTION, i); if (e != EMUNGE_SUCCESS) { log_err (EMUNGE_SNAFU, LOG_ERR, "Failed to set GID restriction: %s", munge_ctx_strerror (conf->ctx)); } break; case 'G': if (query_gid (optarg, (gid_t *) &i) < 0) { log_err (EMUNGE_SNAFU, LOG_ERR, "Unrecognized group \"%s\"", optarg); } conf->cgid = (gid_t) i; break; case 't': errno = 0; l = strtol (optarg, &p, 10); if ((optarg == p) || (*p != '\0') || (l < -1)) { log_err (EMUNGE_SNAFU, LOG_ERR, "Invalid time-to-live '%s'", optarg); } if ((errno == ERANGE) && (l == LONG_MAX)) { log_err (EMUNGE_SNAFU, LOG_ERR, "Overflowed maximum time-to-live of %ld seconds", LONG_MAX); } if (l > UINT_MAX) { log_err (EMUNGE_SNAFU, LOG_ERR, "Exceeded maximum time-to-live of %u seconds", UINT_MAX); } if (l == -1) { l = MUNGE_TTL_MAXIMUM; } e = munge_ctx_set (conf->ctx, MUNGE_OPT_TTL, (int) l); if (e != EMUNGE_SUCCESS) { log_err (EMUNGE_SNAFU, LOG_ERR, "Failed to set time-to-live: %s", munge_ctx_strerror (conf->ctx)); } break; case 'S': e = munge_ctx_set (conf->ctx, MUNGE_OPT_SOCKET, optarg); if (e != EMUNGE_SUCCESS) { log_err (EMUNGE_SNAFU, LOG_ERR, "Failed to set munge socket name: %s", munge_ctx_strerror (conf->ctx)); } break; case '?': if (optopt > 0) { log_err (EMUNGE_SNAFU, LOG_ERR, "Invalid option \"-%c\"", optopt); } else if (optind > 1) { log_err (EMUNGE_SNAFU, LOG_ERR, "Invalid option \"%s\"", argv[optind - 1]); } else { log_err (EMUNGE_SNAFU, LOG_ERR, "Failed to process command-line"); } break; case ':': if ((optind > 1) && (strncmp (argv[optind - 1], "--", 2) == 0)) { log_err (EMUNGE_SNAFU, LOG_ERR, "Missing argument for option \"%s\"", argv[optind - 1]); } else if (optopt > 0) { log_err (EMUNGE_SNAFU, LOG_ERR, "Missing argument for option \"-%c\"", optopt); } else { log_err (EMUNGE_SNAFU, LOG_ERR, "Failed to process command-line"); } break; default: if ((optind > 1) && (strncmp (argv[optind - 1], "--", 2) == 0)) { log_err (EMUNGE_SNAFU, LOG_ERR, "Unimplemented option \"%s\"", argv[optind - 1]); } else { log_err (EMUNGE_SNAFU, LOG_ERR, "Unimplemented option \"-%c\"", c); } break; } } if (argv[optind]) { log_err (EMUNGE_SNAFU, LOG_ERR, "Unrecognized parameter \"%s\"", argv[optind]); } return; } void display_help (char *prog) { /* Displays a help message describing the command-line options. */ const int w = -25; /* pad for width of option string */ assert (prog != NULL); printf ("Usage: %s [OPTIONS]\n", prog); printf ("\n"); printf (" %*s %s\n", w, "-h, --help", "Display this help message"); printf (" %*s %s\n", w, "-L, --license", "Display license information"); printf (" %*s %s\n", w, "-V, --version", "Display version information"); printf ("\n"); printf (" %*s %s\n", w, "-n, --no-input", "Discard all input for payload"); printf (" %*s %s\n", w, "-s, --string=STR", "Input payload from string"); printf (" %*s %s\n", w, "-i, --input=PATH", "Input payload from file"); printf (" %*s %s\n", w, "-o, --output=PATH", "Output credential to file"); printf ("\n"); printf (" %*s %s\n", w, "-c, --cipher=STR", "Specify cipher type"); printf (" %*s %s\n", w, "-C, --list-ciphers", "Display a list of supported ciphers"); printf (" %*s %s\n", w, "-m, --mac=STR", "Specify MAC type"); printf (" %*s %s\n", w, "-M, --list-macs", "Display a list of supported MACs"); printf (" %*s %s\n", w, "-z, --zip=STR", "Specify compression type"); printf (" %*s %s\n", w, "-Z, --list-zips", "Display a list of supported compressions"); printf ("\n"); printf (" %*s %s\n", w, "-u, --restrict-uid=UID", "Restrict credential decoding by user/UID"); printf (" %*s %s\n", w, "-U, --uid=UID", "Specify credential user/UID"); printf (" %*s %s\n", w, "-g, --restrict-gid=GID", "Restrict credential decoding by group/GID"); printf (" %*s %s\n", w, "-G, --gid=GID", "Specify credential group/GID"); printf (" %*s %s\n", w, "-t, --ttl=SECS", "Specify time-to-live (in seconds; 0=dfl -1=max)"); printf (" %*s %s\n", w, "-S, --socket=PATH", "Specify local socket for munged"); printf ("\n"); printf ("By default, payload read from stdin, " "credential written to stdout.\n\n"); return; } void display_strings (const char *header, munge_enum_t type) { int i; const char *p; if (header) { printf ("%s:\n\n", header); } for (i = 0; (p = munge_enum_int_to_str (type, i)); i++) { if (munge_enum_is_valid (type, i)) { printf (" %s (%d)\n", p, i); } } printf ("\n"); return; } void open_files (conf_t conf) { if (conf->fn_in) { if (!strcmp (conf->fn_in, "-")) { conf->fp_in = stdin; } else if (!(conf->fp_in = fopen (conf->fn_in, "r"))) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to read from \"%s\"", conf->fn_in); } } if (conf->fn_out) { if (!strcmp (conf->fn_out, "-")) { conf->fp_out = stdout; } else if (!(conf->fp_out = fopen (conf->fn_out, "w"))) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to write to \"%s\"", conf->fn_out); } } return; } int encode_cred (conf_t conf) { /* Encodes the credential based on the configuration [conf]. * Returns 0 on success, -1 on error. */ uid_t euid; gid_t egid; euid = geteuid (); egid = getegid (); if (egid != conf->cgid) { if (setegid (conf->cgid) < 0) { log_errno (errno, LOG_ERR, "Failed to create credential for GID %u", conf->cgid); } } if (euid != conf->cuid) { if (seteuid (conf->cuid) < 0) { log_errno (errno, LOG_ERR, "Failed to create credential for UID %u", conf->cuid); } } conf->status = munge_encode (&conf->cred, conf->ctx, conf->data, conf->dlen); if (euid != conf->cuid) { if (seteuid (euid) < 0) { log_errno (errno, LOG_ERR, "Failed to restore privileges for UID %u", euid); } } if (egid != conf->cgid) { if (setegid (egid) < 0) { log_errno (errno, LOG_ERR, "Failed to restore privileges for GID %u", egid); } } return ((conf->status == EMUNGE_SUCCESS) ? 0 : -1); } void display_cred (conf_t conf) { if (!conf->fp_out) { return; } if (fprintf (conf->fp_out, "%s\n", conf->cred) < 0) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Write error"); } return; } munge-munge-0.5.15/src/munge/read.c000066400000000000000000000136511425467526100170310ustar00rootroot00000000000000/***************************************************************************** * Written by Chris Dunlap . * Copyright (C) 2007-2022 Lawrence Livermore National Security, LLC. * Copyright (C) 2002-2007 The Regents of the University of California. * UCRL-CODE-155910. * * This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE). * For details, see . * * MUNGE 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. Additionally for the MUNGE library (libmunge), you * can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation, * either version 3 of the License, or (at your option) any later version. * * MUNGE 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 * and GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * and GNU Lesser General Public License along with MUNGE. If not, see * . *****************************************************************************/ #if HAVE_CONFIG_H # include "config.h" #endif /* HAVE_CONFIG_H */ #include #include #include #include #include #include #include #include "log.h" #include "munge_defs.h" #define INITIAL_BUFFER_SIZE 4096 #define MAXIMUM_BUFFER_SIZE MUNGE_MAXIMUM_REQ_LEN /* * MUNGE_MAXIMUM_REQ_LEN (in munge_defs.h) specifies the maximum size of a * request message transmitted over the unix domain socket. Since messages * greater than this length will be rejected, MAXIMUM_BUFFER_SIZE is used to * limit the size of the memory allocation for bufmem. */ void read_data_from_file (FILE *fp, void **buf, int *len) { unsigned char *bufmem; /* base ptr to buffer memory */ unsigned char *bufptr; /* current ptr to unused bufmem */ unsigned char *buftmp; /* tmp ptr to bufmem for realloc() */ size_t bufsiz; /* size allocated for bufmem */ size_t buflen; /* num bytes of unused bufmem */ size_t bufuse; /* num bytes of used bufmem */ size_t n; assert (fp != NULL); assert (buf != NULL); assert (len != NULL); bufsiz = INITIAL_BUFFER_SIZE; bufmem = bufptr = malloc (bufsiz); if (bufmem == NULL) { log_errno (EMUNGE_NO_MEMORY, LOG_ERR, "Failed to allocate %lu bytes", bufsiz); } buflen = bufsiz; /* Since this reads from a standard I/O stream, there is no guarantee that * the stream provides random access (e.g., when reading from a pipe). * As such, it cannot rely on seeking to the end of the stream to * determine the file length before seeking back to the beginning to * start reading. Consequently, this routine realloc()s the buffer to * grow it as needed while reading from the fp steam. */ for (;;) { n = fread (bufptr, 1, buflen, fp); bufptr += n; buflen -= n; if (buflen > 0) { if (feof (fp)) { break; } else if (ferror (fp)) { log_err (EMUNGE_SNAFU, LOG_ERR, "Failed to read from file"); } else { log_err (EMUNGE_SNAFU, LOG_ERR, "Failed to read from file: Unexpected short count"); } } assert (buflen == 0); assert (bufsiz == bufptr - bufmem); bufuse = bufsiz; bufsiz *= 2; if (bufsiz > MAXIMUM_BUFFER_SIZE) { free (bufmem); log_errno (EMUNGE_SNAFU, LOG_ERR, "Exceeded maximum memory allocation"); } buftmp = realloc (bufmem, bufsiz); if (buftmp == NULL) { free (bufmem); log_errno (EMUNGE_NO_MEMORY, LOG_ERR, "Failed to allocate %lu bytes", bufsiz); } buflen = bufsiz - bufuse; bufptr = buftmp + bufuse; bufmem = buftmp; } n = bufptr - bufmem; if (n == 0) { free (bufmem); *buf = NULL; *len = 0; return; } /* If the fp has exactly 'len' bytes remaining, fread (ptr, 1, len, fp) * will return a value equal to 'len'. But the EOF will not be detected * until the next fread() which will return a value of 0. Consequently, * realloc() will double the buffer before this final iteration of the * loop thereby guaranteeing (buflen > 0). The if-guard here is just * for safety/paranoia. */ assert (buflen > 0); if (buflen > 0) { bufmem[n] = '\0'; } if (n > INT_MAX) { log_err (EMUNGE_SNAFU, LOG_ERR, "Exceeded maximum file size"); } *buf = bufmem; *len = (int) n; return; } void read_data_from_string (const char *s, void **buf, int *len) { size_t n; char *p; assert (buf != NULL); assert (len != NULL); *buf = NULL; *len = 0; if (s == NULL) { return; } n = strlen (s); if (n == 0) { return; } p = malloc (n + 1); if (p == NULL) { log_errno (EMUNGE_NO_MEMORY, LOG_ERR, "Failed to allocate %lu bytes", n + 1); } strncpy (p, s, n + 1); p[n] = '\0'; /* null termination here is technically unnecessary */ if (n > INT_MAX) { log_err (EMUNGE_SNAFU, LOG_ERR, "Exceeded maximum string size"); } *buf = p; *len = (int) n; return; } munge-munge-0.5.15/src/munge/read.h000066400000000000000000000044211425467526100170310ustar00rootroot00000000000000/***************************************************************************** * Written by Chris Dunlap . * Copyright (C) 2007-2022 Lawrence Livermore National Security, LLC. * Copyright (C) 2002-2007 The Regents of the University of California. * UCRL-CODE-155910. * * This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE). * For details, see . * * MUNGE 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. Additionally for the MUNGE library (libmunge), you * can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation, * either version 3 of the License, or (at your option) any later version. * * MUNGE 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 * and GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * and GNU Lesser General Public License along with MUNGE. If not, see * . *****************************************************************************/ #ifndef MUNGE_READ_H #define MUNGE_READ_H #include void read_data_from_file (FILE *fp, void **buf, int *len); /* * Malloc()s a buffer and reads data from file pointer [fp] into it, * ensuring the buffer contains a terminating NUL. * The reference parm [buf] is set to the address of the malloc'd buffer, * and [len] is set to the length of the data (not including the * terminating NUL character). */ void read_data_from_string (const char *s, void **buf, int *len); /* * Malloc()s a buffer and copies data from string [s] into it, * ensuring the buffer contains a terminating NUL. * The reference parm [buf] is set to the address of the malloc'd buffer, * and [len] is set to the length of the string (not including the * terminating NUL character). */ #endif /* !MUNGE_READ_H */ munge-munge-0.5.15/src/munge/remunge.1.in000066400000000000000000000134611425467526100201020ustar00rootroot00000000000000.\"**************************************************************************** .\" Written by Chris Dunlap . .\" Copyright (C) 2007-2022 Lawrence Livermore National Security, LLC. .\" Copyright (C) 2002-2007 The Regents of the University of California. .\" UCRL-CODE-155910. .\" .\" This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE). .\" For details, see . .\" .\" MUNGE 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. Additionally for the MUNGE library (libmunge), you .\" can redistribute it and/or modify it under the terms of the GNU Lesser .\" General Public License as published by the Free Software Foundation, .\" either version 3 of the License, or (at your option) any later version. .\" .\" MUNGE 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 .\" and GNU Lesser General Public License for more details. .\" .\" You should have received a copy of the GNU General Public License .\" and GNU Lesser General Public License along with MUNGE. If not, see .\" . .\"**************************************************************************** .TH REMUNGE 1 "@DATE@" "@PACKAGE@-@VERSION@" "MUNGE Uid 'N' Gid Emporium" .SH NAME remunge \- MUNGE credential benchmark .SH SYNOPSIS .B remunge [\fIOPTION\fR]... .SH DESCRIPTION The \fBremunge\fR program benchmarks the performance of MUNGE. A benchmark runs for the specified duration or until the specified number of credentials are processed, whichever comes first. At its conclusion, the number of credentials processed per second is written to stdout. .PP By default, credentials are encoded for one second using a single thread. .SH OPTIONS .TP .BI "\-h, \-\-help" Display a summary of the command-line options. .TP .BI "\-L, \-\-license" Display license information. .TP .BI "\-V, \-\-version" Display version information. .TP .BI "\-q, \-\-quiet" Display only the creds/sec numeric result. This is useful for producing input files for \fBministat\fR. .TP .BI "\-c, \-\-cipher " string Specify the cipher type, either by name or number. .TP .BI "\-C, \-\-list\-ciphers" Display a list of supported cipher types. .TP .BI "\-m, \-\-mac " string Specify the MAC type, either by name or number. .TP .BI "\-M, \-\-list\-macs" Display a list of supported MAC types. .TP .BI "\-z, \-\-zip " string Specify the compression type, either by name or number. .TP .BI "\-Z, \-\-list\-zips" Display a list of supported compression types. .TP .BI "\-e, \-\-encode" Encode (but do not decode) each credential. By bypassing the decode operation, the credential is not stored in the replay cache. .TP .BI "\-d, \-\-decode" Encode and decode each credential. .TP .BI "\-l, \-\-length " bytes Specify an arbitrary payload length (in bytes). The integer may be followed by a single-character modifier: k=kilobytes, m=megabytes, g=gigabytes; K=kibibytes, M=mebibytes, G=gibibytes. .TP .BI "\-u, \-\-restrict\-uid " uid Specify the user name or UID allowed to decode the credential. This will be matched against the effective user ID of the process requesting the credential decode. .TP .BI "\-g, \-\-restrict\-gid " gid Specify the group name or GID allowed to decode the credential. This will be matched against the effective group ID of the process requesting the credential decode, as well as each supplementary group of which the effective user ID of that process is a member. .TP .BI "\-t, \-\-ttl " seconds Specify the time-to-live (in seconds). This controls how long the credential is valid once it has been encoded. A value of 0 selects the default TTL. A value of \-1 selects the maximum allowed TTL. .TP .BI "\-S, \-\-socket " path Specify the local socket for connecting with \fBmunged\fR. .TP .BI "\-D, \-\-duration " seconds Specify the test duration (in seconds). The default duration is one second. A value of \-1 selects the maximum duration. The integer may be followed by a single-character modifier: s=seconds, m=minutes, h=hours, d=days. .TP .BI "\-N, \-\-num\-creds " integer Specify the number of credentials to generate. The integer may be followed by a single-character modifier: k=kilobytes, m=megabytes, g=gigabytes; K=kibibytes, M=mebibytes, G=gibibytes. .TP .BI "\-T, \-\-num\-threads " integer Specify the number of threads to spawn for processing credentials. .TP .BI "\-W, \-\-warn\-time " seconds Specify the maximum number of seconds to allow for a given \fBmunge_encode\fR() or \fBmunge_decode\fR() operation before issuing a warning. .SH "EXIT STATUS" The \fBremunge\fR program returns a zero exit code if the benchmark completes. On error, it prints an error message to stderr and returns a non-zero exit code. .SH AUTHOR Chris Dunlap .SH COPYRIGHT Copyright (C) 2007-2022 Lawrence Livermore National Security, LLC. .br Copyright (C) 2002-2007 The Regents of the University of California. .PP MUNGE 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. .PP Additionally for the MUNGE library (libmunge), you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. .SH "SEE ALSO" .BR munge (1), .BR unmunge (1), .BR munge (3), .BR munge_ctx (3), .BR munge_enum (3), .BR munge (7), .BR munged (8), .BR mungekey (8). .PP \fBhttps://dun.github.io/munge/\fR munge-munge-0.5.15/src/munge/remunge.c000066400000000000000000001275311425467526100175630ustar00rootroot00000000000000/***************************************************************************** * Written by Chris Dunlap . * Copyright (C) 2007-2022 Lawrence Livermore National Security, LLC. * Copyright (C) 2002-2007 The Regents of the University of California. * UCRL-CODE-155910. * * This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE). * For details, see . * * MUNGE 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. Additionally for the MUNGE library (libmunge), you * can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation, * either version 3 of the License, or (at your option) any later version. * * MUNGE 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 * and GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * and GNU Lesser General Public License along with MUNGE. If not, see * . *****************************************************************************/ #if HAVE_CONFIG_H # include "config.h" #endif /* HAVE_CONFIG_H */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "common.h" #include "license.h" #include "log.h" #include "query.h" #include "version.h" #include "xsignal.h" /***************************************************************************** * Constants *****************************************************************************/ #define DEF_DO_DECODE 0 #define DEF_NUM_THREADS 1 #define DEF_PAYLOAD_LENGTH 0 #define DEF_WARNING_TIME 5 #define MIN_DURATION 0.5 /***************************************************************************** * Command-Line Options *****************************************************************************/ const char * const short_opts = ":hLVqc:Cm:Mz:Zedl:u:g:t:S:D:N:T:W:"; #include struct option long_opts[] = { { "help", no_argument, NULL, 'h' }, { "license", no_argument, NULL, 'L' }, { "version", no_argument, NULL, 'V' }, { "quiet", no_argument, NULL, 'q' }, { "cipher", required_argument, NULL, 'c' }, { "list-ciphers", no_argument, NULL, 'C' }, { "mac", required_argument, NULL, 'm' }, { "list-macs", no_argument, NULL, 'M' }, { "zip", required_argument, NULL, 'z' }, { "list-zips", no_argument, NULL, 'Z' }, { "encode", no_argument, NULL, 'e' }, { "decode", no_argument, NULL, 'd' }, { "length", required_argument, NULL, 'l' }, { "restrict-uid", required_argument, NULL, 'u' }, { "restrict-gid", required_argument, NULL, 'g' }, { "ttl", required_argument, NULL, 't' }, { "socket", required_argument, NULL, 'S' }, { "duration", required_argument, NULL, 'D' }, { "num-creds", required_argument, NULL, 'N' }, { "num-threads", required_argument, NULL, 'T' }, { "warn-time", required_argument, NULL, 'W' }, { NULL, 0, NULL, 0 } }; /***************************************************************************** * Data Types *****************************************************************************/ /* LOCKING PROTOCOL: * The mutex must be locked when accessing the following fields: * num_creds_done, num_encode_errs, num_decode_errs. * The remaining fields are either not shared between threads or * are constant while processing credentials. */ struct conf { munge_ctx_t ctx; /* munge context */ int do_decode; /* true to decode/validate all creds */ char *payload; /* payload to be encoded into cred */ int num_payload; /* number of bytes for cred payload */ int max_threads; /* max number of threads available */ int num_threads; /* number of threads to spawn */ int num_running; /* number of threads now running */ int num_seconds; /* number of seconds to run */ unsigned long num_creds; /* number of credentials to process */ int warn_time; /* number of seconds to allow for op */ struct timeval t_main_start; /* time when cred processing started */ struct timeval t_main_stop; /* time when cred processing stopped */ pthread_t *tids; /* ptr to array of thread IDs */ pthread_mutex_t mutex; /* mutex for accessing shared data */ pthread_cond_t cond_done; /* cond for when last thread is done */ struct { /* thread-modified data; mutex req'd */ unsigned long num_creds_done; /* number of credentials processed */ unsigned long num_encode_errs; /* number of errors encoding creds */ unsigned long num_decode_errs; /* number of errors decoding creds */ } shared; }; typedef struct conf * conf_t; struct thread_data { conf_t conf; /* reference to global configuration */ munge_ctx_t ectx; /* local munge context for encodes */ munge_ctx_t dctx; /* local munge context for decodes */ }; typedef struct thread_data * tdata_t; typedef void * (*thread_f) (void *); typedef void (*thread_cleanup_f) (void *); /***************************************************************************** * Global Variables *****************************************************************************/ int g_got_quiet = 0; /***************************************************************************** * Prototypes *****************************************************************************/ conf_t create_conf (void); void destroy_conf (conf_t conf); tdata_t create_tdata (conf_t conf); void destroy_tdata (tdata_t tdata); void parse_cmdline (conf_t conf, int argc, char **argv); void display_help (char *prog); void display_strings (const char *header, munge_enum_t type); int get_si_multiple (char c); int get_time_multiple (char c); void start_threads (conf_t conf); void process_creds (conf_t conf); void stop_threads (conf_t conf); void * remunge (conf_t conf); void remunge_cleanup (tdata_t tdata); void output_msg (const char *format, ...); /***************************************************************************** * Macros *****************************************************************************/ #define GET_TIMEVAL(TV) \ do { \ if (gettimeofday ((&TV), NULL) == -1) { \ log_errno (EMUNGE_SNAFU, LOG_ERR, \ "Failed to query current time"); \ } \ } while (0) #define DIFF_TIMEVAL(TV1, TV0) \ ( ((TV1).tv_sec - (TV0).tv_sec ) + \ (((TV1).tv_usec - (TV0).tv_usec) / 1e6) ) /***************************************************************************** * Functions *****************************************************************************/ int main (int argc, char *argv[]) { conf_t conf; xsignal_ignore (SIGHUP); xsignal_ignore (SIGPIPE); /* Close stdin since it is not used. */ if (close (STDIN_FILENO) < 0) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to close standard input"); } /* Set stdout to be line buffered. */ if (setvbuf (stdout, NULL, _IOLBF, 0) < 0) { log_err (EMUNGE_SNAFU, LOG_ERR, "Failed to line-buffer standard output"); } log_open_file (stderr, argv[0], LOG_INFO, LOG_OPT_PRIORITY); conf = create_conf (); parse_cmdline (conf, argc, argv); start_threads (conf); process_creds (conf); stop_threads (conf); destroy_conf (conf); log_close_file (); exit (EMUNGE_SUCCESS); } conf_t create_conf (void) { /* Creates and returns the default configuration. * Returns a valid ptr or dies trying. */ conf_t conf; int n; if (!(conf = malloc (sizeof (*conf)))) { log_errno (EMUNGE_NO_MEMORY, LOG_ERR, "Failed to allocate conf"); } if (!(conf->ctx = munge_ctx_create ())) { log_errno (EMUNGE_NO_MEMORY, LOG_ERR, "Failed to create conf ctx"); } if ((errno = pthread_mutex_init (&conf->mutex, NULL)) != 0) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to init mutex"); } if ((errno = pthread_cond_init (&conf->cond_done, NULL)) != 0) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to init condition"); } conf->do_decode = DEF_DO_DECODE; conf->payload = NULL; conf->num_payload = DEF_PAYLOAD_LENGTH;; conf->num_threads = DEF_NUM_THREADS; conf->num_running = 0; conf->num_seconds = 0; conf->num_creds = 0; conf->shared.num_creds_done = 0; conf->shared.num_encode_errs = 0; conf->shared.num_decode_errs = 0; conf->warn_time = DEF_WARNING_TIME; conf->tids = NULL; /* * Compute the maximum number of threads available for the process. * Each thread requires an open file descriptor to communicate with * the local munge daemon. Reserve 2 fds for stdout and stderr. * And reserve 2 fds in case LinuxThreads is being used. */ errno = 0; if (((n = sysconf (_SC_OPEN_MAX)) == -1) && (errno != 0)) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to determine maximum number of open files"); } if ((conf->max_threads = n - 2 - 2) < 1) { log_err (EMUNGE_SNAFU, LOG_ERR, "Failed to compute maximum number of threads"); } return (conf); } void destroy_conf (conf_t conf) { /* Destroys the configuration [conf]. */ assert (conf != NULL); if (conf->payload) { assert (conf->num_payload > 0); free (conf->payload); } if ((errno = pthread_cond_destroy (&conf->cond_done)) != 0) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to destroy condition"); } if ((errno = pthread_mutex_destroy (&conf->mutex)) != 0) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to destroy mutex"); } munge_ctx_destroy (conf->ctx); free (conf->tids); free (conf); return; } tdata_t create_tdata (conf_t conf) { /* Create thread-specific data referencing back to the global config [conf]. * This struct is required since remunge_cleanup() needs access to both * the global conf mutex and the local munge context. * Returns a valid ptr or dies trying. */ tdata_t tdata; assert (conf != NULL); if (!(tdata = malloc (sizeof (*tdata)))) { log_errno (EMUNGE_NO_MEMORY, LOG_ERR, "Failed to allocate thread data"); } tdata->conf = conf; /* * The munge ctx in the global conf is copied since each thread needs * access to its own local ctx for thread-safety. * A separate ctx is used for both encoding and decoding since a * decode error could place the ctx in an invalid state for encoding. * The decode ctx is copied from the global conf instead of creating * a new one from scratch in order to preserve the location of the * munge socket (which may have been set in the conf). */ if (!(tdata->ectx = munge_ctx_copy (conf->ctx))) { log_err (EMUNGE_SNAFU, LOG_ERR, "Failed to copy munge encode context"); } if ((conf->do_decode) && !(tdata->dctx = munge_ctx_copy (conf->ctx))) { log_err (EMUNGE_SNAFU, LOG_ERR, "Failed to copy munge decode context"); } return (tdata); } void destroy_tdata (tdata_t tdata) { /* Destroy the thread-specific data [tdata]. */ assert (tdata != NULL); if (tdata->conf->do_decode) { munge_ctx_destroy (tdata->dctx); } munge_ctx_destroy (tdata->ectx); free (tdata); return; } void parse_cmdline (conf_t conf, int argc, char **argv) { /* Parses the command-line, altering the configuration [conf] as specified. */ char *prog; int c; char *p; int i; long int l; unsigned long u; int multiplier; munge_err_t e; opterr = 0; /* suppress default getopt err msgs */ prog = (prog = strrchr (argv[0], '/')) ? prog + 1 : argv[0]; for (;;) { c = getopt_long (argc, argv, short_opts, long_opts, NULL); if (c == -1) { /* reached end of option list */ break; } switch (c) { case 'h': display_help (prog); exit (EMUNGE_SUCCESS); break; case 'L': display_license (); exit (EMUNGE_SUCCESS); break; case 'V': display_version (); exit (EMUNGE_SUCCESS); break; case 'q': g_got_quiet = 1; break; case 'c': i = munge_enum_str_to_int (MUNGE_ENUM_CIPHER, optarg); if ((i < 0) || !munge_enum_is_valid (MUNGE_ENUM_CIPHER, i)) { log_err (EMUNGE_SNAFU, LOG_ERR, "Invalid cipher type \"%s\"", optarg); } e = munge_ctx_set (conf->ctx, MUNGE_OPT_CIPHER_TYPE, i); if (e != EMUNGE_SUCCESS) { log_err (EMUNGE_SNAFU, LOG_ERR, "Failed to set cipher type: %s", munge_ctx_strerror (conf->ctx)); } break; case 'C': display_strings ("Cipher types", MUNGE_ENUM_CIPHER); exit (EMUNGE_SUCCESS); break; case 'm': i = munge_enum_str_to_int (MUNGE_ENUM_MAC, optarg); if ((i < 0) || !munge_enum_is_valid (MUNGE_ENUM_MAC, i)) { log_err (EMUNGE_SNAFU, LOG_ERR, "Invalid MAC type \"%s\"", optarg); } e = munge_ctx_set (conf->ctx, MUNGE_OPT_MAC_TYPE, i); if (e != EMUNGE_SUCCESS) { log_err (EMUNGE_SNAFU, LOG_ERR, "Failed to set MAC type: %s", munge_ctx_strerror (conf->ctx)); } break; case 'M': display_strings ("MAC types", MUNGE_ENUM_MAC); exit (EMUNGE_SUCCESS); break; case 'z': i = munge_enum_str_to_int (MUNGE_ENUM_ZIP, optarg); if ((i < 0) || !munge_enum_is_valid (MUNGE_ENUM_ZIP, i)) { log_err (EMUNGE_SNAFU, LOG_ERR, "Invalid compression type \"%s\"", optarg); } e = munge_ctx_set (conf->ctx, MUNGE_OPT_ZIP_TYPE, i); if (e != EMUNGE_SUCCESS) { log_err (EMUNGE_SNAFU, LOG_ERR, "Failed to set compression type: %s", munge_ctx_strerror (conf->ctx)); } break; case 'Z': display_strings ("Compression types", MUNGE_ENUM_ZIP); exit (EMUNGE_SUCCESS); break; case 'e': conf->do_decode = 0; break; case 'd': conf->do_decode = 1; break; case 'l': errno = 0; l = strtol (optarg, &p, 10); if ((optarg == p) || ((*p != '\0') && (*(p+1) != '\0')) || (l < 0)) { log_err (EMUNGE_SNAFU, LOG_ERR, "Invalid number of bytes '%s'", optarg); } if (((errno == ERANGE) && (l == LONG_MAX)) || (l > INT_MAX)) { log_err (EMUNGE_SNAFU, LOG_ERR, "Exceeded maximum number of %d bytes", INT_MAX); } if (!(multiplier = get_si_multiple (*p))) { log_err (EMUNGE_SNAFU, LOG_ERR, "Invalid number specifier '%c'", *p); } if (l > (INT_MAX / multiplier)) { log_err (EMUNGE_SNAFU, LOG_ERR, "Exceeded maximum number of %d bytes", INT_MAX); } conf->num_payload = (int) (l * multiplier); break; case 'u': if (query_uid (optarg, (uid_t *) &i) < 0) { log_err (EMUNGE_SNAFU, LOG_ERR, "Unrecognized user \"%s\"", optarg); } e = munge_ctx_set (conf->ctx, MUNGE_OPT_UID_RESTRICTION, i); if (e != EMUNGE_SUCCESS) { log_err (EMUNGE_SNAFU, LOG_ERR, "Failed to set UID restriction: %s", munge_ctx_strerror (conf->ctx)); } break; case 'g': if (query_gid (optarg, (gid_t *) &i) < 0) { log_err (EMUNGE_SNAFU, LOG_ERR, "Unrecognized group \"%s\"", optarg); } e = munge_ctx_set (conf->ctx, MUNGE_OPT_GID_RESTRICTION, i); if (e != EMUNGE_SUCCESS) { log_err (EMUNGE_SNAFU, LOG_ERR, "Failed to set GID restriction: %s", munge_ctx_strerror (conf->ctx)); } break; case 't': errno = 0; l = strtol (optarg, &p, 10); if ((optarg == p) || (*p != '\0') || (l < -1)) { log_err (EMUNGE_SNAFU, LOG_ERR, "Invalid time-to-live '%s'", optarg); } if ((errno == ERANGE) && (l == LONG_MAX)) { log_err (EMUNGE_SNAFU, LOG_ERR, "Overflowed maximum time-to-live of %ld seconds", LONG_MAX); } if (l > UINT_MAX) { log_err (EMUNGE_SNAFU, LOG_ERR, "Exceeded maximum time-to-live of %u seconds", UINT_MAX); } if (l == -1) { l = MUNGE_TTL_MAXIMUM; } e = munge_ctx_set (conf->ctx, MUNGE_OPT_TTL, (int) l); if (e != EMUNGE_SUCCESS) { log_err (EMUNGE_SNAFU, LOG_ERR, "Failed to set time-to-live: %s", munge_ctx_strerror (conf->ctx)); } break; case 'S': e = munge_ctx_set (conf->ctx, MUNGE_OPT_SOCKET, optarg); if (e != EMUNGE_SUCCESS) { log_err (EMUNGE_SNAFU, LOG_ERR, "Failed to set munge socket name: %s", munge_ctx_strerror (conf->ctx)); } break; case 'D': errno = 0; l = strtol (optarg, &p, 10); if ((optarg == p) || ((*p != '\0') && (*(p+1) != '\0')) || (l <= 0)) { log_err (EMUNGE_SNAFU, LOG_ERR, "Invalid duration '%s'", optarg); } if (((errno == ERANGE) && (l == LONG_MAX)) || (l > INT_MAX)) { log_err (EMUNGE_SNAFU, LOG_ERR, "Exceeded maximum duration of %d seconds", INT_MAX); } if (!(multiplier = get_time_multiple (*p))) { log_err (EMUNGE_SNAFU, LOG_ERR, "Invalid duration specifier '%c'", *p); } if (l > (INT_MAX / multiplier)) { log_err (EMUNGE_SNAFU, LOG_ERR, "Exceeded maximum duration of %d seconds", INT_MAX); } conf->num_seconds = (int) (l * multiplier); break; case 'N': errno = 0; u = strtoul (optarg, &p, 10); if ((optarg == p) || ((*p != '\0') && (*(p+1) != '\0')) || (u == 0)) { log_err (EMUNGE_SNAFU, LOG_ERR, "Invalid number of credentials '%s'", optarg); } if ((errno == ERANGE) && (u == ULONG_MAX)) { log_err (EMUNGE_SNAFU, LOG_ERR, "Exceeded maximum number of %lu credentials", ULONG_MAX); } if (!(multiplier = get_si_multiple (*p))) { log_err (EMUNGE_SNAFU, LOG_ERR, "Invalid number specifier '%c'", *p); } if (u > (ULONG_MAX / multiplier)) { log_err (EMUNGE_SNAFU, LOG_ERR, "Exceeded maximum number of %lu credentials", ULONG_MAX); } conf->num_creds = u * multiplier; break; case 'T': errno = 0; l = strtol (optarg, &p, 10); if ((optarg == p) || (*p != '\0') || (l <= 0)) { log_err (EMUNGE_SNAFU, LOG_ERR, "Invalid number of threads '%s'", optarg); } if (((errno == ERANGE) && (l == LONG_MAX)) || (l > INT_MAX) || (l > conf->max_threads)) { log_err (EMUNGE_SNAFU, LOG_ERR, "Exceeded maximum number of %d thread%s", conf->max_threads, (conf->max_threads == 1) ? "" : "s"); } conf->num_threads = (int) l; break; case 'W': errno = 0; l = strtol (optarg, &p, 10); if ((optarg == p) || (*p != '\0') || (l <= 0)) { log_err (EMUNGE_SNAFU, LOG_ERR, "Invalid number of seconds '%s'", optarg); } if (((errno == ERANGE) && (l == LONG_MAX)) || (l > INT_MAX)) { log_err (EMUNGE_SNAFU, LOG_ERR, "Exceeded maximum number of %d seconds", INT_MAX); } conf->warn_time = (int) l; break; case '?': if (optopt > 0) { log_err (EMUNGE_SNAFU, LOG_ERR, "Invalid option \"-%c\"", optopt); } else if (optind > 1) { log_err (EMUNGE_SNAFU, LOG_ERR, "Invalid option \"%s\"", argv[optind - 1]); } else { log_err (EMUNGE_SNAFU, LOG_ERR, "Failed to process command-line"); } break; case ':': if ((optind > 1) && (strncmp (argv[optind - 1], "--", 2) == 0)) { log_err (EMUNGE_SNAFU, LOG_ERR, "Missing argument for option \"%s\"", argv[optind - 1]); } else if (optopt > 0) { log_err (EMUNGE_SNAFU, LOG_ERR, "Missing argument for option \"-%c\"", optopt); } else { log_err (EMUNGE_SNAFU, LOG_ERR, "Failed to process command-line"); } break; default: if ((optind > 1) && (strncmp (argv[optind - 1], "--", 2) == 0)) { log_err (EMUNGE_SNAFU, LOG_ERR, "Unimplemented option \"%s\"", argv[optind - 1]); } else { log_err (EMUNGE_SNAFU, LOG_ERR, "Unimplemented option \"-%c\"", c); } break; } } if (argv[optind]) { log_err (EMUNGE_SNAFU, LOG_ERR, "Unrecognized parameter \"%s\"", argv[optind]); } /* Create arbitrary payload of the specified length. */ if (conf->num_payload > 0) { if (!(conf->payload = malloc (conf->num_payload + 1))) { log_err (EMUNGE_NO_MEMORY, LOG_ERR, "Failed to allocate credential payload of %d byte%s", conf->num_payload, (conf->num_payload == 1 ? "" : "s")); } for (i = 0, c = 'A'; i < conf->num_payload; i++) { if ((conf->payload[i] = c++) == 'Z') { c = 'A'; } } conf->payload[conf->num_payload] = '\0'; } return; } void display_help (char *prog) { /* Displays a help message describing the command-line options. */ const int w = -25; /* pad for width of option string */ assert (prog != NULL); printf ("Usage: %s [OPTIONS]\n", prog); printf ("\n"); printf (" %*s %s\n", w, "-h, --help", "Display this help message"); printf (" %*s %s\n", w, "-L, --license", "Display license information"); printf (" %*s %s\n", w, "-V, --version", "Display version information"); printf (" %*s %s\n", w, "-q, --quiet", "Display only the creds/sec numeric result"); printf ("\n"); printf (" %*s %s\n", w, "-c, --cipher=STR", "Specify cipher type"); printf (" %*s %s\n", w, "-C, --list-ciphers", "Display a list of supported ciphers"); printf (" %*s %s\n", w, "-m, --mac=STR", "Specify MAC type"); printf (" %*s %s\n", w, "-M, --list-macs", "Display a list of supported MACs"); printf (" %*s %s\n", w, "-z, --zip=STR", "Specify compression type"); printf (" %*s %s\n", w, "-Z, --list-zips", "Display a list of supported compressions"); printf ("\n"); printf (" %*s %s\n", w, "-e, --encode", "Encode (but do not decode) each credential"); printf (" %*s %s\n", w, "-d, --decode", "Encode and decode each credential"); printf (" %*s %s\n", w, "-l, --length=BYTES", "Specify payload length (in bytes)"); printf (" %*s %s\n", w, "-u, --restrict-uid=UID", "Restrict credential decoding by user/UID"); printf (" %*s %s\n", w, "-g, --restrict-gid=GID", "Restrict credential decoding by group/GID"); printf (" %*s %s\n", w, "-t, --ttl=SECS", "Specify time-to-live (in seconds; 0=dfl -1=max)"); printf (" %*s %s\n", w, "-S, --socket=PATH", "Specify local socket for munged"); printf ("\n"); printf (" %*s %s\n", w, "-D, --duration=SECS", "Specify test duration (in seconds; -1=max)"); printf (" %*s %s\n", w, "-N, --num-creds=INT", "Specify number of credentials to generate"); printf (" %*s %s\n", w, "-T, --num-threads=INT", "Specify number of threads to spawn"); printf (" %*s %s\n", w, "-W, --warn-time=SECS", "Specify max seconds for munge op before warning"); printf ("\n"); return; } void display_strings (const char *header, munge_enum_t type) { int i; const char *p; if (header) { printf ("%s:\n\n", header); } for (i = 0; (p = munge_enum_int_to_str (type, i)); i++) { if (munge_enum_is_valid (type, i)) { printf (" %s (%d)\n", p, i); } } printf ("\n"); return; } int get_si_multiple (char c) { /* Converts the SI-suffix [c] into an equivalent multiplier. * Returns the multiple, or 0 if invalid. */ int multiple; switch (c) { case '\0': /* bytes */ multiple = 1; break; case 'k': /* kilobytes */ multiple = 1e3; break; case 'K': /* kibibytes */ multiple = 1 << 10; break; case 'm': /* megabytes */ multiple = 1e6; break; case 'M': /* mebibytes */ multiple = 1 << 20; break; case 'g': /* gigabytes */ multiple = 1e9; break; case 'G': /* gibibytes */ multiple = 1 << 30; break; default: multiple = 0; break; } return (multiple); } int get_time_multiple (char c) { /* Converts the time suffix [c] into a multiplier for computing * the number of seconds. * Returns the multiple, or 0 if invalid. */ int multiple; switch (c) { case '\0': case 's': case 'S': multiple = 1; break; case 'm': case 'M': multiple = 60; break; case 'h': case 'H': multiple = 60 * 60; break; case 'd': case 'D': multiple = 60 * 60 * 24; break; default: multiple = 0; break; } return (multiple); } void start_threads (conf_t conf) { /* Start the number of threads specified by [conf] for processing credentials. */ pthread_attr_t tattr; size_t stacksize = 256 * 1024; int i; if (!(conf->tids = malloc (sizeof (*conf->tids) * conf->num_threads))) { log_err (EMUNGE_NO_MEMORY, LOG_ERR, "Failed to allocate tid array"); } if ((errno = pthread_attr_init (&tattr)) != 0) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to init thread attribute"); } #ifdef _POSIX_THREAD_ATTR_STACKSIZE if ((errno = pthread_attr_setstacksize (&tattr, stacksize)) != 0) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to set thread stacksize"); } #endif /* _POSIX_THREAD_ATTR_STACKSIZE */ /* * Lock mutex to prevent threads from starting until all are created. * After the timer has been started, the mutex will be unlocked via * pthread_cond_timedwait(). */ if ((errno = pthread_mutex_lock (&conf->mutex)) != 0) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to lock mutex"); } /* The purpose of the num_running count is for signaling the main thread * when the last worker thread has exited in order to interrupt the * pthread_cond_timedwait(). The reason num_running is set to * num_threads here instead of incrementing it at the start of each * thread is to prevent this condition from being signaled prematurely. * This could happen if all credentials are processed by just a few * threads before all threads have been scheduled to run; consequently, * num_running would bounce to 0 before all threads have finished while * the remaining threads would have no credentials left to process. */ assert (conf->num_threads > 0); conf->num_running = conf->num_threads; output_msg ("Spawning %d thread%s for %s", conf->num_threads, ((conf->num_threads == 1) ? "" : "s"), (conf->do_decode ? "encoding/decoding" : "encoding")); for (i = 0; i < conf->num_threads; i++) { if ((errno = pthread_create (&conf->tids[i], &tattr, (thread_f) remunge, conf)) != 0) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to create thread #%d", i+1); } } if ((errno = pthread_attr_destroy (&tattr)) != 0) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to destroy thread attribute"); } return; } void process_creds (conf_t conf) { /* Process credentials according to the configuration [conf]. * Processing continues for the specified duration or until the * credential count is reached, whichever comes first. */ int n_secs; unsigned long n_creds; struct timespec to; /* Start the main timer before the timeout is computed below. */ GET_TIMEVAL (conf->t_main_start); /* * The default is to process credentials for 1 second. */ if (!conf->num_creds && !conf->num_seconds) { conf->num_seconds = 1; } /* Save configuration values before they are further modified. */ n_secs = conf->num_seconds; n_creds = conf->num_creds; /* * If a duration is not specified (either explicitly or implicitly), * set the timeout to the maximum value so pthread_cond_timedwait() * can still be used. */ if (conf->num_seconds) { to.tv_sec = conf->t_main_start.tv_sec + conf->num_seconds; if (to.tv_sec < conf->t_main_start.tv_sec) { to.tv_sec = (sizeof (to.tv_sec) == 4) ? INT_MAX : LONG_MAX; } to.tv_nsec = conf->t_main_start.tv_usec * 1e3; } else { to.tv_sec = (sizeof (to.tv_sec) == 4) ? INT_MAX : LONG_MAX; to.tv_nsec = 0; } /* Recompute the number of seconds in case the specified duration * exceeded the maximum timeout. */ conf->num_seconds = to.tv_sec - conf->t_main_start.tv_sec; /* * If a credential count was not specified, set the limit at the maximum. */ if (!conf->num_creds) { conf->num_creds = ULONG_MAX; } /* Output processing start message. */ if (n_creds && !n_secs) { output_msg ("Processing %lu credential%s", conf->num_creds, ((conf->num_creds == 1) ? "" : "s")); } else if (n_secs && !n_creds) { output_msg ("Processing credentials for %d second%s", conf->num_seconds, ((conf->num_seconds == 1) ? "" : "s")); } else { output_msg ("Processing %lu credential%s for up to %d second%s", conf->num_creds, ((conf->num_creds == 1) ? "" : "s"), conf->num_seconds, ((conf->num_seconds == 1) ? "" : "s")); } /* Start processing credentials. */ while (conf->num_running > 0) { errno = pthread_cond_timedwait (&conf->cond_done, &conf->mutex, &to); if (!errno || (errno == ETIMEDOUT)) { break; } else if (errno == EINTR) { continue; } else { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to wait on condition"); } } return; } void stop_threads (conf_t conf) { /* Stop the threads from processing further credentials. Output the results. */ int i; unsigned long n; double delta; double rate; /* The mutex must be unlocked here in order to let the threads clean up * (via remunge_cleanup()) once they are canceled/finished. */ if ((errno = pthread_mutex_unlock (&conf->mutex)) != 0) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to unlock mutex"); } for (i = 0; i < conf->num_threads; i++) { errno = pthread_cancel (conf->tids[i]); if ((errno != 0) && (errno != ESRCH)) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to cancel thread #%d", i+1); } } for (i = 0; i < conf->num_threads; i++) { if ((errno = pthread_join (conf->tids[i], NULL)) != 0) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to join thread #%d", i+1); } conf->tids[i] = 0; } /* Stop the main timer now that all credential processing has stopped. */ GET_TIMEVAL (conf->t_main_stop); delta = DIFF_TIMEVAL (conf->t_main_stop, conf->t_main_start); /* * Output processing stop message and results. */ if (conf->shared.num_encode_errs && conf->shared.num_decode_errs) { output_msg ("Generated %lu encoding error%s and %lu decoding error%s", conf->shared.num_encode_errs, ((conf->shared.num_encode_errs == 1) ? "" : "s"), conf->shared.num_decode_errs, ((conf->shared.num_decode_errs == 1) ? "" : "s")); } else if (conf->shared.num_encode_errs) { output_msg ("Generated %lu encoding error%s", conf->shared.num_encode_errs, ((conf->shared.num_encode_errs == 1) ? "" : "s")); } else if (conf->shared.num_decode_errs) { output_msg ("Generated %lu decoding error%s", conf->shared.num_decode_errs, ((conf->shared.num_decode_errs == 1) ? "" : "s")); } /* Subtract the errors from the number of credentials processed. */ n = conf->shared.num_creds_done - conf->shared.num_encode_errs - conf->shared.num_decode_errs; rate = n / delta; output_msg ("Processed %lu credential%s in %0.3fs (%0.0f creds/sec)", n, ((n == 1) ? "" : "s"), delta, rate); if (g_got_quiet) { printf ("%0.0f\n", rate); } /* Check for minimum duration time interval. */ if (delta < MIN_DURATION) { printf ("\nWARNING: Results based on such a short time interval " "are of low accuracy\n\n"); } return; } void * remunge (conf_t conf) { /* Worker thread responsible for encoding/decoding/validating credentials. */ tdata_t tdata; int cancel_state; unsigned long n; unsigned long got_encode_err; unsigned long got_decode_err; struct timeval t_start; struct timeval t_stop; double delta; munge_err_t e; char *cred; void *data; int dlen; uid_t uid; gid_t gid; tdata = create_tdata (conf); pthread_cleanup_push ((thread_cleanup_f) remunge_cleanup, tdata); if ((errno = pthread_mutex_lock (&conf->mutex)) != 0) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to lock mutex"); } while (conf->num_creds - conf->shared.num_creds_done > 0) { pthread_testcancel (); if ((errno = pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, &cancel_state)) != 0) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to disable thread cancellation"); } n = ++conf->shared.num_creds_done; if ((errno = pthread_mutex_unlock (&conf->mutex)) != 0) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to unlock mutex"); } got_encode_err = 0; got_decode_err = 0; data = NULL; GET_TIMEVAL (t_start); e = munge_encode(&cred, tdata->ectx, conf->payload, conf->num_payload); GET_TIMEVAL (t_stop); delta = DIFF_TIMEVAL (t_stop, t_start); if (delta > conf->warn_time) { output_msg ("Credential #%lu encoding took %0.3f seconds", n, delta); } if (e != EMUNGE_SUCCESS) { output_msg ("Credential #%lu encoding failed: %s (err=%d)", n, munge_ctx_strerror (tdata->ectx), e); ++got_encode_err; } else if (conf->do_decode) { GET_TIMEVAL (t_start); e = munge_decode (cred, tdata->dctx, &data, &dlen, &uid, &gid); GET_TIMEVAL (t_stop); delta = DIFF_TIMEVAL (t_stop, t_start); if (delta > conf->warn_time) { output_msg ("Credential #%lu decoding took %0.3f seconds", n, delta); } if (e != EMUNGE_SUCCESS) { output_msg ("Credential #%lu decoding failed: %s (err=%d)", n, munge_ctx_strerror (tdata->dctx), e); ++got_decode_err; } /* FIXME: * The following block does some validating of the decoded credential. * It should have a cmdline option to enable this validation check. * The decode ctx should also be checked against the encode ctx. * This becomes slightly more difficult in that it must also take * into account the default field settings. * * This block should be moved into a separate function (or more). * The [cred], [data], [dlen], [uid], and [gid] vars could be placed * into the tdata struct to facilitate parameter passing. */ #if 0 else if (conf->do_validate) { if (getuid () != uid) { output_msg ( "Credential #%lu UID %d does not match process UID %d", n, uid, getuid ()); } if (getgid () != gid) { output_msg ( "Credential #%lu GID %d does not match process GID %d", n, gid, getgid ()); } if (conf->num_payload != dlen) { output_msg ( "Credential #%lu payload length mismatch (%d/%d)", n, conf->num_payload, dlen); } else if (data && memcmp (conf->payload, data, dlen) != 0) { output_msg ("Credential #%lu payload mismatch", n); } } #endif /* 0 */ /* The 'data' parm can still be set on certain munge errors. */ if (data != NULL) { free (data); } } if (cred != NULL) { free (cred); } if ((errno = pthread_setcancelstate (cancel_state, &cancel_state)) != 0) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to enable thread cancellation"); } if ((errno = pthread_mutex_lock (&conf->mutex)) != 0) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to lock mutex"); } conf->shared.num_encode_errs += got_encode_err; conf->shared.num_decode_errs += got_decode_err; } pthread_cleanup_pop (1); return (NULL); } void remunge_cleanup (tdata_t tdata) { /* Signal the main thread when the last worker thread is exiting. * Clean up resources held by the thread. */ if (--tdata->conf->num_running == 0) { if ((errno = pthread_cond_signal (&tdata->conf->cond_done)) != 0) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to signal condition"); } } if ((errno = pthread_mutex_unlock (&tdata->conf->mutex)) != 0) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to unlock mutex"); } destroy_tdata (tdata); return; } void output_msg (const char *format, ...) { /* Outputs the current time followed by the [format] string * to stdout in a thread-safe manner. */ time_t t; struct tm tm; struct tm *tm_ptr; char buf[256]; char *p = buf; int len = sizeof (buf); int n; va_list vargs; if (g_got_quiet) { return; } if (!format) { return; } if (time (&t) == ((time_t) -1)) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to query current time"); } #if HAVE_LOCALTIME_R tm_ptr = localtime_r (&t, &tm); #else /* !HAVE_LOCALTIME_R */ tm_ptr = localtime (&t); #endif /* !HAVE_LOCALTIME_R */ if (tm_ptr != NULL) { n = strftime (p, len, "%Y-%m-%d %H:%M:%S ", tm_ptr); if ((n <= 0) || (n >= len)) { log_err (EMUNGE_SNAFU, LOG_ERR, "Exceeded buffer while writing timestamp"); } p += n; len -= n; } va_start (vargs, format); n = vsnprintf (p, len, format, vargs); va_end (vargs); if ((n < 0) || (n >= len)) { buf[sizeof (buf) - 2] = '+'; buf[sizeof (buf) - 1] = '\0'; /* technically redundant */ } printf ("%s\n", buf); return; } munge-munge-0.5.15/src/munge/unmunge.1.in000066400000000000000000000125211425467526100201120ustar00rootroot00000000000000.\"**************************************************************************** .\" Written by Chris Dunlap . .\" Copyright (C) 2007-2022 Lawrence Livermore National Security, LLC. .\" Copyright (C) 2002-2007 The Regents of the University of California. .\" UCRL-CODE-155910. .\" .\" This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE). .\" For details, see . .\" .\" MUNGE 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. Additionally for the MUNGE library (libmunge), you .\" can redistribute it and/or modify it under the terms of the GNU Lesser .\" General Public License as published by the Free Software Foundation, .\" either version 3 of the License, or (at your option) any later version. .\" .\" MUNGE 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 .\" and GNU Lesser General Public License for more details. .\" .\" You should have received a copy of the GNU General Public License .\" and GNU Lesser General Public License along with MUNGE. If not, see .\" . .\"**************************************************************************** .TH UNMUNGE 1 "@DATE@" "@PACKAGE@-@VERSION@" "MUNGE Uid 'N' Gid Emporium" .SH NAME unmunge \- MUNGE credential decoder .SH SYNOPSIS .B unmunge [\fIOPTION\fR]... .SH DESCRIPTION The \fBunmunge\fR program validates a MUNGE credential (e.g., one created by the \fBmunge\fR program). .PP By default, the credential is read from stdin and the metadata and payload are written to stdout. When the metadata and payload are written to the same stream, they are separated by a blank line. .SH OPTIONS .TP .BI "\-h, \-\-help" Display a summary of the command-line options. .TP .BI "\-L, \-\-license" Display license information. .TP .BI "\-V, \-\-version" Display version information. .TP .BI "\-i, \-\-input " path Input the credential from the specified file. .TP .BI "\-n, \-\-no\-output" Discard all output, both metadata and payload. .TP .BI "\-m, \-\-metadata " path Output metadata to the specified file. .TP .BI "\-o, \-\-output " path Output the payload to the specified file. .TP .BI "\-k, \-\-keys " string Specify a subset of metadata keys to output. The keys are case-insensitive and delimited by whitespace, commas, semicolons, or periods -- as long as the string is treated as a single argument by the shell (e.g., enclosed by quotes). Invalid keys are ignored. If a subset is not specified, all available keys are selected by default. .TP .BI "\-K, \-\-list\-keys" Display a list of metadata keys. .TP .BI "\-N, \-\-numeric" Display metadata values numerically. This omits conversions from IP addresses to hostnames, seconds to date and time strings, UIDs to user names, GIDs to group names, and cipher/mac/zip type lookups. .TP .BI "\-S, \-\-socket " path Specify the local socket for connecting with \fBmunged\fR. .SH "METADATA KEYS" The following metadata keys are supported. .TP .B STATUS The status of the credential decode operation. .TP .B ENCODE_HOST The address of the host on which the credential was encoded. .TP .B ENCODE_TIME The time at which the credential was encoded (according to the local clock of the host that encoded it). .TP .B DECODE_TIME The time at which the credential was decoded (according to the local clock of the host that decoded it). .TP .B TTL The time-to-live value (in seconds) placed within the credential. .TP .B CIPHER The cipher type used to encode the credential. .TP .B MAC The MAC type used to encode the credential. .TP .B ZIP The compression type used to encode the credential. .TP .B UID The user ID of the process that encoded the credential. .TP .B GID The group ID of the process that encoded the credential. .TP .B UID_RESTRICTION The user ID restriction placed within the credential. .TP .B GID_RESTRICTION The group ID restriction placed within the credential. .TP .B LENGTH The length (in bytes) of the payload. .SH "EXIT STATUS" The \fBunmunge\fR program returns an exit code corresponding to the return code of \fBmunge_decode\fR(). On success, it returns a zero exit code which signifies the credential is valid. On error, it prints an error message to stderr and returns a non-zero exit code. .SH AUTHOR Chris Dunlap .SH COPYRIGHT Copyright (C) 2007-2022 Lawrence Livermore National Security, LLC. .br Copyright (C) 2002-2007 The Regents of the University of California. .PP MUNGE 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. .PP Additionally for the MUNGE library (libmunge), you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. .SH "SEE ALSO" .BR munge (1), .BR remunge (1), .BR munge (3), .BR munge_ctx (3), .BR munge_enum (3), .BR munge (7), .BR munged (8), .BR mungekey (8). .PP \fBhttps://dun.github.io/munge/\fR munge-munge-0.5.15/src/munge/unmunge.c000066400000000000000000001003211425467526100175630ustar00rootroot00000000000000/***************************************************************************** * Written by Chris Dunlap . * Copyright (C) 2007-2022 Lawrence Livermore National Security, LLC. * Copyright (C) 2002-2007 The Regents of the University of California. * UCRL-CODE-155910. * * This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE). * For details, see . * * MUNGE 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. Additionally for the MUNGE library (libmunge), you * can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation, * either version 3 of the License, or (at your option) any later version. * * MUNGE 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 * and GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * and GNU Lesser General Public License along with MUNGE. If not, see * . *****************************************************************************/ #if HAVE_CONFIG_H # include "config.h" #endif /* HAVE_CONFIG_H */ #include /* include before in.h for bsd */ #include /* include before inet.h for bsd */ #include #include #include #include #include #include /* for gethostbyaddr() */ #include #include #include #include #include #include /* for AF_INET */ #include #include #include #include #include "common.h" #include "license.h" #include "log.h" #include "missing.h" /* for inet_ntop() */ #include "read.h" #include "version.h" #include "xsignal.h" /***************************************************************************** * Constants *****************************************************************************/ #define MAX_TIME_STR 64 /***************************************************************************** * Typedefs *****************************************************************************/ typedef struct conf * conf_t; typedef void display_func_t (conf_t); typedef struct { int val; char *str; display_func_t *fp; } display_key_t; /***************************************************************************** * Prototypes *****************************************************************************/ conf_t create_conf (void); void destroy_conf (conf_t conf); void parse_cmdline (conf_t conf, int argc, char **argv); void display_help (char *prog); void parse_keys (conf_t conf, char *keys); void display_keys (void); void open_files (conf_t conf); void display_meta (conf_t conf); void display_status (conf_t conf); void display_encode_host (conf_t conf); void display_encode_time (conf_t conf); void display_decode_time (conf_t conf); void display_time (conf_t conf, int munge_key); void display_ttl (conf_t conf); void display_cipher_type (conf_t conf); void display_mac_type (conf_t conf); void display_zip_type (conf_t conf); void display_uid (conf_t conf); void display_gid (conf_t conf); void display_uid_restriction (conf_t conf); void display_gid_restriction (conf_t conf); void display_length (conf_t conf); void display_data (conf_t conf); int key_str_to_val (const char *str); const char * key_val_to_str (int val); /***************************************************************************** * MUNGE Keys *****************************************************************************/ typedef enum { MUNGE_KEY_STATUS, MUNGE_KEY_ENCODE_HOST, MUNGE_KEY_ENCODE_TIME, MUNGE_KEY_DECODE_TIME, MUNGE_KEY_TTL, MUNGE_KEY_CIPHER_TYPE, MUNGE_KEY_MAC_TYPE, MUNGE_KEY_ZIP_TYPE, MUNGE_KEY_UID, MUNGE_KEY_GID, MUNGE_KEY_UID_RESTRICTION, MUNGE_KEY_GID_RESTRICTION, MUNGE_KEY_LENGTH, MUNGE_KEY_LAST } munge_key_t; display_key_t munge_keys[] = { { MUNGE_KEY_STATUS, "STATUS", display_status }, { MUNGE_KEY_ENCODE_HOST, "ENCODE_HOST", display_encode_host }, { MUNGE_KEY_ENCODE_TIME, "ENCODE_TIME", display_encode_time }, { MUNGE_KEY_DECODE_TIME, "DECODE_TIME", display_decode_time }, { MUNGE_KEY_TTL, "TTL", display_ttl }, { MUNGE_KEY_CIPHER_TYPE, "CIPHER", display_cipher_type }, { MUNGE_KEY_MAC_TYPE, "MAC", display_mac_type }, { MUNGE_KEY_ZIP_TYPE, "ZIP", display_zip_type }, { MUNGE_KEY_UID, "UID", display_uid }, { MUNGE_KEY_GID, "GID", display_gid }, { MUNGE_KEY_UID_RESTRICTION, "UID_RESTRICTION", display_uid_restriction }, { MUNGE_KEY_GID_RESTRICTION, "GID_RESTRICTION", display_gid_restriction }, { MUNGE_KEY_LENGTH, "LENGTH", display_length }, { MUNGE_KEY_LAST, NULL, NULL } }; /***************************************************************************** * Command-Line Options *****************************************************************************/ const char * const short_opts = ":hLVi:nm:o:k:KNS:"; #include struct option long_opts[] = { { "help", no_argument, NULL, 'h' }, { "license", no_argument, NULL, 'L' }, { "version", no_argument, NULL, 'V' }, { "input", required_argument, NULL, 'i' }, { "no-output", no_argument, NULL, 'n' }, { "metadata", required_argument, NULL, 'm' }, { "output", required_argument, NULL, 'o' }, { "keys", required_argument, NULL, 'k' }, { "list-keys", no_argument, NULL, 'K' }, { "numeric", no_argument, NULL, 'N' }, { "socket", required_argument, NULL, 'S' }, { NULL, 0, NULL, 0 } }; /***************************************************************************** * Configuration *****************************************************************************/ struct conf { munge_ctx_t ctx; /* munge context */ munge_err_t status; /* error status unmunging the cred */ char *fn_in; /* input filename, '-' for stdin */ char *fn_meta; /* metadata filename, '-' for stdout */ char *fn_out; /* output filename, '-' for stdout */ FILE *fp_in; /* input file pointer */ FILE *fp_meta; /* metadata file pointer */ FILE *fp_out; /* output file pointer */ int clen; /* munged credential length */ char *cred; /* munged credential */ int dlen; /* unmunged payload data length */ void *data; /* unmunged payload data */ uid_t uid; /* process uid according to cred */ gid_t gid; /* process gid according to cred */ char key[ MUNGE_KEY_LAST ]; /* key flag array (true if enabled) */ int key_width; /* num chars reserved for key field */ unsigned got_numeric:1; /* flag for NUMERIC option */ }; /***************************************************************************** * Functions *****************************************************************************/ int main (int argc, char *argv[]) { conf_t conf; int rc; const char *p; xsignal_ignore (SIGHUP); xsignal_ignore (SIGPIPE); log_open_file (stderr, argv[0], LOG_INFO, LOG_OPT_PRIORITY); conf = create_conf (); parse_cmdline (conf, argc, argv); open_files (conf); read_data_from_file (conf->fp_in, (void **) &conf->cred, &conf->clen); conf->status = munge_decode (conf->cred, conf->ctx, &conf->data, &conf->dlen, &conf->uid, &conf->gid); /* If the credential is expired, rewound, or replayed, the integrity * of its contents is valid even though the credential itself is not. * As such, display the metadata & payload with an appropriate status * if the integrity checks succeed; o/w, exit out here with an error. */ if ((conf->status != EMUNGE_SUCCESS) && (conf->status != EMUNGE_CRED_EXPIRED) && (conf->status != EMUNGE_CRED_REWOUND) && (conf->status != EMUNGE_CRED_REPLAYED)) { p = munge_ctx_strerror (conf->ctx); if (p == NULL) { p = munge_strerror (conf->status); } log_err (conf->status, LOG_ERR, "%s", p); } display_meta (conf); display_data (conf); rc = conf->status; destroy_conf (conf); log_close_file (); exit (rc); } conf_t create_conf (void) { conf_t conf; int i; int len; int maxlen; if (!(conf = malloc (sizeof (struct conf)))) { log_errno (EMUNGE_NO_MEMORY, LOG_ERR, "Failed to allocate conf"); } if (!(conf->ctx = munge_ctx_create ())) { log_errno (EMUNGE_NO_MEMORY, LOG_ERR, "Failed to create conf ctx"); } conf->status = -1; conf->fn_in = "-"; conf->fn_meta = "-"; conf->fn_out = "-"; conf->fp_in = NULL; conf->fp_meta = NULL; conf->fp_out = NULL; conf->clen = 0; conf->cred = NULL; conf->dlen = 0; conf->data = NULL; conf->uid = UID_SENTINEL; conf->gid = GID_SENTINEL; for (i = 0, maxlen = 0; i < MUNGE_KEY_LAST; i++) { conf->key[i] = 0; len = strlen (key_val_to_str (i)); maxlen = MAX (maxlen, len); } conf->key_width = maxlen + 1; /* separate longest key by one space */ conf->got_numeric = 0; return (conf); } void destroy_conf (conf_t conf) { /* XXX: Don't free() conf's fn_in/fn_meta/fn_out * since they point inside argv[]. */ if (conf->fp_in != NULL) { if (fclose (conf->fp_in) < 0) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to close input file"); } conf->fp_in = NULL; } if (conf->fp_meta != NULL) { if ((fclose (conf->fp_meta) < 0) && (errno != EPIPE)) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to close metadata output file"); } conf->fp_meta = NULL; } if (conf->fp_out != NULL) { if (conf->fn_out && conf->fn_meta && strcmp (conf->fn_out, conf->fn_meta)) { if ((fclose (conf->fp_out) < 0) && (errno != EPIPE)) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to close payload output file"); } } conf->fp_out = NULL; } if (conf->cred) { assert (conf->clen > 0); memburn (conf->cred, 0, conf->clen); free (conf->cred); conf->cred = NULL; } if (conf->data) { assert (conf->dlen > 0); memburn (conf->data, 0, conf->dlen); free (conf->data); conf->data = NULL; } munge_ctx_destroy (conf->ctx); free (conf); return; } void parse_cmdline (conf_t conf, int argc, char **argv) { int got_keys = 0; char *prog; int c; munge_err_t e; const char *p; int i; opterr = 0; /* suppress default getopt err msgs */ prog = (prog = strrchr (argv[0], '/')) ? prog + 1 : argv[0]; for (;;) { c = getopt_long (argc, argv, short_opts, long_opts, NULL); if (c == -1) { /* reached end of option list */ break; } switch (c) { case 'h': display_help (prog); exit (EMUNGE_SUCCESS); break; case 'L': display_license (); exit (EMUNGE_SUCCESS); break; case 'V': display_version (); exit (EMUNGE_SUCCESS); break; case 'i': conf->fn_in = optarg; break; case 'n': conf->fn_meta = NULL; conf->fn_out = NULL; break; case 'm': conf->fn_meta = optarg; break; case 'o': conf->fn_out = optarg; break; case 'k': got_keys = 1; parse_keys (conf, optarg); break; case 'K': display_keys (); exit (EMUNGE_SUCCESS); break; case 'N': conf->got_numeric = 1; break; case 'S': e = munge_ctx_set (conf->ctx, MUNGE_OPT_SOCKET, optarg); if (e != EMUNGE_SUCCESS) { p = munge_ctx_strerror (conf->ctx); log_err (EMUNGE_SNAFU, LOG_ERR, "Failed to set munge socket name: %s", (p ? p : "Unspecified error")); } break; case '?': if (optopt > 0) { log_err (EMUNGE_SNAFU, LOG_ERR, "Invalid option \"-%c\"", optopt); } else if (optind > 1) { log_err (EMUNGE_SNAFU, LOG_ERR, "Invalid option \"%s\"", argv[optind - 1]); } else { log_err (EMUNGE_SNAFU, LOG_ERR, "Failed to process command-line"); } break; case ':': if ((optind > 1) && (!strncmp (argv[optind - 1], "--", 2))) { log_err (EMUNGE_SNAFU, LOG_ERR, "Missing argument for option \"%s\"", argv[optind - 1]); } else if (optopt > 0) { log_err (EMUNGE_SNAFU, LOG_ERR, "Missing argument for option \"-%c\"", optopt); } else { log_err (EMUNGE_SNAFU, LOG_ERR, "Failed to process command-line"); } break; default: if ((optind > 1) && (!strncmp (argv[optind - 1], "--", 2))) { log_err (EMUNGE_SNAFU, LOG_ERR, "Unimplemented option \"%s\"", argv[optind - 1]); } else { log_err (EMUNGE_SNAFU, LOG_ERR, "Unimplemented option \"-%c\"", c); } break; } } if (argv[optind]) { log_err (EMUNGE_SNAFU, LOG_ERR, "Unrecognized parameter \"%s\"", argv[optind]); } /* Enable all metadata keys if a subset was not specified. */ if (!got_keys) { for (i = 0; i < MUNGE_KEY_LAST; i++) { conf->key[i] = 1; } } return; } void display_help (char *prog) { const int w = -25; /* pad for width of option string */ assert (prog != NULL); printf ("Usage: %s [OPTIONS]\n", prog); printf ("\n"); printf (" %*s %s\n", w, "-h, --help", "Display this help message"); printf (" %*s %s\n", w, "-L, --license", "Display license information"); printf (" %*s %s\n", w, "-V, --version", "Display version information"); printf ("\n"); printf (" %*s %s\n", w, "-i, --input=PATH", "Input credential from file"); printf (" %*s %s\n", w, "-n, --no-output", "Discard all output"); printf (" %*s %s\n", w, "-m, --metadata=PATH", "Output metadata to file"); printf (" %*s %s\n", w, "-o, --output=PATH", "Output payload to file"); printf ("\n"); printf (" %*s %s\n", w, "-k, --keys=STR", "Specify subset of metadata keys to output"); printf (" %*s %s\n", w, "-K, --list-keys", "Display list of metadata keys"); printf (" %*s %s\n", w, "-N, --numeric", "Display metadata values numerically"); printf (" %*s %s\n", w, "-S, --socket=PATH", "Specify local socket for munged"); printf ("\n"); printf ("By default, credential read from stdin, " "metadata & payload written to stdout.\n\n"); return; } void parse_keys (conf_t conf, char *keys) { const char *separators = " \t\n.,;"; char *key; int val; if (!keys || !*keys) { return; } key = strtok (keys, separators); while (key != NULL) { val = key_str_to_val (key); if (val >= 0) { conf->key[val] = 1; } key = strtok (NULL, separators); } return; } void display_keys (void) { int i; printf ("Metadata keys:\n\n"); for (i = 0; i < MUNGE_KEY_LAST; i++) { printf (" %s\n", munge_keys[i].str); } printf ("\n"); return; } void open_files (conf_t conf) { if (conf->fn_in) { if (!strcmp (conf->fn_in, "-")) { conf->fp_in = stdin; } else if (!(conf->fp_in = fopen (conf->fn_in, "r"))) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to read from \"%s\"", conf->fn_in); } } if (conf->fn_meta) { if (!strcmp (conf->fn_meta, "-")) { conf->fp_meta = stdout; } else if (conf->fn_in && !strcmp (conf->fn_meta, conf->fn_in)) { log_err (EMUNGE_SNAFU, LOG_ERR, "Cannot read and write to the same file \"%s\"", conf->fn_meta); } else if (!(conf->fp_meta = fopen (conf->fn_meta, "w"))) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to write to \"%s\"", conf->fn_meta); } } if (conf->fn_out) { if (!strcmp (conf->fn_out, "-")) { conf->fp_out = stdout; } else if (conf->fn_in && !strcmp (conf->fn_out, conf->fn_in)) { log_err (EMUNGE_SNAFU, LOG_ERR, "Cannot read and write to the same file \"%s\"", conf->fn_out); } else if (conf->fn_meta && !strcmp (conf->fn_out, conf->fn_meta)) { conf->fp_out = conf->fp_meta; } else if (!(conf->fp_out = fopen (conf->fn_out, "w"))) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to write to \"%s\"", conf->fn_out); } } return; } void display_meta (conf_t conf) { int i; assert (conf != NULL); if (conf->fp_meta == NULL) { return; } for (i = 0; i < MUNGE_KEY_LAST; i++) { if (conf->key[i] && munge_keys[i].fp) { (*(munge_keys[i].fp)) (conf); } } /* Since we've been ignoring the return values of fprintf(), * check for errors on fp_meta. */ if (ferror (conf->fp_meta)) { log_err (EMUNGE_SNAFU, LOG_ERR, "Write error"); } /* Separate metadata from payload with a newline * if they are being written to the same file stream. */ if (conf->fp_meta == conf->fp_out) { fprintf (conf->fp_meta, "\n"); } return; } void display_status (conf_t conf) { const char *key; int num_spaces; assert (conf != NULL); key = key_val_to_str (MUNGE_KEY_STATUS); num_spaces = conf->key_width - strlen (key); if (conf->got_numeric) { fprintf (conf->fp_meta, "%s:%*c%d\n", key, num_spaces, 0x20, conf->status); } else { fprintf (conf->fp_meta, "%s:%*c%s (%d)\n", key, num_spaces, 0x20, munge_strerror (conf->status), conf->status); } return; } void display_encode_host (conf_t conf) { const char *key; int num_spaces; munge_err_t err; const char *p; struct in_addr addr; char addr_str[ INET_ADDRSTRLEN ]; struct hostent *hostent_ptr; assert (conf != NULL); key = key_val_to_str (MUNGE_KEY_ENCODE_HOST); num_spaces = conf->key_width - strlen (key); err = munge_ctx_get (conf->ctx, MUNGE_OPT_ADDR4, &addr); if (err != EMUNGE_SUCCESS) { p = munge_ctx_strerror (conf->ctx); log_err (EMUNGE_SNAFU, LOG_ERR, "Failed to retrieve %s: %s", key, (p ? p : "Unspecified error")); } if (!inet_ntop (AF_INET, &addr, addr_str, sizeof (addr_str))) { log_err (EMUNGE_SNAFU, LOG_ERR, "Failed to convert %s to string: %s", key, strerror (errno)); } if (conf->got_numeric) { fprintf (conf->fp_meta, "%s:%*c%s\n", key, num_spaces, 0x20, addr_str); } else { hostent_ptr = gethostbyaddr (&addr, sizeof (addr), AF_INET); fprintf (conf->fp_meta, "%s:%*c%s (%s)\n", key, num_spaces, 0x20, (hostent_ptr ? hostent_ptr->h_name : "???"), addr_str); } return; } void display_encode_time (conf_t conf) { const char *key; int num_spaces; munge_err_t err; const char *p; time_t t; struct tm *tm_ptr; int t_len; char t_buf[ MAX_TIME_STR ]; assert (conf != NULL); key = key_val_to_str (MUNGE_KEY_ENCODE_TIME); num_spaces = conf->key_width - strlen (key); err = munge_ctx_get (conf->ctx, MUNGE_OPT_ENCODE_TIME, &t); if (err != EMUNGE_SUCCESS) { p = munge_ctx_strerror (conf->ctx); log_err (EMUNGE_SNAFU, LOG_ERR, "Failed to retrieve %s: %s", key, (p ? p : "Unspecified error")); } if (conf->got_numeric) { fprintf (conf->fp_meta, "%s:%*c%ld\n", key, num_spaces, 0x20, (long) t); } else { tm_ptr = localtime (&t); if (tm_ptr == NULL) { log_err (EMUNGE_SNAFU, LOG_ERR, "Failed to convert %s to local time", key); } t_len = strftime (t_buf, sizeof (t_buf), "%Y-%m-%d %H:%M:%S %z", tm_ptr); if ((t_len == 0) || (t_len >= sizeof (t_buf))) { log_err (EMUNGE_OVERFLOW, LOG_ERR, "Failed to format %s: exceeded buffer", key); } /* Since ISO C does not support the '%s' strftime() format option... */ if (strcatf (t_buf, sizeof (t_buf), " (%ld)", (long) t) < 0) { log_err (EMUNGE_OVERFLOW, LOG_ERR, "Failed to format %s: exceeded buffer", key); } fprintf (conf->fp_meta, "%s:%*c%s\n", key, num_spaces, 0x20, t_buf); } return; } void display_decode_time (conf_t conf) { const char *key; int num_spaces; munge_err_t err; const char *p; time_t t; struct tm *tm_ptr; int t_len; char t_buf[ MAX_TIME_STR ]; assert (conf != NULL); key = key_val_to_str (MUNGE_KEY_DECODE_TIME); num_spaces = conf->key_width - strlen (key); err = munge_ctx_get (conf->ctx, MUNGE_OPT_DECODE_TIME, &t); if (err != EMUNGE_SUCCESS) { p = munge_ctx_strerror (conf->ctx); log_err (EMUNGE_SNAFU, LOG_ERR, "Failed to retrieve %s: %s", key, (p ? p : "Unspecified error")); } if (conf->got_numeric) { fprintf (conf->fp_meta, "%s:%*c%ld\n", key, num_spaces, 0x20, (long) t); } else { tm_ptr = localtime (&t); if (tm_ptr == NULL) { log_err (EMUNGE_SNAFU, LOG_ERR, "Failed to convert %s to local time", key); } t_len = strftime (t_buf, sizeof (t_buf), "%Y-%m-%d %H:%M:%S %z", tm_ptr); if ((t_len == 0) || (t_len >= sizeof (t_buf))) { log_err (EMUNGE_OVERFLOW, LOG_ERR, "Failed to format %s: exceeded buffer", key); } /* Since ISO C does not support the '%s' strftime() format option... */ if (strcatf (t_buf, sizeof (t_buf), " (%ld)", (long) t) < 0) { log_err (EMUNGE_OVERFLOW, LOG_ERR, "Failed to format %s: exceeded buffer", key); } fprintf (conf->fp_meta, "%s:%*c%s\n", key, num_spaces, 0x20, t_buf); } return; } void display_ttl (conf_t conf) { const char *key; int num_spaces; munge_err_t err; const char *p; int i; assert (conf != NULL); key = key_val_to_str (MUNGE_KEY_TTL); num_spaces = conf->key_width - strlen (key); err = munge_ctx_get (conf->ctx, MUNGE_OPT_TTL, &i); if (err != EMUNGE_SUCCESS) { p = munge_ctx_strerror (conf->ctx); log_err (EMUNGE_SNAFU, LOG_ERR, "Failed to retrieve %s: %s", key, (p ? p : "Unspecified error")); } fprintf (conf->fp_meta, "%s:%*c%d\n", key, num_spaces, 0x20, i); return; } void display_cipher_type (conf_t conf) { const char *key; int num_spaces; munge_err_t err; const char *p; int i; assert (conf != NULL); key = key_val_to_str (MUNGE_KEY_CIPHER_TYPE); num_spaces = conf->key_width - strlen (key); err = munge_ctx_get (conf->ctx, MUNGE_OPT_CIPHER_TYPE, &i); if (err != EMUNGE_SUCCESS) { p = munge_ctx_strerror (conf->ctx); log_err (EMUNGE_SNAFU, LOG_ERR, "Failed to retrieve %s: %s", key, (p ? p : "Unspecified error")); } if (conf->got_numeric) { fprintf (conf->fp_meta, "%s:%*c%d\n", key, num_spaces, 0x20, i); } else { p = munge_enum_int_to_str (MUNGE_ENUM_CIPHER, i); fprintf (conf->fp_meta, "%s:%*c%s (%d)\n", key, num_spaces, 0x20, (p ? p : "???"), i); } return; } void display_mac_type (conf_t conf) { const char *key; int num_spaces; munge_err_t err; const char *p; int i; assert (conf != NULL); key = key_val_to_str (MUNGE_KEY_MAC_TYPE); num_spaces = conf->key_width - strlen (key); err = munge_ctx_get (conf->ctx, MUNGE_OPT_MAC_TYPE, &i); if (err != EMUNGE_SUCCESS) { p = munge_ctx_strerror (conf->ctx); log_err (EMUNGE_SNAFU, LOG_ERR, "Failed to retrieve %s: %s", key, (p ? p : "Unspecified error")); } if (conf->got_numeric) { fprintf (conf->fp_meta, "%s:%*c%d\n", key, num_spaces, 0x20, i); } else { p = munge_enum_int_to_str (MUNGE_ENUM_MAC, i); fprintf (conf->fp_meta, "%s:%*c%s (%d)\n", key, num_spaces, 0x20, (p ? p : "???"), i); } return; } void display_zip_type (conf_t conf) { const char *key; int num_spaces; munge_err_t err; const char *p; int i; assert (conf != NULL); key = key_val_to_str (MUNGE_KEY_ZIP_TYPE); num_spaces = conf->key_width - strlen (key); err = munge_ctx_get (conf->ctx, MUNGE_OPT_ZIP_TYPE, &i); if (err != EMUNGE_SUCCESS) { p = munge_ctx_strerror (conf->ctx); log_err (EMUNGE_SNAFU, LOG_ERR, "Failed to retrieve %s: %s", key, (p ? p : "Unspecified error")); } if (conf->got_numeric) { fprintf (conf->fp_meta, "%s:%*c%d\n", key, num_spaces, 0x20, i); } else { p = munge_enum_int_to_str (MUNGE_ENUM_ZIP, i); fprintf (conf->fp_meta, "%s:%*c%s (%d)\n", key, num_spaces, 0x20, (p ? p : "???"), i); } return; } void display_uid (conf_t conf) { const char *key; int num_spaces; struct passwd *pw_ptr; assert (conf != NULL); key = key_val_to_str (MUNGE_KEY_UID); num_spaces = conf->key_width - strlen (key); if (conf->got_numeric) { fprintf (conf->fp_meta, "%s:%*c%u\n", key, num_spaces, 0x20, (unsigned int) conf->uid); } else { pw_ptr = getpwuid (conf->uid); fprintf (conf->fp_meta, "%s:%*c%s (%u)\n", key, num_spaces, 0x20, (pw_ptr ? pw_ptr->pw_name : "???"), (unsigned int) conf->uid); } return; } void display_gid (conf_t conf) { const char *key; int num_spaces; struct group *gr_ptr; assert (conf != NULL); key = key_val_to_str (MUNGE_KEY_GID); num_spaces = conf->key_width - strlen (key); if (conf->got_numeric) { fprintf (conf->fp_meta, "%s:%*c%u\n", key, num_spaces, 0x20, (unsigned int) conf->gid); } else { gr_ptr = getgrgid (conf->gid); fprintf (conf->fp_meta, "%s:%*c%s (%u)\n", key, num_spaces, 0x20, (gr_ptr ? gr_ptr->gr_name : "???"), (unsigned int) conf->gid); } return; } void display_uid_restriction (conf_t conf) { const char *key; int num_spaces; munge_err_t err; const char *p; int i; struct passwd *pw_ptr; assert (conf != NULL); key = key_val_to_str (MUNGE_KEY_UID_RESTRICTION); num_spaces = conf->key_width - strlen (key); err = munge_ctx_get (conf->ctx, MUNGE_OPT_UID_RESTRICTION, &i); if (err != EMUNGE_SUCCESS) { p = munge_ctx_strerror (conf->ctx); log_err (EMUNGE_SNAFU, LOG_ERR, "Failed to retrieve %s: %s", key, (p ? p : "Unspecified error")); } if (i == MUNGE_UID_ANY) { return; } if (conf->got_numeric) { fprintf (conf->fp_meta, "%s:%*c%u\n", key, num_spaces, 0x20, (unsigned int) i); } else { pw_ptr = getpwuid (i); fprintf (conf->fp_meta, "%s:%*c%s (%u)\n", key, num_spaces, 0x20, (pw_ptr ? pw_ptr->pw_name : "???"), (unsigned int) i); } return; } void display_gid_restriction (conf_t conf) { const char *key; int num_spaces; munge_err_t err; const char *p; int i; struct group *gr_ptr; assert (conf != NULL); key = key_val_to_str (MUNGE_KEY_GID_RESTRICTION); num_spaces = conf->key_width - strlen (key); err = munge_ctx_get (conf->ctx, MUNGE_OPT_GID_RESTRICTION, &i); if (err != EMUNGE_SUCCESS) { p = munge_ctx_strerror (conf->ctx); log_err (EMUNGE_SNAFU, LOG_ERR, "Failed to retrieve %s: %s", key, (p ? p : "Unspecified error")); } if (i == MUNGE_GID_ANY) { return; } if (conf->got_numeric) { fprintf (conf->fp_meta, "%s:%*c%u\n", key, num_spaces, 0x20, (unsigned int) i); } else { gr_ptr = getgrgid (i); fprintf (conf->fp_meta, "%s:%*c%s (%u)\n", key, num_spaces, 0x20, (gr_ptr ? gr_ptr->gr_name : "???"), (unsigned int) i); } return; } void display_length (conf_t conf) { const char *key; int num_spaces; assert (conf != NULL); key = key_val_to_str (MUNGE_KEY_LENGTH); num_spaces = conf->key_width - strlen (key); fprintf (conf->fp_meta, "%s:%*c%d\n", key, num_spaces, 0x20, conf->dlen); return; } void display_data (conf_t conf) { if ((conf->dlen <= 0) || (!conf->data)) { return; } if (!conf->fp_out) { return; } if (fwrite (conf->data, 1, conf->dlen, conf->fp_out) != conf->dlen) { log_err (EMUNGE_SNAFU, LOG_ERR, "Write error"); } /* If outputting to a tty, append a final newline if one is missing. */ if (isatty (fileno (conf->fp_out)) && ((char *) conf->data) [conf->dlen - 1] != '\n') { fprintf (conf->fp_out, "\n"); } return; } int key_str_to_val (const char *str) { int i; if ((str == NULL) || (str[0] == '\0')) { return (-1); } for (i = 0; i < MUNGE_KEY_LAST; i++) { if (!strcasecmp (str, munge_keys[i].str)) { return (i); } } return (-1); } const char * key_val_to_str (int val) { assert (val >= 0); assert (val < MUNGE_KEY_LAST); assert (munge_keys[val].str != NULL); return (munge_keys[val].str); } munge-munge-0.5.15/src/munged/000077500000000000000000000000001425467526100161105ustar00rootroot00000000000000munge-munge-0.5.15/src/munged/Makefile.am000066400000000000000000000057461425467526100201600ustar00rootroot00000000000000# MUNGE src/munged/Makefile.am # # This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE). # For details, see . include $(top_srcdir)/Make-inc.mk TEMPLATE_FILES = \ munged.8.in \ # End of TEMPLATE_FILES SUBSTITUTE_FILES = \ munged.8 \ # End of SUBSTITUTE_FILES EXTRA_DIST = \ $(TEMPLATE_FILES) \ # End of EXTRA_DIST CLEANFILES = \ $(SUBSTITUTE_FILES) \ # End of CLEANFILES $(SUBSTITUTE_FILES): Makefile $(AM_V_GEN)$(substitute) < '$(srcdir)/$@.in' > '$(builddir)/$@' munged.8: munged.8.in sbin_PROGRAMS = \ munged \ # End of sbin_PROGRAMS munged_CFLAGS = \ $(AM_CFLAGS) \ $(CRYPTO_CFLAGS) \ # End of munged_CFLAGS munged_CPPFLAGS = \ -DLOCALSTATEDIR='"$(localstatedir)"' \ -DRUNSTATEDIR='"$(runstatedir)"' \ -DSYSCONFDIR='"$(sysconfdir)"' \ -DWITH_PTHREADS \ -I$(top_srcdir)/src/common \ -I$(top_srcdir)/src/libcommon \ -I$(top_srcdir)/src/libmissing \ -I$(top_srcdir)/src/libmunge \ # End of munged_CPPFLAGS munged_LDADD = \ $(top_builddir)/src/libcommon/libcommon.la \ $(top_builddir)/src/libmissing/libmissing.la \ $(top_builddir)/src/libmunge/libmunge.la \ $(LIBPTHREAD) \ $(LIBBZ2) \ $(LIBRT) \ $(LIBZ) \ $(CRYPTO_LIBS) \ # End of munged_LDADD munged_SOURCES = \ munged.c \ auth_recv.c \ auth_recv.h \ base64.c \ base64.h \ cipher.c \ cipher.h \ clock.c \ clock.h \ conf.c \ conf.h \ cred.c \ cred.h \ dec.c \ dec.h \ enc.c \ enc.h \ gids.c \ gids.h \ hash.c \ hash.h \ job.c \ job.h \ lock.c \ lock.h \ net.c \ net.h \ path.c \ path.h \ random.c \ random.h \ replay.c \ replay.h \ thread.c \ thread.h \ timer.c \ timer.h \ work.c \ work.h \ zip.c \ zip.h \ $(top_srcdir)/src/common/crypto.c \ $(top_srcdir)/src/common/crypto.h \ $(top_srcdir)/src/common/entropy.c \ $(top_srcdir)/src/common/entropy.h \ $(top_srcdir)/src/common/mac.c \ $(top_srcdir)/src/common/mac.h \ $(top_srcdir)/src/common/md.c \ $(top_srcdir)/src/common/md.h \ $(top_srcdir)/src/common/query.c \ $(top_srcdir)/src/common/query.h \ $(top_srcdir)/src/common/rotate.c \ $(top_srcdir)/src/common/rotate.h \ $(top_srcdir)/src/common/xgetgr.c \ $(top_srcdir)/src/common/xgetgr.h \ $(top_srcdir)/src/common/xgetpw.c \ $(top_srcdir)/src/common/xgetpw.h \ $(top_srcdir)/src/common/xsignal.c \ $(top_srcdir)/src/common/xsignal.h \ # End of munged_SOURCES # For dependencies on LOCALSTATEDIR, RUNSTATEDIR, and SYSCONFDIR via the # #defines for MUNGE_AUTH_SERVER_DIR, MUNGE_KEYFILE_PATH, MUNGE_LOGFILE_PATH, # MUNGE_PIDFILE_PATH, MUNGE_SEEDFILE_PATH, and MUNGE_SOCKET_NAME. # $(srcdir)/munged-conf.$(OBJEXT): Makefile man_MANS = \ munged.8 \ # End of man_MANS check_PROGRAMS = \ $(TESTS) \ # End of check_PROGRAMS TESTS = \ base64_test \ # End of TESTS base64_test_CPPFLAGS = \ -I$(top_srcdir)/src/libtap \ # End of base64_test_CPPFLAGS base64_test_LDADD = \ $(top_builddir)/src/libtap/libtap.la \ # End of base64_test_LDADD base64_test_SOURCES = \ base64.c \ base64.h \ base64_test.c \ # End of base64_test_SOURCES munge-munge-0.5.15/src/munged/auth_recv.c000066400000000000000000000557541425467526100202540ustar00rootroot00000000000000/***************************************************************************** * Written by Chris Dunlap . * Copyright (C) 2007-2022 Lawrence Livermore National Security, LLC. * Copyright (C) 2002-2007 The Regents of the University of California. * UCRL-CODE-155910. * * This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE). * For details, see . * * MUNGE 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. Additionally for the MUNGE library (libmunge), you * can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation, * either version 3 of the License, or (at your option) any later version. * * MUNGE 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 * and GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * and GNU Lesser General Public License along with MUNGE. If not, see * . *****************************************************************************/ #if HAVE_CONFIG_H # include #endif /* HAVE_CONFIG_H */ #include #include #include #include #include #include "log.h" #include "m_msg.h" #include "path.h" /***************************************************************************** * initialization *****************************************************************************/ static void _check_auth_server_dir (const char *dir, int got_force); static void _check_auth_client_dir (const char *dir, int got_force); void auth_recv_init (const char *srvrdir, const char *clntdir, int got_force) { #ifdef AUTH_METHOD_RECVFD_MKNOD if (geteuid () != 0) { log_err (EMUNGE_SNAFU, LOG_ERR, "Root privileges are required for munged"); } #endif /* AUTH_METHOD_RECVFD_MKNOD */ _check_auth_server_dir (srvrdir, got_force); _check_auth_client_dir (clntdir, got_force); return; } static void _check_auth_server_dir (const char *dir, int got_force) { #if defined(AUTH_METHOD_RECVFD_MKFIFO) || defined(AUTH_METHOD_RECVFD_MKNOD) int is_symlink; struct stat st; int n; char ebuf [1024]; if ((dir == NULL) || (*dir == '\0')) { log_err (EMUNGE_SNAFU, LOG_ERR, "The auth server dir name is undefined"); } is_symlink = (lstat (dir, &st) == 0) ? S_ISLNK (st.st_mode) : 0; if (stat (dir, &st) < 0) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to stat auth server dir \"%s\"", dir); } /* Check if [dir] is an actual directory. */ if (!S_ISDIR (st.st_mode)) { log_err (EMUNGE_SNAFU, LOG_ERR, "The auth server dir is insecure: \"%s\" must be a directory", dir); } if (is_symlink) { log_err_or_warn (got_force, "The auth server dir is insecure: " "\"%s\" should not be a symbolic link", dir); } /* Check if [dir] has valid ownership and permissions. */ if (st.st_uid != geteuid ()) { log_err (EMUNGE_SNAFU, LOG_ERR, "The auth server dir is insecure: " "\"%s\" must be owned by UID %u", dir, (unsigned) geteuid ()); } if (!(st.st_mode & S_IWUSR)) { log_err (EMUNGE_SNAFU, LOG_ERR, "The auth server dir is insecure: " "\"%s\" must be writable by user", dir); } if (st.st_mode & S_IRGRP) { log_err_or_warn (got_force, "The auth server dir is insecure: " "\"%s\" should not be readable by group", dir); } if (st.st_mode & S_IROTH) { log_err_or_warn (got_force, "The auth server dir is insecure: " "\"%s\" should not be readable by other", dir); } /* Check if [dir] is secure against modification by others. */ n = path_is_secure (dir, ebuf, sizeof (ebuf), PATH_SECURITY_NO_FLAGS); if (n < 0) { log_err (EMUNGE_SNAFU, LOG_ERR, "Failed to check auth server dir \"%s\": %s", dir, ebuf); } else if (n == 0) { log_err_or_warn (got_force, "The auth server dir is insecure: %s", ebuf); } /* Check if [dir] path is accessible by all. */ n = path_is_accessible (dir, ebuf, sizeof (ebuf)); if (n < 0) { log_err (EMUNGE_SNAFU, LOG_ERR, "Failed to check auth server dir \"%s\": %s", dir, ebuf); } else if (n == 0) { log_err_or_warn (got_force, "The auth server dir is inaccessible: %s", ebuf); } #endif /* AUTH_METHOD_RECVFD_MKFIFO || AUTH_METHOD_RECVFD_MKNOD */ return; } static void _check_auth_client_dir (const char *dir, int got_force) { #if defined(AUTH_METHOD_RECVFD_MKFIFO) || defined(AUTH_METHOD_RECVFD_MKNOD) int is_symlink; struct stat st; int n; char parent_dir [PATH_MAX]; char ebuf [1024]; if ((dir == NULL) || (*dir == '\0')) { log_err (EMUNGE_SNAFU, LOG_ERR, "The auth client dir name is undefined"); } is_symlink = (lstat (dir, &st) == 0) ? S_ISLNK (st.st_mode) : 0; if (stat (dir, &st) < 0) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to check auth client dir \"%s\"", dir); } /* Check if [dir] is an actual directory. */ if (!S_ISDIR (st.st_mode)) { log_err (EMUNGE_SNAFU, LOG_ERR, "The auth client dir is insecure: \"%s\" must be a directory", dir); } if (is_symlink) { log_err_or_warn (got_force, "The auth client dir is insecure: " "\"%s\" should not be a symbolic link", dir); } /* Check if [dir] has valid ownership and permissions. */ if ((st.st_uid != 0) && (st.st_uid != geteuid ())) { log_err_or_warn (got_force, "The auth client dir is insecure: " "\"%s\" should be owned by UID %u or UID 0", dir, (unsigned) geteuid ()); } if ((st.st_mode & (S_IWUSR | S_IWGRP | S_IWOTH | S_ISVTX)) != (S_IWUSR | S_IWGRP | S_IWOTH | S_ISVTX)) { log_err (EMUNGE_SNAFU, LOG_ERR, "The auth client dir is insecure: " "\"%s\" must be writable by all with the sticky bit set", dir); } /* Check if parent dir is secure against modification by others. */ if (path_dirname (dir, parent_dir, sizeof (parent_dir)) < 0) { log_err (EMUNGE_SNAFU, LOG_ERR, "Failed to determine dirname of auth client dir \"%s\"", dir); } n = path_is_secure (parent_dir, ebuf, sizeof (ebuf), PATH_SECURITY_NO_FLAGS); if (n < 0) { log_err (EMUNGE_SNAFU, LOG_ERR, "Failed to check auth client parent dir \"%s\": %s", parent_dir, ebuf); } else if (n == 0) { log_err_or_warn (got_force, "The auth client dir is insecure: %s", ebuf); } /* Check if [dir] path is accessible by all. */ n = path_is_accessible (dir, ebuf, sizeof (ebuf)); if (n < 0) { log_err (EMUNGE_SNAFU, LOG_ERR, "Failed to check auth client dir \"%s\": %s", dir, ebuf); } else if (n == 0) { log_err_or_warn (got_force, "The auth client dir is inaccessible: %s", ebuf); } #endif /* AUTH_METHOD_RECVFD_MKFIFO || AUTH_METHOD_RECVFD_MKNOD */ return; } /***************************************************************************** * getpeereid *****************************************************************************/ #ifdef AUTH_METHOD_GETPEEREID #include #include int auth_recv (m_msg_t m, uid_t *uid, gid_t *gid) { if (getpeereid (m->sd, uid, gid) < 0) { log_msg (LOG_ERR, "Failed to get peer identity: %s", strerror (errno)); return (-1); } return (0); } #endif /* AUTH_METHOD_GETPEEREID */ /***************************************************************************** * getpeerucred *****************************************************************************/ #ifdef AUTH_METHOD_GETPEERUCRED #include int auth_recv (m_msg_t m, uid_t *uid, gid_t *gid) { ucred_t *ucred = NULL; uid_t uid_tmp; gid_t gid_tmp; int rc = -1; if (getpeerucred (m->sd, &ucred) < 0) { log_msg (LOG_ERR, "Failed to get peer ucred: %s", strerror (errno)); } else if ((uid_tmp = ucred_geteuid (ucred)) < 0) { log_msg (LOG_ERR, "Failed to get peer UID: %s", strerror (errno)); } else if ((gid_tmp = ucred_getegid (ucred)) < 0) { log_msg (LOG_ERR, "Failed to get peer GID: %s", strerror (errno)); } else { *uid = uid_tmp; *gid = gid_tmp; rc = 0; } if (ucred) { ucred_free (ucred); } return (rc); } #endif /* AUTH_METHOD_GETPEERUCRED */ /***************************************************************************** * SO_PEERCRED sockopt *****************************************************************************/ #ifdef AUTH_METHOD_SO_PEERCRED #include #ifndef HAVE_SOCKLEN_T typedef int socklen_t; /* socklen_t is uint32_t in Posix.1g */ #endif /* !HAVE_SOCKLEN_T */ int auth_recv (m_msg_t m, uid_t *uid, gid_t *gid) { struct ucred cred; socklen_t len = sizeof (cred); if (getsockopt (m->sd, SOL_SOCKET, SO_PEERCRED, &cred, &len) < 0) { log_msg (LOG_ERR, "Failed to get peer identity: %s", strerror (errno)); return (-1); } *uid = cred.uid; *gid = cred.gid; return (0); } #endif /* AUTH_METHOD_SO_PEERCRED */ /***************************************************************************** * LOCAL_PEERCRED sockopt *****************************************************************************/ #ifdef AUTH_METHOD_LOCAL_PEERCRED #include /* for FreeBSD */ #include #include #include /* for FreeBSD */ #ifndef HAVE_SOCKLEN_T typedef int socklen_t; /* socklen_t is uint32_t in Posix.1g */ #endif /* !HAVE_SOCKLEN_T */ int auth_recv (m_msg_t m, uid_t *uid, gid_t *gid) { struct xucred cred; socklen_t len = sizeof (cred); if (getsockopt (m->sd, 0, LOCAL_PEERCRED, &cred, &len) < 0) { log_msg (LOG_ERR, "Failed to get peer identity: %s", strerror (errno)); return (-1); } if (cred.cr_version != XUCRED_VERSION) { log_msg (LOG_ERR, "Failed to get peer identity: invalid xucred v%d", cred.cr_version); return (-1); } *uid = cred.cr_uid; *gid = cred.cr_gid; return (0); } #endif /* AUTH_METHOD_LOCAL_PEERCRED */ /***************************************************************************** * strrecvfd struct (mkfifo) *****************************************************************************/ #ifdef AUTH_METHOD_RECVFD_MKFIFO #include #include /* open, O_RDONLY */ #include /* free */ #include /* I_RECVFD, struct strrecvfd */ #include /* ioctl */ #include /* mkfifo, S_IWUSR, etc. */ static int _name_auth_pipe (char **pipe_name_p); static int _send_auth_req (int sd, const char *pipe_name); int auth_recv (m_msg_t m, uid_t *uid, gid_t *gid) { char *pipe_name = NULL; int pipe_fd = -1; struct strrecvfd recvfd; if (_name_auth_pipe (&pipe_name) < 0) { log_msg (LOG_ERR, "Failed to name auth pipe"); goto err; } assert (pipe_name != NULL); (void) unlink (pipe_name); /* in case it already exists */ /* * The auth pipe must be created in the filesystem before the auth req * is sent to the client in order to prevent a race condition. */ if (mkfifo (pipe_name, S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH) < 0) { log_msg (LOG_ERR, "Failed to create auth pipe \"%s\": %s", pipe_name, strerror (errno)); goto err; } if (_send_auth_req (m->sd, pipe_name) < 0) { log_msg (LOG_ERR, "Failed to send auth request"); goto err; } /* This open() blocks until the client opens the fifo for writing. * * FIXME: The open() & ioctl() calls could block and lead to a DoS attack. */ if ((pipe_fd = open (pipe_name, O_RDONLY)) < 0) { log_msg (LOG_ERR, "Failed to open auth pipe \"%s\": %s", pipe_name, strerror (errno)); goto err; } if (ioctl (pipe_fd, I_RECVFD, &recvfd) < 0) { log_msg (LOG_ERR, "Failed to receive client identity: %s", strerror (errno)); goto err; } /* Authentication has succeeded at this point, * so the following "errors" are not considered fatal. */ if (close (recvfd.fd) < 0) { log_msg (LOG_WARNING, "Failed to close auth fd from \"%s\": %s", pipe_name, strerror (errno)); } if (close (pipe_fd) < 0) { log_msg (LOG_WARNING, "Failed to close auth pipe \"%s\": %s", pipe_name, strerror (errno)); } if (unlink (pipe_name) < 0) { log_msg (LOG_WARNING, "Failed to remove auth pipe \"%s\": %s", pipe_name, strerror (errno)); } *uid = recvfd.uid; *gid = recvfd.gid; free (pipe_name); return (0); err: if (pipe_fd >= 0) { (void) close (pipe_fd); } if (pipe_name != NULL) { (void) unlink (pipe_name); free (pipe_name); } return (-1); } #endif /* AUTH_METHOD_RECVFD_MKFIFO */ /***************************************************************************** * strrecvfd struct (mknod) *****************************************************************************/ #ifdef AUTH_METHOD_RECVFD_MKNOD #include #include /* open, O_RDWR */ #include /* free */ #include /* struct strrecvfd, I_RECVFD */ #include /* ioctl */ #include /* struct stat, mknod, S_IFCHR */ #include /* queue_t */ #include /* include before stream.h for aix */ static int _ns_pipe (const char *name, int fds[2]); static int _s_pipe (int fd[2]); static int _name_auth_pipe (char **dst); static int _send_auth_req (int sd, const char *pipe_name); int auth_recv (m_msg_t m, uid_t *uid, gid_t *gid) { char *pipe_name = NULL; int pipe_fds[2] = {-1, -1}; struct strrecvfd recvfd; if (_name_auth_pipe (&pipe_name) < 0) { log_msg (LOG_ERR, "Failed to name auth pipe"); goto err; } assert (pipe_name != NULL); /* * The auth pipe must be created in the filesystem before the auth req * is sent to the client in order to prevent a race condition. */ if ((_ns_pipe (pipe_name, pipe_fds)) < 0) { log_msg (LOG_ERR, "Failed to create auth pipe \"%s\"", pipe_name); goto err; } if (_send_auth_req (m->sd, pipe_name) < 0) { log_msg (LOG_ERR, "Failed to send auth request"); goto err; } /* FIXME: The ioctl() call could block and lead to a DoS attack. */ if (ioctl (pipe_fds[0], I_RECVFD, &recvfd) < 0) { log_msg (LOG_ERR, "Failed to receive client identity: %s", strerror (errno)); goto err; } /* Authentication has succeeded at this point, * so the following "errors" are not considered fatal. */ if (close (recvfd.fd) < 0) { log_msg (LOG_WARNING, "Failed to close auth fd from \"%s\": %s", pipe_name, strerror (errno)); } if (close (pipe_fds[0]) < 0) { log_msg (LOG_WARNING, "Failed to close auth pipe \"%s\" for reading: %s", pipe_name, strerror (errno)); } if (close (pipe_fds[1]) < 0) { log_msg (LOG_WARNING, "Failed to close auth pipe \"%s\" for writing: %s", pipe_name, strerror (errno)); } if (unlink (pipe_name) < 0) { log_msg (LOG_WARNING, "Failed to remove auth pipe \"%s\": %s", pipe_name, strerror (errno)); } *uid = recvfd.uid; *gid = recvfd.gid; free (pipe_name); return (0); err: if (pipe_fds[0] >= 0) { (void) close (pipe_fds[0]); } if (pipe_fds[1] >= 0) { (void) close (pipe_fds[1]); } if (pipe_name != NULL) { (void) unlink (pipe_name); free (pipe_name); } return (-1); } static int _ns_pipe (const char *name, int fd[2]) { /* Creates a named stream pipe for SVR3 (cf, Stevens UNP1e, section 7.9). * To create a named stream pipe, we have to call mknod(). While any * user can call it to create a FIFO, only root can call it for any other * purpose. Consequently, root privileges are required to create a named * stream pipe. * The "write" end (ie, fd[1]) of this named stream pipe will be bound to * [name] since the client will open it by name in order to write its fd. * Returns 0 on success, -1 on error. */ int omask; struct stat stbuf; /* Start with creating an unnamed stream pipe. */ if (_s_pipe (fd) < 0) { return (-1); } /* Ensure mode is 0666, notb. */ omask = umask (0); /* * Unlink this name in case it already exists. */ (void) unlink (name); /* * Determine the major/minor device numbers of one end of the pipe. */ if (fstat (fd[1], &stbuf) < 0) { (void) close (fd[0]); (void) close (fd[1]); return (-1); } /* Create the filesystem entry by assigning the [name] to one end * of the pipe. This requires root privileges. */ if (mknod (name, S_IFCHR | 0666, stbuf.st_rdev) < 0) { (void) close (fd[0]); (void) close (fd[1]); umask (omask); return (-1); } umask (omask); return (0); } static int _s_pipe (int fd[2]) { /* Creates an unnamed stream pipe for SVR3 (cf, Stevens UNP1e, section 7.9). * Returns 0 on success, -1 on error. */ struct strfdinsert ins; queue_t *pointer; /* Open the stream clone device "/dev/spx" twice. */ if ((fd[0] = open ("/dev/spx", O_RDWR)) < 0) { return (-1); } if ((fd[1] = open ("/dev/spx", O_RDWR)) < 0) { (void) close (fd[0]); return (-1); } /* Link these two streams together with an I_FDINSERT ioctl. */ ins.ctlbuf.buf = (char *) &pointer; /* no ctrl info, just the ptr */ ins.ctlbuf.len = sizeof (queue_t *); ins.ctlbuf.maxlen = sizeof (queue_t *); ins.databuf.buf = (char *) 0; /* no data to send */ ins.databuf.len = -1; /* magic: must be -1 for stream pipe */ ins.databuf.maxlen = 0; ins.fildes = fd[1]; /* the fd to connect with fd[0] */ ins.flags = 0; /* non-priority message */ ins.offset = 0; /* offset of pointer in ctlbuf */ if (ioctl (fd[0], I_FDINSERT, (char *) &ins) < 0) { (void) close (fd[0]); (void) close (fd[1]); return (-1); } return (0); } #endif /* AUTH_METHOD_RECVFD_MKNOD */ /***************************************************************************** * strrecvfd struct (common) *****************************************************************************/ #if defined(AUTH_METHOD_RECVFD_MKFIFO) || defined(AUTH_METHOD_RECVFD_MKNOD) #include #include /* snprintf */ #include /* malloc, free */ #include /* memset, strlen, strdup */ #include "conf.h" #include "random.h" /* random_pseudo_bytes */ #include "str.h" /* strbin2hex */ static int _name_auth_pipe (char **pipe_name_p) { /* Creates a unique filename for the authentication pipe, storing the result * in a newly-allocated string referenced by [pipe_name_p]. * The caller is responsible for freeing the string returned by [pipe_name_p]. * The auth pipe name is of the form "AUTH_PIPE_DIR/.munge-RANDOM.pipe". * Returns 0 on success, -1 on error. */ unsigned char *nonce_bin = NULL; int nonce_bin_len; char *nonce_asc = NULL; int nonce_asc_len; char *dst = NULL; int dst_len; int n; *pipe_name_p = NULL; assert (conf->auth_rnd_bytes > 0); assert (conf->auth_server_dir != NULL); nonce_bin_len = conf->auth_rnd_bytes; if (!(nonce_bin = malloc (nonce_bin_len))) { goto err; } nonce_asc_len = (2 * nonce_bin_len) + 1; if (!(nonce_asc = malloc (nonce_asc_len))) { goto err; } dst_len = strlen (conf->auth_server_dir) + 8 /* strlen ("/.munge-") */ + (2 * conf->auth_rnd_bytes) + 6; /* strlen (".pipe") + "\0" */ if (!(dst = malloc (dst_len))) { goto err; } random_pseudo_bytes (nonce_bin, nonce_bin_len); if (!(strbin2hex (nonce_asc, nonce_asc_len, nonce_bin, nonce_bin_len))) { goto err; } n = snprintf (dst, dst_len, "%s/.munge-%s.pipe", conf->auth_server_dir, nonce_asc); if ((n < 0) || (n >= dst_len)) { goto err; } free (nonce_bin); free (nonce_asc); *pipe_name_p = dst; return (0); err: if (nonce_bin) { free (nonce_bin); } if (nonce_asc) { free (nonce_asc); } if (dst) { free (dst); } return (-1); } static int _send_auth_req (int sd, const char *pipe_name) { /* Sends an authentication request to the client on the established * socket [sd] using [pipe_name] as the authentication pipe to use * for sending an fd across. * Returns 0 on success, -1 on error. * * The authentication request message contains the authentication pipe name * for the client to send a file descriptor across, as well as the directory * name in which to create the authentication file corresponding to the file * descriptor being sent. */ m_msg_t m; munge_err_t e; if ((e = m_msg_create (&m)) != EMUNGE_SUCCESS) { goto end; } if ((e = m_msg_bind (m, sd)) != EMUNGE_SUCCESS) { goto end; } m->auth_s_str = (char *) pipe_name; m->auth_s_len = strlen (m->auth_s_str) + 1; m->auth_s_is_copy = 1; m->auth_c_str = conf->auth_client_dir; m->auth_c_len = strlen (m->auth_c_str) + 1; m->auth_c_is_copy = 1; e = m_msg_send (m, MUNGE_MSG_AUTH_FD_REQ, 0); end: if (m) { m->sd = -1; /* prevent close by m_msg_destroy() */ m_msg_destroy (m); } return (e == EMUNGE_SUCCESS ? 0 : -1); } #endif /* AUTH_METHOD_RECVFD_MKFIFO || AUTH_METHOD_RECVFD_MKNOD */ munge-munge-0.5.15/src/munged/auth_recv.h000066400000000000000000000040141425467526100202400ustar00rootroot00000000000000/***************************************************************************** * Written by Chris Dunlap . * Copyright (C) 2007-2022 Lawrence Livermore National Security, LLC. * Copyright (C) 2002-2007 The Regents of the University of California. * UCRL-CODE-155910. * * This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE). * For details, see . * * MUNGE 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. Additionally for the MUNGE library (libmunge), you * can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation, * either version 3 of the License, or (at your option) any later version. * * MUNGE 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 * and GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * and GNU Lesser General Public License along with MUNGE. If not, see * . *****************************************************************************/ #ifndef MUNGE_AUTH_RECV_H #define MUNGE_AUTH_RECV_H #include #include "m_msg.h" void auth_recv_init (const char *srvrdir, const char *clntdir, int got_force); /* * Checks for required privileges needed to perform client authentication. */ int auth_recv (m_msg_t m, uid_t *uid, gid_t *gid); /* * Receives the identity of the client that sent msg [m], * storing the result in the output parms [uid] and [gid]. * Note that the server NEVER simply trusts the client to * directly provide its identity. */ #endif /* !MUNGE_AUTH_RECV_H */ munge-munge-0.5.15/src/munged/base64.c000066400000000000000000000310011425467526100173330ustar00rootroot00000000000000/***************************************************************************** * Written by Chris Dunlap . * Copyright (C) 2007-2022 Lawrence Livermore National Security, LLC. * Copyright (C) 2002-2007 The Regents of the University of California. * UCRL-CODE-155910. * * This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE). * For details, see . * * MUNGE 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. Additionally for the MUNGE library (libmunge), you * can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation, * either version 3 of the License, or (at your option) any later version. * * MUNGE 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 * and GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * and GNU Lesser General Public License along with MUNGE. If not, see * . *****************************************************************************/ #if HAVE_CONFIG_H # include #endif /* HAVE_CONFIG_H */ #include #include #include "base64.h" /***************************************************************************** * Notes *****************************************************************************/ /* * For details on base64 encoding/decoding, refer to * rfc2440 (OpenPGP Message Format) sections 6.3-6.5. * * Why am I not using OpenSSL's base64 encoding/decoding functions? * Because they have the following fucked functionality: * For base64-encoding, use of the context results in output that is broken * into 64-character lines; however, EVP_EncodeBlock() output is not broken. * For base64-decoding, use of the context returns the correct length of the * resulting output; however, EVP_DecodeBlock() returns a length that may * be up to two characters too long. * Finally, data base64-encoded via a context has to be decoded via a context, * and data base64-encoded w/o a context has to be decoded w/o a context. * So fuck it, I wrote my own. :-P */ /***************************************************************************** * Constants *****************************************************************************/ #define BASE64_MAGIC 0xDEADBEEF #define BASE64_ERR 0xFF #define BASE64_IGN 0xFE #define BASE64_PAD 0xFD #define BASE64_PAD_CHAR '=' /***************************************************************************** * Static Variables *****************************************************************************/ static const unsigned char bin2asc[] = \ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; static const unsigned char asc2bin[256] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3e, 0xff, 0xff, 0xff, 0x3f, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; /***************************************************************************** * Extern Functions *****************************************************************************/ int base64_init (base64_ctx *x) { assert (x != NULL); x->num = 0; x->pad = 0; assert (x->magic = BASE64_MAGIC); assert (!(x->finalized = 0)); return (0); } int base64_encode_update (base64_ctx *x, void *vdst, int *dstlen, const void *vsrc, int srclen) { int n; int num_read; int num_write; unsigned char *dst = (unsigned char *) vdst; unsigned char *src = (unsigned char *) vsrc; assert (x != NULL); assert (x->magic == BASE64_MAGIC); assert (x->finalized != 1); assert (dst != NULL); assert (dstlen != NULL); assert (src != NULL); num_write = 0; if (srclen <= 0) { return (0); } /* Encode leftover data if context buffer can be filled. */ if ((x->num > 0) && (srclen >= (num_read = 3 - x->num))) { memcpy (&x->buf[x->num], src, num_read); src += num_read; srclen -= num_read; base64_encode_block (dst, &n, x->buf, 3); x->num = 0; dst += n; num_write += n; } /* Encode maximum amount of data w/o requiring a pad. */ if (srclen >= 3) { num_read = (srclen / 3) * 3; base64_encode_block (dst, &n, src, num_read); src += num_read; srclen -= num_read; num_write += n; } /* Save leftover data for the next update() or final(). */ if (srclen > 0) { memcpy (&x->buf[x->num], src, srclen); x->num += srclen; } *dstlen = num_write; return (0); } int base64_encode_final (base64_ctx *x, void *dst, int *dstlen) { assert (x != NULL); assert (x->magic == BASE64_MAGIC); assert (x->finalized != 1); assert (dst != NULL); assert (dstlen != NULL); /* Encode leftover data from the previous update(). */ if (x->num > 0) { base64_encode_block (dst, dstlen, x->buf, x->num); x->num = 0; } else { *dstlen = 0; } assert (x->finalized = 1); return (0); } int base64_decode_update (base64_ctx *x, void *dst, int *dstlen, const void *src, int srclen) { /* Context [x] should only be NULL when called via base64_decode_block(). */ int i = 0; int err = 0; int pad = 0; unsigned char *pdst; const unsigned char *psrc; const unsigned char *psrc_last; unsigned char c; assert ((x == NULL) || (x->magic == BASE64_MAGIC)); assert ((x == NULL) || (x->finalized != 1)); assert (dst != NULL); assert (dstlen != NULL); assert (src != NULL); pdst = dst; psrc = src; psrc_last = psrc + srclen; /* Restore context. */ if (x != NULL) { i = x->num; pad = x->pad; *pdst = x->buf[0]; } while (psrc < psrc_last) { c = asc2bin[*psrc++]; if (c == BASE64_IGN) { continue; } if ((c == BASE64_PAD) && (pad < 2)) { pad++; continue; } if ((c == BASE64_ERR) || (pad > 0)) { err++; break; } switch (i) { case 0: *pdst = (c << 2) & 0xfc; break; case 1: *pdst++ |= (c >> 4) & 0x03; *pdst = (c << 4) & 0xf0; break; case 2: *pdst++ |= (c >> 2) & 0x0f; *pdst = (c << 6) & 0xc0; break; case 3: *pdst++ |= (c ) & 0x3f; break; } i = (i + 1) % 4; } /* Save context. */ if (x != NULL) { x->num = i; x->pad = pad; x->buf[0] = *pdst; } /* Check for the correct amount of padding. */ else if (!err) { err = (((i + pad) % 4) != 0); } *pdst = '\0'; *dstlen = pdst - (unsigned char *) dst; return (err ? -1 : 0); } int base64_decode_final (base64_ctx *x, void *dst, int *dstlen) { int rc = 0; assert (x != NULL); assert (x->magic == BASE64_MAGIC); assert (x->finalized != 1); if (((x->num + x->pad) % 4) != 0) { rc = -1; } *dstlen = 0; assert (x->finalized = 1); return (rc); } int base64_cleanup (base64_ctx *x) { assert (x != NULL); assert (x->magic == BASE64_MAGIC); memset (x, 0, sizeof (*x)); assert (x->magic = ~BASE64_MAGIC); return (0); } int base64_encode_block (void *dst, int *dstlen, const void *src, int srclen) { unsigned char *pdst; const unsigned char *psrc; int n; pdst = dst; psrc = src; n = 0; while (srclen >= 3) { *pdst++ = bin2asc[ (psrc[0] >> 2) & 0x3f]; *pdst++ = bin2asc[((psrc[0] << 4) & 0x30) | ((psrc[1] >> 4) & 0x0f)]; *pdst++ = bin2asc[((psrc[1] << 2) & 0x3c) | ((psrc[2] >> 6) & 0x03)]; *pdst++ = bin2asc[ (psrc[2] ) & 0x3f]; psrc += 3; srclen -= 3; n += 4; } if (srclen == 2) { *pdst++ = bin2asc[ (psrc[0] >> 2) & 0x3f]; *pdst++ = bin2asc[((psrc[0] << 4) & 0x30) | ((psrc[1] >> 4) & 0x0f)]; *pdst++ = bin2asc[ (psrc[1] << 2) & 0x3c]; *pdst++ = '='; n += 4; } else if (srclen == 1) { *pdst++ = bin2asc[ (psrc[0] >> 2) & 0x3f]; *pdst++ = bin2asc[ (psrc[0] << 4) & 0x30]; *pdst++ = '='; *pdst++ = '='; n += 4; } *pdst = '\0'; *dstlen = n; return (0); } int base64_decode_block (void *dst, int *dstlen, const void *src, int srclen) { return (base64_decode_update (NULL, dst, dstlen, src, srclen)); } int base64_encode_length (int srclen) { /* When encoding, 3 bytes are encoded into 4 characters. * Add 2 bytes to ensure a partial 3-byte chunk will be accounted for * during integer division, then add 1 byte for the terminating NUL. */ return (((srclen + 2) / 3) * 4) + 1; } int base64_decode_length (int srclen) { /* When decoding, 4 characters are decoded into 3 bytes. * Add 3 bytes to ensure a partial 4-byte chunk will be accounted for * during integer division, then add 1 byte for the terminating NUL. */ return (((srclen + 3) / 4) * 3) + 1; } /***************************************************************************** * Table Initialization Routines *****************************************************************************/ #ifdef BASE64_INIT #include #include #include #define BASE64_DEF_COLS 12 void base64_build_table (unsigned char *data, int len); void base64_print_table (unsigned char *data, int len, char *name, int col); int main (int argc, char *argv[]) { int col; unsigned char a2b[256]; col = (argc > 1) ? atoi (argv[1]) : BASE64_DEF_COLS; base64_build_table (a2b, sizeof (a2b)); base64_print_table (a2b, sizeof (a2b), "asc2bin", col); exit (EXIT_SUCCESS); } void base64_build_table (unsigned char *data, int len) { int i; for (i = 0; i < len; i++) data[i] = (isspace (i)) ? BASE64_IGN : BASE64_ERR; for (i = strlen (bin2asc) - 1; i >= 0; i--) data[bin2asc[i]] = i; data[BASE64_PAD_CHAR] = BASE64_PAD; return; } void base64_print_table (unsigned char *data, int len, char *name, int col) { int i; int n; if (col < 1) { col = BASE64_DEF_COLS; } printf ("static const unsigned char %s[%d] = {", name, len); for (i=0, n=len-1; ; i++) { if ((i % col) == 0) printf ("\n "); printf ("0x%02x", data[i]); if (i == n) break; printf (", "); } printf ("\n};\n"); return; } #endif /* BASE64_INIT */ munge-munge-0.5.15/src/munged/base64.h000066400000000000000000000114571425467526100173550ustar00rootroot00000000000000/***************************************************************************** * Written by Chris Dunlap . * Copyright (C) 2007-2022 Lawrence Livermore National Security, LLC. * Copyright (C) 2002-2007 The Regents of the University of California. * UCRL-CODE-155910. * * This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE). * For details, see . * * MUNGE 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. Additionally for the MUNGE library (libmunge), you * can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation, * either version 3 of the License, or (at your option) any later version. * * MUNGE 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 * and GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * and GNU Lesser General Public License along with MUNGE. If not, see * . *****************************************************************************/ #ifndef BASE64_H #define BASE64_H #if HAVE_CONFIG_H # include #endif /* HAVE_CONFIG_H */ /***************************************************************************** * Data Types *****************************************************************************/ typedef struct { unsigned char buf[3]; int num; int pad; #ifndef NDEBUG int magic; int finalized; #endif /* !NDEBUG */ } base64_ctx; /***************************************************************************** * Prototypes *****************************************************************************/ int base64_init (base64_ctx *x); /* * Initializes the base64 context [x] for base64 encoding/decoding of data. * Returns 0 on success, or -1 on error. */ int base64_encode_update (base64_ctx *x, void *dst, int *dstlen, const void *src, int srclen); /* * Updates the base64 context [x], encoding [srclen] bytes from [src] * into [dst], and setting [dstlen] to the number of bytes written. * This can be called multiple times to process successive blocks of data. * Returns 0 on success, or -1 on error. */ int base64_encode_final (base64_ctx *x, void *dst, int *dstlen); /* * Finalizes the base64 context [x], encoding the "final" data remaining * in a partial block into [dst], and setting [dstlen] to the number of * bytes written. * After calling this function, no further updates should be made to [x] * without re-initializing it first. * Returns 0 on success, or -1 on error. */ int base64_decode_update (base64_ctx *x, void *dst, int *dstlen, const void *src, int srclen); /* * Updates the base64 context [x], decoding [srclen] bytes from [src] * into [dst], and setting [dstlen] to the number of bytes written. * This can be called multiple times to process successive blocks of data. * Returns 0 on success, or -1 on error. */ int base64_decode_final (base64_ctx *x, void *dst, int *dstlen); /* * Finalizes the base64 context [x], decoding the "final" data remaining * in a partial block into [dst], and setting [dstlen] to the number of * bytes written. * After calling this function, no further updates should be made to [x] * without re-initializing it first. * Returns 0 on success, or -1 on error. */ int base64_cleanup (base64_ctx *x); /* * Clears the base64 context [x]. * Returns 0 on success, or -1 on error. */ int base64_encode_block (void *dst, int *dstlen, const void *src, int srclen); /* * Base64-encodes [srclen] bytes from the contiguous [src] into [dst], * and sets [dstlen] to the number of bytes written. * Returns 0 on success, or -1 on error. */ int base64_decode_block (void *dst, int *dstlen, const void *src, int srclen); /* * Base64-decodes [srclen] bytes from the contiguous [src] into [dst], * and sets [dstlen] to the number of bytes written. * Returns 0 on success, or -1 on error. */ int base64_encode_length (int srclen); /* * Returns the size (in bytes) of the destination memory block required * for base64 encoding a block of [srclen] bytes. */ int base64_decode_length (int srclen); /* * Returns the size (in bytes) of the destination memory block required * for base64 decoding a block of [srclen] bytes. */ #endif /* !BASE64_H */ munge-munge-0.5.15/src/munged/base64_test.c000066400000000000000000000117121425467526100204010ustar00rootroot00000000000000/***************************************************************************** * Written by Chris Dunlap . * Copyright (C) 2007-2022 Lawrence Livermore National Security, LLC. * Copyright (C) 2002-2007 The Regents of the University of California. * UCRL-CODE-155910. * * This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE). * For details, see . * * MUNGE 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. Additionally for the MUNGE library (libmunge), you * can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation, * either version 3 of the License, or (at your option) any later version. * * MUNGE 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 * and GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * and GNU Lesser General Public License along with MUNGE. If not, see * . *****************************************************************************/ #include #include #include #include "base64.h" #include "tap.h" /***************************************************************************** * Test cases from RFC 2440 (OpenPGP Message Format) * Section 6.5 (Examples of Radix-64). *****************************************************************************/ int validate (const char *dst, const void *src, int srclen); int encode_block (char *dst, int *dstlen, const void *src, int srclen); int encode_context (char *dst, int *dstlen, const void *src, int srclen); int decode_block (char *dst, int *dstlen, const void *src, int srclen); int decode_context (char *dst, int *dstlen, const void *src, int srclen); int main (int argc, char *argv[]) { const unsigned char src1[] = { 0x14, 0xfb, 0x9c, 0x03, 0xd9, 0x7e }; const unsigned char src2[] = { 0x14, 0xfb, 0x9c, 0x03, 0xd9 }; const unsigned char src3[] = { 0x14, 0xfb, 0x9c, 0x03 }; const char dst1[] = "FPucA9l+"; const char dst2[] = "FPucA9k="; const char dst3[] = "FPucAw=="; plan (3); ok (validate (dst1, src1, sizeof (src1)) == 0, "Input data 0x14fb9c03d97e"); ok (validate (dst2, src2, sizeof (src2)) == 0, "Input data 0x14fb9c03d9"); ok (validate (dst3, src3, sizeof (src3)) == 0, "Input data 0x14fb9c03"); done_testing (); exit (EXIT_SUCCESS); } int validate (const char *dst, const void *src, int srclen) { int n; char buf[9]; if (encode_block (buf, &n, src, srclen) < 0) return (-1); if (n != strlen (dst)) return (-1); if (strncmp (dst, buf, n)) return (-1); if (decode_block (buf, &n, dst, strlen (dst)) < 0) return (-1); if (n != srclen) return (-1); if (strncmp (src, buf, n)) return (-1); if (encode_context (buf, &n, src, srclen) < 0) return (-1); if (n != strlen (dst)) return (-1); if (strncmp (dst, buf, n)) return (-1); if (decode_context (buf, &n, dst, strlen (dst)) < 0) return (-1); if (n != srclen) return (-1); if (strncmp (src, buf, n)) return (-1); return (0); } int encode_block (char *dst, int *dstlen, const void *src, int srclen) { return (base64_encode_block (dst, dstlen, src, srclen)); } int encode_context (char *dst, int *dstlen, const void *src, int srclen) { base64_ctx x; int i; int n; int m; const unsigned char *p = src; if (base64_init (&x) < 0) return (-1); for (i = 0, n = 0; i < srclen; i++) { if (base64_encode_update (&x, dst, &m, p + i, 1) < 0) return (-1); dst += m; n += m; } if (base64_encode_final (&x, dst, &m) < 0) return (-1); if (base64_cleanup (&x) < 0) return (-1); n += m; *dstlen = n; return (0); } int decode_block (char *dst, int *dstlen, const void *src, int srclen) { return (base64_decode_block (dst, dstlen, src, srclen)); } int decode_context (char *dst, int *dstlen, const void *src, int srclen) { base64_ctx x; int i; int n; int m; const unsigned char *p = src; if (base64_init (&x) < 0) return (-1); for (i = 0, n = 0; i < srclen; i++) { if (base64_decode_update (&x, dst, &m, p + i, 1) < 0) return (-1); dst += m; n += m; } if (base64_decode_final (&x, dst, &m) < 0) return (-1); if (base64_cleanup (&x) < 0) return (-1); n += m; *dstlen = n; return (0); } munge-munge-0.5.15/src/munged/cipher.c000066400000000000000000000447501425467526100175400ustar00rootroot00000000000000/***************************************************************************** * Written by Chris Dunlap . * Copyright (C) 2007-2022 Lawrence Livermore National Security, LLC. * Copyright (C) 2002-2007 The Regents of the University of California. * UCRL-CODE-155910. * * This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE). * For details, see . * * MUNGE 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. Additionally for the MUNGE library (libmunge), you * can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation, * either version 3 of the License, or (at your option) any later version. * * MUNGE 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 * and GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * and GNU Lesser General Public License along with MUNGE. If not, see * . *****************************************************************************/ #if HAVE_CONFIG_H # include #endif /* HAVE_CONFIG_H */ #include #include #include #include "cipher.h" /***************************************************************************** * Private Data *****************************************************************************/ static int _cipher_is_initialized = 0; /***************************************************************************** * Private Prototypes *****************************************************************************/ static void _cipher_init_subsystem (void); static int _cipher_init (cipher_ctx *x, munge_cipher_t cipher, unsigned char *key, unsigned char *iv, int enc); static int _cipher_update (cipher_ctx *x, void *dst, int *dstlenp, const void *src, int srclen); static int _cipher_final (cipher_ctx *x, void *dst, int *dstlenp); static int _cipher_cleanup (cipher_ctx *x); static int _cipher_block_size (munge_cipher_t cipher); static int _cipher_iv_size (munge_cipher_t cipher); static int _cipher_key_size (munge_cipher_t cipher); static int _cipher_map_enum (munge_cipher_t cipher, void *dst); /***************************************************************************** * Public Functions *****************************************************************************/ void cipher_init_subsystem (void) { /* Note that this call is *NOT* thread-safe. */ if (! _cipher_is_initialized) { _cipher_init_subsystem (); _cipher_is_initialized++; } return; } int cipher_init (cipher_ctx *x, munge_cipher_t cipher, unsigned char *key, unsigned char *iv, int enc) { int rc; assert (_cipher_is_initialized); if (!x || !key || !iv || !((enc == CIPHER_DECRYPT) || (enc == CIPHER_ENCRYPT))) { return (-1); } rc = _cipher_init (x, cipher, key, iv, enc); return (rc); } int cipher_update (cipher_ctx *x, void *dst, int *dstlenp, const void *src, int srclen) { int rc; assert (_cipher_is_initialized); if (!x || !dst || !dstlenp || (*dstlenp < 0) || !src || (srclen < 0)) { return (-1); } rc = _cipher_update (x, dst, dstlenp, src, srclen); return (rc); } int cipher_final (cipher_ctx *x, void *dst, int *dstlenp) { int rc; assert (_cipher_is_initialized); if (!x || !dst || !dstlenp || (*dstlenp < 0)) { return (-1); } rc = _cipher_final (x, dst, dstlenp); return (rc); } int cipher_cleanup (cipher_ctx *x) { int rc; assert (_cipher_is_initialized); if (!x) { return (-1); } rc = _cipher_cleanup (x); memset (x, 0, sizeof (*x)); return (rc); } int cipher_block_size (munge_cipher_t cipher) { assert (_cipher_is_initialized); return (_cipher_block_size (cipher)); } int cipher_iv_size (munge_cipher_t cipher) { assert (_cipher_is_initialized); return (_cipher_iv_size (cipher)); } int cipher_key_size (munge_cipher_t cipher) { assert (_cipher_is_initialized); return (_cipher_key_size (cipher)); } int cipher_map_enum (munge_cipher_t cipher, void *dst) { assert (_cipher_is_initialized); return (_cipher_map_enum (cipher, dst)); } /***************************************************************************** * Private Functions (Libgcrypt) *****************************************************************************/ #if HAVE_LIBGCRYPT #include #include #include "common.h" #include "log.h" static int _cipher_map [MUNGE_CIPHER_LAST_ITEM]; static int _cipher_update_aux (cipher_ctx *x, void *dst, int *dstlenp, const void *src, int srclen); void _cipher_init_subsystem (void) { int i; for (i = 0; i < MUNGE_CIPHER_LAST_ITEM; i++) { _cipher_map [i] = -1; } _cipher_map [MUNGE_CIPHER_BLOWFISH] = GCRY_CIPHER_BLOWFISH; _cipher_map [MUNGE_CIPHER_CAST5] = GCRY_CIPHER_CAST5; _cipher_map [MUNGE_CIPHER_AES128] = GCRY_CIPHER_AES128; _cipher_map [MUNGE_CIPHER_AES256] = GCRY_CIPHER_AES256; return; } static int _cipher_init (cipher_ctx *x, munge_cipher_t cipher, unsigned char *key, unsigned char *iv, int enc) { gcry_error_t e; int algo; size_t nbytes; if (_cipher_map_enum (cipher, &algo) < 0) { return (-1); } e = gcry_cipher_open (&(x->ctx), algo, GCRY_CIPHER_MODE_CBC, 0); if (e != 0) { log_msg (LOG_DEBUG, "gcry_cipher_open failed for cipher=%d: %s", cipher, gcry_strerror (e)); return (-1); } e = gcry_cipher_algo_info (algo, GCRYCTL_GET_KEYLEN, NULL, &nbytes); if (e != 0) { log_msg (LOG_DEBUG, "gcry_cipher_algo_info failed for cipher=%d key length: %s", cipher, gcry_strerror (e)); return (-1); } e = gcry_cipher_setkey (x->ctx, key, nbytes); if (e != 0) { log_msg (LOG_DEBUG, "gcry_cipher_setkey failed for cipher=%d: %s", cipher, gcry_strerror (e)); return (-1); } e = gcry_cipher_algo_info (algo, GCRYCTL_GET_BLKLEN, NULL, &nbytes); if (e != 0) { log_msg (LOG_DEBUG, "gcry_cipher_algo_info failed for cipher=%d block length: %s", cipher, gcry_strerror (e)); return (-1); } e = gcry_cipher_setiv (x->ctx, iv, nbytes); if (e != 0) { log_msg (LOG_DEBUG, "gcry_cipher_setiv failed for cipher=%d: %s", cipher, gcry_strerror (e)); return (-1); } x->do_encrypt = enc; x->len = 0; x->blklen = (int) nbytes; return (0); } static int _cipher_update (cipher_ctx *x, void *vdst, int *dstlenp, const void *vsrc, int srclen) { /* During encryption, any remaining src data that is not a multiple of the * cipher block size is saved in the context's partial block buffer. * This buffer will be padded when the encryption is finalized * (see PKCS #5, rfc2898). * During decryption, the partial block buffer will always contain data at * the end of each update to ensure the padding is properly removed when * the decryption is finalized. */ int n; int n_written; int n_partial; int n_complete; unsigned char *dst = vdst; unsigned char *src = (void *) vsrc; n_written = 0; /* * Continue processing a partial block if one exists. */ if (x->len > 0) { assert (x->len < x->blklen); n_partial = MIN (srclen, x->blklen - x->len); memcpy (&(x->buf[x->len]), src, n_partial); x->len += n_partial; src += n_partial; srclen -= n_partial; /* If the partial block buffer is full, process the block unless * decryption is being performed and there is no more data. * This exception is to ensure _cipher_final() is able to * validate & remove the PKCS #5 padding. */ if (x->len == x->blklen) { if ((x->do_encrypt) || (srclen > 0)) { n = *dstlenp; if (_cipher_update_aux (x, dst, &n, x->buf, x->blklen) < 0) { goto err; } assert (n == x->blklen); dst += n; n_written += n; x->len = 0; } } } /* Compute the number of bytes for complete blocks, and the remainder * that will be saved in the partial block buffer. During decryption, * the partial block buffer will always contain data to ensure * _cipher_final() is able to validate & remove the PKCS #5 padding. */ n_partial = srclen % x->blklen; if ((!x->do_encrypt) && (n_partial == 0)) { n_partial = x->blklen; } n_complete = srclen - n_partial; /* Process complete blocks. */ if (n_complete > 0) { assert (x->len == 0); assert (n_complete % x->blklen == 0); n = *dstlenp - n_written; if (_cipher_update_aux (x, dst, &n, src, n_complete) < 0) { goto err; } assert (n == n_complete); src += n; srclen -= n; n_written += n; } /* Copy src leftovers to the partial block buf. */ if (n_partial > 0) { assert (x->len == 0); assert (n_partial <= x->blklen); memcpy (x->buf, src, n_partial); x->len = n_partial; } /* Ensure the partial block buffer is never empty during decryption. */ assert ((x->do_encrypt) || (x->len > 0)); /* Set the number of bytes written. */ *dstlenp = n_written; return (0); err: *dstlenp = 0; return (-1); } static int _cipher_update_aux (cipher_ctx *x, void *dst, int *dstlenp, const void *src, int srclen) { gcry_error_t e; int dstlen = *dstlenp; if (x->do_encrypt) { e = gcry_cipher_encrypt (x->ctx, dst, dstlen, src, srclen); } else { e = gcry_cipher_decrypt (x->ctx, dst, dstlen, src, srclen); } if (e != 0) { log_msg (LOG_DEBUG, "%s failed: %s", (x->do_encrypt ? "gcry_cipher_encrypt" : "gcry_cipher_decrypt"), gcry_strerror (e)); *dstlenp = 0; return (-1); } if ((src != NULL) || (srclen != 0)) { *dstlenp = srclen; } return (0); } static int _cipher_final (cipher_ctx *x, void *dst, int *dstlenp) { int n; int i; int pad; if (x->do_encrypt) { assert (x->len < x->blklen); pad = x->blklen - x->len; for (i = x->len; i < x->blklen; i++) { x->buf[i] = pad; } if (_cipher_update_aux (x, dst, dstlenp, x->buf, x->blklen) < 0) { return (-1); } } else { /* Final cipher block should always be full due to padding. */ if (x->len != x->blklen) { log_msg (LOG_DEBUG, "Final decryption block has only %d of %d bytes", x->len, x->blklen); return (-1); } /* Perform in-place decryption of final cipher block. */ n = x->blklen; if (_cipher_update_aux (x, x->buf, &n, NULL, 0) < 0) { return (-1); } assert (n == x->blklen); /* * Validate PKCS #5 block padding. */ pad = x->buf[x->blklen - 1]; if ((pad <= 0) || (pad > x->blklen)) { log_msg (LOG_DEBUG, "Final decryption block has invalid pad of %d", pad); return (-1); } for (i = x->blklen - pad; i < x->blklen; i++) { if (x->buf[i] != pad) { log_msg (LOG_DEBUG, "Final decryption block has padding error at byte %d", i); return (-1); } } /* Copy decrypted plaintext to dst. */ n = x->blklen - pad; if (n > 0) { if (*dstlenp < n) { return (-1); } memcpy (dst, x->buf, n); } *dstlenp = n; } return (0); } static int _cipher_cleanup (cipher_ctx *x) { gcry_cipher_close (x->ctx); return (0); } static int _cipher_block_size (munge_cipher_t cipher) { gcry_error_t e; int algo; size_t nbytes; if (_cipher_map_enum (cipher, &algo) < 0) { return (-1); } e = gcry_cipher_algo_info (algo, GCRYCTL_GET_BLKLEN, NULL, &nbytes); if (e != 0) { log_msg (LOG_DEBUG, "gcry_cipher_algo_info failed for cipher=%d block length: %s", cipher, gcry_strerror (e)); return (-1); } return (nbytes); } static int _cipher_iv_size (munge_cipher_t cipher) { return (_cipher_block_size (cipher)); } static int _cipher_key_size (munge_cipher_t cipher) { gcry_error_t e; int algo; size_t nbytes; if (_cipher_map_enum (cipher, &algo) < 0) { return (-1); } e = gcry_cipher_algo_info (algo, GCRYCTL_GET_KEYLEN, NULL, &nbytes); if (e != 0) { log_msg (LOG_DEBUG, "gcry_cipher_algo_info failed for cipher=%d key length: %s", cipher, gcry_strerror (e)); return (-1); } return (nbytes); } static int _cipher_map_enum (munge_cipher_t cipher, void *dst) { int algo = -1; if ((cipher > MUNGE_CIPHER_DEFAULT) && (cipher < MUNGE_CIPHER_LAST_ITEM)) { algo = _cipher_map [cipher]; } if (algo < 0) { return (-1); } if (dst != NULL) { * (int *) dst = algo; } return (0); } #endif /* HAVE_LIBGCRYPT */ /***************************************************************************** * Private Functions (OpenSSL) *****************************************************************************/ #if HAVE_OPENSSL #include #include static const EVP_CIPHER *_cipher_map [MUNGE_CIPHER_LAST_ITEM]; void _cipher_init_subsystem (void) { int i; for (i = 0; i < MUNGE_CIPHER_LAST_ITEM; i++) { _cipher_map [i] = NULL; } _cipher_map [MUNGE_CIPHER_BLOWFISH] = EVP_bf_cbc (); _cipher_map [MUNGE_CIPHER_CAST5] = EVP_cast5_cbc (); #if HAVE_EVP_AES_128_CBC _cipher_map [MUNGE_CIPHER_AES128] = EVP_aes_128_cbc (); #endif /* HAVE_EVP_AES_128_CBC */ #if HAVE_EVP_AES_256_CBC && HAVE_EVP_SHA256 _cipher_map [MUNGE_CIPHER_AES256] = EVP_aes_256_cbc (); #endif /* HAVE_EVP_AES_256_CBC && HAVE_EVP_SHA256 */ return; } static int _cipher_init (cipher_ctx *x, munge_cipher_t cipher, unsigned char *key, unsigned char *iv, int enc) { EVP_CIPHER *algo; if (_cipher_map_enum (cipher, &algo) < 0) { return (-1); } #if HAVE_EVP_CIPHER_CTX_NEW /* OpenSSL >= 0.9.8b */ x->ctx = EVP_CIPHER_CTX_new (); #else /* !HAVE_EVP_CIPHER_CTX_NEW */ x->ctx = OPENSSL_malloc (sizeof (EVP_CIPHER_CTX)); #endif /* !HAVE_EVP_CIPHER_CTX_NEW */ if (x->ctx == NULL) { return (-1); } #if HAVE_EVP_CIPHERINIT_EX #if HAVE_EVP_CIPHER_CTX_INIT /* OpenSSL >= 0.9.7, < 1.1.0 */ EVP_CIPHER_CTX_init (x->ctx); #endif /* HAVE_EVP_CIPHER_CTX_INIT */ /* OpenSSL >= 0.9.7 */ if (EVP_CipherInit_ex (x->ctx, algo, NULL, key, iv, enc) != 1) { return (-1); } #elif HAVE_EVP_CIPHERINIT_RETURN_INT /* EVP_CipherInit() implicitly initializes the EVP_CIPHER_CTX. */ /* OpenSSL > 0.9.5a */ if (EVP_CipherInit (x->ctx, algo, key, iv, enc) != 1) { return (-1); } #elif HAVE_EVP_CIPHERINIT /* EVP_CipherInit() implicitly initializes the EVP_CIPHER_CTX. */ /* OpenSSL <= 0.9.5a */ EVP_CipherInit (x->ctx, algo, key, iv, enc); #else /* !HAVE_EVP_CIPHERINIT */ #error "No OpenSSL EVP_CipherInit" #endif /* !HAVE_EVP_CIPHERINIT */ return (0); } static int _cipher_update (cipher_ctx *x, void *dst, int *dstlenp, const void *src, int srclen) { #if HAVE_EVP_CIPHERUPDATE_RETURN_INT /* OpenSSL > 0.9.5a */ if (EVP_CipherUpdate (x->ctx, dst, dstlenp, (void *) src, srclen) != 1) { return (-1); } #elif HAVE_EVP_CIPHERUPDATE /* OpenSSL <= 0.9.5a */ EVP_CipherUpdate (x->ctx, dst, dstlenp, (void *) src, srclen); #else /* !HAVE_EVP_CIPHERUPDATE */ #error "No OpenSSL EVP_CipherUpdate" #endif /* !HAVE_EVP_CIPHERUPDATE */ return (0); } static int _cipher_final (cipher_ctx *x, void *dst, int *dstlenp) { #if HAVE_EVP_CIPHERFINAL_EX /* OpenSSL >= 0.9.7 */ if (EVP_CipherFinal_ex (x->ctx, dst, dstlenp) != 1) { return (-1); } #elif HAVE_EVP_CIPHERFINAL if (EVP_CipherFinal (x->ctx, dst, dstlenp) != 1) { return (-1); } #else /* !HAVE_EVP_CIPHERFINAL */ #error "No OpenSSL EVP_CipherFinal" #endif /* !HAVE_EVP_CIPHERFINAL */ return (0); } static int _cipher_cleanup (cipher_ctx *x) { int rv = 0; #if HAVE_EVP_CIPHER_CTX_FREE /* OpenSSL >= 0.9.8b */ EVP_CIPHER_CTX_free (x->ctx); #else /* !HAVE_EVP_CIPHER_CTX_FREE */ #if HAVE_EVP_CIPHER_CTX_CLEANUP_RETURN_INT /* OpenSSL > 0.9.5a, < 1.1.0 */ if (EVP_CIPHER_CTX_cleanup (x->ctx) != 1) { rv = -1; } #elif HAVE_EVP_CIPHER_CTX_CLEANUP /* OpenSSL <= 0.9.5a */ EVP_CIPHER_CTX_cleanup (x->ctx); #endif /* HAVE_EVP_CIPHER_CTX_CLEANUP */ OPENSSL_free (x->ctx); #endif /* !HAVE_EVP_CIPHER_CTX_FREE */ x->ctx = NULL; return (rv); } static int _cipher_block_size (munge_cipher_t cipher) { EVP_CIPHER *algo; if (_cipher_map_enum (cipher, &algo) < 0) { return (-1); } return (EVP_CIPHER_block_size (algo)); } static int _cipher_iv_size (munge_cipher_t cipher) { EVP_CIPHER *algo; if (_cipher_map_enum (cipher, &algo) < 0) { return (-1); } return (EVP_CIPHER_iv_length (algo)); } static int _cipher_key_size (munge_cipher_t cipher) { EVP_CIPHER *algo; if (_cipher_map_enum (cipher, &algo) < 0) { return (-1); } return (EVP_CIPHER_key_length (algo)); } static int _cipher_map_enum (munge_cipher_t cipher, void *dst) { const EVP_CIPHER *algo = NULL; if ((cipher > MUNGE_CIPHER_DEFAULT) && (cipher < MUNGE_CIPHER_LAST_ITEM)) { algo = _cipher_map [cipher]; } if (algo == NULL) { return (-1); } if (dst != NULL) { * (const EVP_CIPHER **) dst = algo; } return (0); } #endif /* HAVE_OPENSSL */ munge-munge-0.5.15/src/munged/cipher.h000066400000000000000000000117711425467526100175420ustar00rootroot00000000000000/***************************************************************************** * Written by Chris Dunlap . * Copyright (C) 2007-2022 Lawrence Livermore National Security, LLC. * Copyright (C) 2002-2007 The Regents of the University of California. * UCRL-CODE-155910. * * This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE). * For details, see . * * MUNGE 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. Additionally for the MUNGE library (libmunge), you * can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation, * either version 3 of the License, or (at your option) any later version. * * MUNGE 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 * and GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * and GNU Lesser General Public License along with MUNGE. If not, see * . *****************************************************************************/ #ifndef CIPHER_H #define CIPHER_H #if HAVE_CONFIG_H # include #endif /* HAVE_CONFIG_H */ #include #include "munge_defs.h" /***************************************************************************** * Data Types *****************************************************************************/ #if HAVE_LIBGCRYPT #include typedef struct { gcry_cipher_hd_t ctx; int do_encrypt; int len; int blklen; unsigned char buf [MUNGE_MAXIMUM_BLK_LEN]; } cipher_ctx; #endif /* HAVE_LIBGCRYPT */ #if HAVE_OPENSSL #include typedef struct { EVP_CIPHER_CTX *ctx; } cipher_ctx; #endif /* HAVE_OPENSSL */ enum { CIPHER_DECRYPT = 0, CIPHER_ENCRYPT = 1 }; /***************************************************************************** * Prototypes *****************************************************************************/ void cipher_init_subsystem (void); /* * Initializes the cipher subsystem. * WARNING: This routine is *NOT* guaranteed to be thread-safe. */ int cipher_init (cipher_ctx *x, munge_cipher_t cipher, unsigned char *key, unsigned char *iv, int enc); /* * Initializes the cipher context [x] with cipher [cipher], * symmetric key [key], and initialization vector [iv]. * The [enc] parm is set to 1 for encryption, and 0 for decryption. * Returns 0 on success, or -1 on error. */ int cipher_update (cipher_ctx *x, void *dst, int *dstlenp, const void *src, int srclen); /* * Updates the cipher context [x], reading [srclen] bytes from [src] and * writing the result into [dst] of length [dstlenp]. This can be called * multiple times to process successive blocks of data. * The number of bytes written will be from 0 to (srclen + cipher_block_size) * depending on the cipher block alignment. * Returns 0 on success, or -1 on error; in addition, [dstlenp] will be set * to the number of bytes written to [dst]. */ int cipher_final (cipher_ctx *x, void *dst, int *dstlenp); /* * Finalizes the cipher context [x], processing the "final" data * remaining in a partial block and writing the result into [dst] of * length [dstlen]. * The number of bytes written will be at most cipher_block_size() bytes * depending on the cipher block alignment. * After this function, no further calls to cipher_update() should be made. * Returns 0 on success, or -1 on error; in addition, [dstlenp] will be set * to the number of bytes written to [dst]. */ int cipher_cleanup (cipher_ctx *x); /* * Clears the cipher context [x]. * Returns 0 on success, or -1 on error. */ int cipher_block_size (munge_cipher_t cipher); /* * Returns the block size (in bytes) of the cipher [cipher], or -1 on error. */ int cipher_iv_size (munge_cipher_t cipher); /* * Returns the initialization vector length (in bytes) of the cipher [cipher], * 0 if the cipher does not use an IV, or -1 on error. */ int cipher_key_size (munge_cipher_t cipher); /* * Returns the key length (in bytes) of the cipher [cipher], or -1 on error. */ int cipher_map_enum (munge_cipher_t cipher, void *dst); /* * Map the specified [cipher] algorithm to the internal representation used * by the underlying cryptographic library. * If [dst] is non-NULL, write the cryptographic library's internal * representation of the cipher algorithm to [dst]; otherwise, just validate * the specified [cipher] algorithm. * Returns 0 on success, or -1 on error. */ #endif /* !CIPHER_H */ munge-munge-0.5.15/src/munged/clock.c000066400000000000000000000060611425467526100173520ustar00rootroot00000000000000/***************************************************************************** * Written by Chris Dunlap . * Copyright (C) 2007-2022 Lawrence Livermore National Security, LLC. * Copyright (C) 2002-2007 The Regents of the University of California. * UCRL-CODE-155910. * * This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE). * For details, see . * * MUNGE 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. Additionally for the MUNGE library (libmunge), you * can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation, * either version 3 of the License, or (at your option) any later version. * * MUNGE 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 * and GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * and GNU Lesser General Public License along with MUNGE. If not, see * . *****************************************************************************/ #if HAVE_CONFIG_H # include #endif /* HAVE_CONFIG_H */ #include #include #include "clock.h" /* Set timespec [tsp] to the current time adjusted forward by * [msecs] milliseconds. * Return 0 on success, or -1 on error (with errno set). */ int clock_get_timespec (struct timespec *tsp, long msecs) { int rv; if (tsp == NULL) { errno = EINVAL; return -1; } rv = clock_gettime (CLOCK_REALTIME, tsp); if (rv < 0) { return -1; } if (msecs > 0) { tsp->tv_sec += msecs / 1000; tsp->tv_nsec += (msecs % 1000) * 1000 * 1000; if (tsp->tv_nsec >= 1000 * 1000 * 1000) { tsp->tv_sec += tsp->tv_nsec / (1000 * 1000 * 1000); tsp->tv_nsec %= 1000 * 1000 * 1000; } } return 0; } /* Return 1 if timespec [tsp0] <= [tsp1], 0 if not, or -1 on error. */ int clock_is_timespec_le (const struct timespec *tsp0, const struct timespec *tsp1) { if ((tsp0 == NULL) || (tsp1 == NULL)) { errno = EINVAL; return -1; } if (tsp0->tv_sec == tsp1->tv_sec) { return (tsp0->tv_nsec <= tsp1->tv_nsec); } else { return (tsp0->tv_sec <= tsp1->tv_sec); } } /* Return 1 if timespec [tsp] <= the current time, 0 if not, or -1 on error. */ int clock_is_timespec_expired (const struct timespec *tsp) { struct timespec now; int rv; if (tsp == NULL) { errno = EINVAL; return -1; } rv = clock_get_timespec (&now, 0); if (rv < 0) { return -1; } rv = clock_is_timespec_le (tsp, &now); return rv; } munge-munge-0.5.15/src/munged/clock.h000066400000000000000000000034731425467526100173630ustar00rootroot00000000000000/***************************************************************************** * Written by Chris Dunlap . * Copyright (C) 2007-2022 Lawrence Livermore National Security, LLC. * Copyright (C) 2002-2007 The Regents of the University of California. * UCRL-CODE-155910. * * This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE). * For details, see . * * MUNGE 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. Additionally for the MUNGE library (libmunge), you * can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation, * either version 3 of the License, or (at your option) any later version. * * MUNGE 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 * and GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * and GNU Lesser General Public License along with MUNGE. If not, see * . *****************************************************************************/ #ifndef CLOCK_H #define CLOCK_H #if HAVE_CONFIG_H # include #endif /* HAVE_CONFIG_H */ #include int clock_get_timespec (struct timespec *tsp, long msecs); int clock_is_timespec_le ( const struct timespec *tsp0, const struct timespec *tsp1); int clock_is_timespec_expired (const struct timespec *tsp); #endif /* !CLOCK_H */ munge-munge-0.5.15/src/munged/conf.c000066400000000000000000001054471425467526100172140ustar00rootroot00000000000000/***************************************************************************** * Written by Chris Dunlap . * Copyright (C) 2007-2022 Lawrence Livermore National Security, LLC. * Copyright (C) 2002-2007 The Regents of the University of California. * UCRL-CODE-155910. * * This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE). * For details, see . * * MUNGE 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. Additionally for the MUNGE library (libmunge), you * can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation, * either version 3 of the License, or (at your option) any later version. * * MUNGE 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 * and GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * and GNU Lesser General Public License along with MUNGE. If not, see * . *****************************************************************************/ #if HAVE_CONFIG_H # include #endif /* HAVE_CONFIG_H */ #include /* for inet_ntop() */ #include #include #include #include #include #include #include #include /* for AF_INET */ #include #include #include #include #include #include "clock.h" #include "conf.h" #include "license.h" #include "lock.h" #include "log.h" #include "md.h" #include "missing.h" /* for inet_ntop() */ #include "munge_defs.h" #include "net.h" #include "path.h" #include "str.h" #include "version.h" #include "zip.h" /***************************************************************************** * Command-Line Options *****************************************************************************/ #define OPT_ADVICE 256 #define OPT_KEY_FILE 257 #define OPT_NUM_THREADS 258 #define OPT_AUTH_SERVER 259 #define OPT_AUTH_CLIENT 260 #define OPT_GROUP_CHECK 261 #define OPT_GROUP_UPDATE 262 #define OPT_SYSLOG 263 #define OPT_BENCHMARK 264 #define OPT_MAX_TTL 265 #define OPT_PID_FILE 266 #define OPT_LOG_FILE 267 #define OPT_SEED_FILE 268 #define OPT_TRUSTED_GROUP 269 #define OPT_ORIGIN 270 #define OPT_LAST 271 const char * const short_opts = ":hLVfFMsS:v"; #include struct option long_opts[] = { { "help", no_argument, NULL, 'h' }, { "license", no_argument, NULL, 'L' }, { "version", no_argument, NULL, 'V' }, { "force", no_argument, NULL, 'f' }, { "foreground", no_argument, NULL, 'F' }, { "mlockall", no_argument, NULL, 'M' }, { "stop", no_argument, NULL, 's' }, { "socket", required_argument, NULL, 'S' }, { "verbose", no_argument, NULL, 'v' }, { "advice", no_argument, NULL, OPT_ADVICE }, #if defined(AUTH_METHOD_RECVFD_MKFIFO) || defined(AUTH_METHOD_RECVFD_MKNOD) { "auth-server-dir", required_argument, NULL, OPT_AUTH_SERVER }, { "auth-client-dir", required_argument, NULL, OPT_AUTH_CLIENT }, #endif /* AUTH_METHOD_RECVFD_MKFIFO || AUTH_METHOD_RECVFD_MKNOD */ { "benchmark", no_argument, NULL, OPT_BENCHMARK }, { "group-check-mtime", required_argument, NULL, OPT_GROUP_CHECK }, { "group-update-time", required_argument, NULL, OPT_GROUP_UPDATE }, { "key-file", required_argument, NULL, OPT_KEY_FILE }, { "log-file", required_argument, NULL, OPT_LOG_FILE }, { "max-ttl", required_argument, NULL, OPT_MAX_TTL }, { "num-threads", required_argument, NULL, OPT_NUM_THREADS }, { "origin", required_argument, NULL, OPT_ORIGIN }, { "pid-file", required_argument, NULL, OPT_PID_FILE }, { "seed-file", required_argument, NULL, OPT_SEED_FILE }, { "syslog", no_argument, NULL, OPT_SYSLOG }, { "trusted-group", required_argument, NULL, OPT_TRUSTED_GROUP }, { NULL, 0, NULL, 0 } }; /***************************************************************************** * Internal Prototypes *****************************************************************************/ static void _conf_set_cwd (conf_t conf); static void _conf_display_help (char *prog); static void _conf_set_string (char **str_p, const char *val, const char *cwd, const char *dsc); static void _conf_process_stop (conf_t conf); static int _conf_send_signal (pid_t pid, int signum, int msecs); static void _conf_sleep (int msecs); static void _conf_set_origin_addr (conf_t conf); static int _conf_open_keyfile (const char *keyfile, int got_force); /***************************************************************************** * Global Variables *****************************************************************************/ conf_t conf = NULL; /* global configuration struct */ /***************************************************************************** * External Functions *****************************************************************************/ conf_t create_conf (void) { conf_t conf; if (!(conf = malloc (sizeof (struct conf)))) { log_errno (EMUNGE_NO_MEMORY, LOG_ERR, "Failed to allocate conf"); } conf->ld = -1; conf->got_benchmark = 0; conf->got_clock_skew = 1; conf->got_force = 0; conf->got_foreground = 0; conf->got_group_stat = !! MUNGE_GROUP_STAT_FLAG; conf->got_stop = 0; conf->got_mlockall = 0; conf->got_root_auth = !! MUNGE_AUTH_ROOT_ALLOW_FLAG; conf->got_socket_retry = !! MUNGE_SOCKET_RETRY_FLAG; conf->got_syslog = 0; conf->got_verbose = 0; conf->def_cipher = MUNGE_DEFAULT_CIPHER; conf->def_zip = zip_select_default_type (MUNGE_DEFAULT_ZIP); conf->def_mac = MUNGE_DEFAULT_MAC; conf->def_ttl = MUNGE_DEFAULT_TTL; conf->max_ttl = MUNGE_MAXIMUM_TTL; /* * FIXME: Add support for default realm. */ conf->config_name = NULL; conf->lockfile_fd = -1; conf->lockfile_name = NULL; _conf_set_cwd (conf); if (!(conf->logfile_name = strdup (MUNGE_LOGFILE_PATH))) { log_errno (EMUNGE_NO_MEMORY, LOG_ERR, "Failed to copy log-file name default string"); } if (!(conf->pidfile_name = strdup (MUNGE_PIDFILE_PATH))) { log_errno (EMUNGE_NO_MEMORY, LOG_ERR, "Failed to copy pid-file name default string"); } if (!(conf->socket_name = strdup (MUNGE_SOCKET_NAME))) { log_errno (EMUNGE_NO_MEMORY, LOG_ERR, "Failed to copy socket name default string"); } if (!(conf->seed_name = strdup (MUNGE_SEEDFILE_PATH))) { log_errno (EMUNGE_NO_MEMORY, LOG_ERR, "Failed to copy seed-file name default string"); } if (!(conf->key_name = strdup (MUNGE_KEYFILE_PATH))) { log_errno (EMUNGE_NO_MEMORY, LOG_ERR, "Failed to copy key-file name default string"); } conf->dek_key = NULL; conf->dek_key_len = 0; conf->mac_key = NULL; conf->mac_key_len = 0; conf->origin_name = NULL; conf->origin_ifname = NULL; memset (&conf->addr, 0, sizeof (conf->addr)); conf->gids = NULL; conf->gids_update_secs = MUNGE_GROUP_UPDATE_SECS; conf->nthreads = MUNGE_THREADS; conf->auth_server_dir = NULL; conf->auth_client_dir = NULL; conf->auth_rnd_bytes = MUNGE_AUTH_RND_BYTES; #if defined(AUTH_METHOD_RECVFD_MKFIFO) || defined(AUTH_METHOD_RECVFD_MKNOD) if (!(conf->auth_server_dir = strdup (MUNGE_AUTH_SERVER_DIR))) { log_errno (EMUNGE_NO_MEMORY, LOG_ERR, "Failed to copy auth-server-dir default string"); } if (!(conf->auth_client_dir = strdup (MUNGE_AUTH_CLIENT_DIR))) { log_errno (EMUNGE_NO_MEMORY, LOG_ERR, "Failed to copy auth-client-dir default string"); } #endif /* AUTH_METHOD_RECVFD_MKFIFO || AUTH_METHOD_RECVFD_MKNOD */ return (conf); } void destroy_conf (conf_t conf, int do_unlink) { int rv; assert (conf != NULL); assert (conf->ld < 0); /* sock_destroy() already called */ assert (conf->lockfile_fd < 0); if (conf->cwd) { free (conf->cwd); conf->cwd = NULL; } if (conf->config_name) { free (conf->config_name); conf->config_name = NULL; } if (conf->lockfile_name) { free (conf->lockfile_name); conf->lockfile_name = NULL; } if (conf->logfile_name) { free (conf->logfile_name); conf->logfile_name = NULL; } if (conf->pidfile_name) { if (do_unlink) { do { rv = unlink (conf->pidfile_name); } while ((rv < 0) && (errno == EINTR)); if (rv < 0) { log_msg (LOG_WARNING, "Failed to remove pidfile \"%s\": %s", conf->pidfile_name, strerror (errno)); } } free (conf->pidfile_name); conf->pidfile_name = NULL; } if (conf->socket_name) { free (conf->socket_name); conf->socket_name = NULL; } if (conf->seed_name) { free (conf->seed_name); conf->seed_name = NULL; } if (conf->key_name) { free (conf->key_name); conf->key_name = NULL; } if (conf->dek_key) { memburn (conf->dek_key, 0, conf->dek_key_len); free (conf->dek_key); conf->dek_key = NULL; } if (conf->mac_key) { memburn (conf->mac_key, 0, conf->mac_key_len); free (conf->mac_key); conf->mac_key = NULL; } if (conf->origin_name) { free (conf->origin_name); conf->origin_name = NULL; } if (conf->origin_ifname) { free (conf->origin_ifname); conf->origin_ifname = NULL; } if (conf->auth_server_dir) { free (conf->auth_server_dir); conf->auth_server_dir = NULL; } if (conf->auth_client_dir) { free (conf->auth_client_dir); conf->auth_client_dir = NULL; } free (conf); return; } void parse_cmdline (conf_t conf, int argc, char **argv) { char *prog; int c; long l; char *p; assert (conf != NULL); opterr = 0; /* suppress default getopt err msgs */ prog = (prog = strrchr (argv[0], '/')) ? prog + 1 : argv[0]; for (;;) { c = getopt_long (argc, argv, short_opts, long_opts, NULL); if (c == -1) { /* reached end of option list */ break; } switch (c) { case 'h': _conf_display_help (prog); exit (EMUNGE_SUCCESS); break; case 'L': display_license (); exit (EMUNGE_SUCCESS); break; case 'V': display_version (); exit (EMUNGE_SUCCESS); break; case 'f': conf->got_force = 1; break; case 'F': conf->got_foreground = 1; break; case 'M': conf->got_mlockall = 1; break; case 's': conf->got_stop = 1; break; case 'S': _conf_set_string (&conf->socket_name, optarg, conf->cwd, "socket name"); break; case 'v': conf->got_verbose = 1; break; case OPT_ADVICE: printf ("Don't Panic!\n"); exit (42); #if defined(AUTH_METHOD_RECVFD_MKFIFO) || defined(AUTH_METHOD_RECVFD_MKNOD) case OPT_AUTH_SERVER: _conf_set_string (&conf->auth_server_dir, optarg, conf->cwd, "auth-server-dir name"); break; case OPT_AUTH_CLIENT: _conf_set_string (&conf->auth_client_dir, optarg, conf->cwd, "auth-client-dir name"); break; #endif /* AUTH_METHOD_RECVFD_MKFIFO || AUTH_METHOD_RECVFD_MKNOD */ case OPT_BENCHMARK: conf->got_benchmark = 1; break; case OPT_GROUP_CHECK: errno = 0; l = strtol (optarg, &p, 10); if (((errno == ERANGE) && ((l == LONG_MIN) || (l == LONG_MAX))) || (optarg == p) || (*p != '\0')) { log_err (EMUNGE_SNAFU, LOG_ERR, "Invalid value \"%s\" for group-check-mtime", optarg); } conf->got_group_stat = !! l; break; case OPT_GROUP_UPDATE: errno = 0; l = strtol (optarg, &p, 10); if (((errno == ERANGE) && ((l == LONG_MIN) || (l == LONG_MAX))) || (optarg == p) || (*p != '\0') || (l < INT_MIN) || (l > INT_MAX)) { log_err (EMUNGE_SNAFU, LOG_ERR, "Invalid value \"%s\" for group-update-time", optarg); } conf->gids_update_secs = l; break; case OPT_KEY_FILE: _conf_set_string (&conf->key_name, optarg, conf->cwd, "key-file name"); break; case OPT_LOG_FILE: _conf_set_string (&conf->logfile_name, optarg, conf->cwd, "log-file name"); break; case OPT_MAX_TTL: l = strtol (optarg, &p, 10); if (((errno == ERANGE) && ((l == LONG_MIN) || (l == LONG_MAX))) || (optarg == p) || (*p != '\0') || (l < 1) || (l > MUNGE_MAXIMUM_TTL)) { log_err (EMUNGE_SNAFU, LOG_ERR, "Invalid value \"%s\" for max-ttl", optarg); } conf->max_ttl = l; break; case OPT_NUM_THREADS: errno = 0; l = strtol (optarg, &p, 10); if (((errno == ERANGE) && ((l == LONG_MIN) || (l == LONG_MAX))) || (optarg == p) || (*p != '\0') || (l <= 0) || (l > INT_MAX)) { log_err (EMUNGE_SNAFU, LOG_ERR, "Invalid value \"%s\" for num-threads", optarg); } conf->nthreads = l; break; case OPT_ORIGIN: _conf_set_string (&conf->origin_name, optarg, NULL, "origin"); break; case OPT_PID_FILE: _conf_set_string (&conf->pidfile_name, optarg, conf->cwd, "pid-file name"); break; case OPT_SEED_FILE: _conf_set_string (&conf->seed_name, optarg, conf->cwd, "seed-file name"); break; case OPT_SYSLOG: conf->got_syslog = 1; break; case OPT_TRUSTED_GROUP: if (path_set_trusted_group (optarg) < 0) { log_err (EMUNGE_SNAFU, LOG_ERR, "Invalid value \"%s\" for trusted-group", optarg); } break; case '?': if (optopt > 0) { log_err (EMUNGE_SNAFU, LOG_ERR, "Invalid option \"-%c\"", optopt); } else if (optind > 1) { log_err (EMUNGE_SNAFU, LOG_ERR, "Invalid option \"%s\"", argv[optind - 1]); } else { log_err (EMUNGE_SNAFU, LOG_ERR, "Failed to process command-line"); } break; case ':': if ((optind > 1) && (strncmp (argv[optind - 1], "--", 2) == 0)) { log_err (EMUNGE_SNAFU, LOG_ERR, "Missing argument for option \"%s\"", argv[optind - 1]); } else if (optopt > 0) { log_err (EMUNGE_SNAFU, LOG_ERR, "Missing argument for option \"-%c\"", optopt); } else { log_err (EMUNGE_SNAFU, LOG_ERR, "Failed to process command-line"); } break; default: if ((optind > 1) && (strncmp (argv[optind - 1], "--", 2) == 0)) { log_err (EMUNGE_SNAFU, LOG_ERR, "Unimplemented option \"%s\"", argv[optind - 1]); } else { log_err (EMUNGE_SNAFU, LOG_ERR, "Unimplemented option \"-%c\"", c); } break; } } if (argv[optind]) { log_err (EMUNGE_SNAFU, LOG_ERR, "Unrecognized parameter \"%s\"", argv[optind]); } } void process_conf (conf_t conf) { /* Process the configuration. */ assert (conf != NULL); if (conf->got_stop) { _conf_process_stop (conf); } _conf_set_origin_addr (conf); return; } void write_origin_addr (conf_t conf) { /* Write a log message indicating the origin address that will be encoded into * the credential metadata. */ char buf[INET_ADDRSTRLEN]; assert (conf != NULL); if (!inet_ntop (AF_INET, &conf->addr, buf, sizeof (buf))) { log_msg (LOG_WARNING, "Failed to convert origin address to a string"); } else if (conf->origin_ifname != NULL) { log_msg (LOG_INFO, "Set origin address to %s (%s)", buf, conf->origin_ifname); } else { log_msg (LOG_INFO, "Set origin address to %s", buf); } return; } void create_subkeys (conf_t conf) { int fd; int n; int n_total; unsigned char buf[1024]; md_ctx dek_ctx; md_ctx mac_ctx; assert (conf != NULL); assert (conf->dek_key == NULL); assert (conf->mac_key == NULL); /* Allocate memory for subkeys. */ if ((conf->dek_key_len = md_size (MUNGE_MAC_SHA1)) <= 0) { log_err (EMUNGE_NO_MEMORY, LOG_ERR, "Failed to determine DEK key length"); } if (!(conf->dek_key = malloc (conf->dek_key_len))) { log_err (EMUNGE_NO_MEMORY, LOG_ERR, "Failed to allocate %d bytes for cipher subkey", conf->dek_key_len); } if ((conf->mac_key_len = md_size (MUNGE_MAC_SHA1)) <= 0) { log_err (EMUNGE_NO_MEMORY, LOG_ERR, "Failed to determine MAC key length"); } if (!(conf->mac_key = malloc (conf->mac_key_len))) { log_err (EMUNGE_NO_MEMORY, LOG_ERR, "Failed to allocate %d bytes for MAC subkey", conf->mac_key_len); } if (md_init (&dek_ctx, MUNGE_MAC_SHA1) < 0) { log_err (EMUNGE_SNAFU, LOG_ERR, "Failed to compute subkeys: Cannot init md ctx"); } /* Compute keyfile's message digest. */ fd = _conf_open_keyfile (conf->key_name, conf->got_force); assert (fd >= 0); n_total = 0; for (;;) { n = read (fd, buf, sizeof (buf)); if (n == 0) break; if ((n < 0) && (errno == EINTR)) continue; if (n < 0) log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to read keyfile \"%s\"", conf->key_name); if (md_update (&dek_ctx, buf, n) < 0) log_err (EMUNGE_SNAFU, LOG_ERR, "Failed to compute subkeys: Cannot update md ctx"); n_total += n; } if (close (fd) < 0) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to close keyfile \"%s\"", conf->key_name); } if (n_total < MUNGE_KEY_LEN_MIN_BYTES) { log_err (EMUNGE_SNAFU, LOG_ERR, "Keyfile must be at least %d bytes", MUNGE_KEY_LEN_MIN_BYTES); } if (md_copy (&mac_ctx, &dek_ctx) < 0) { log_err (EMUNGE_SNAFU, LOG_ERR, "Failed to compute subkeys: Cannot copy md ctx"); } /* Append "1" to keyfile in order to compute cipher subkey. */ n = conf->dek_key_len; if ( (md_update (&dek_ctx, "1", 1) < 0) || (md_final (&dek_ctx, conf->dek_key, &n) < 0) || (md_cleanup (&dek_ctx) < 0) ) { log_err (EMUNGE_SNAFU, LOG_ERR, "Failed to compute cipher subkey"); } assert (n <= conf->dek_key_len); /* Append "2" to keyfile in order to compute mac subkey. */ n = conf->mac_key_len; if ( (md_update (&mac_ctx, "2", 1) < 0) || (md_final (&mac_ctx, conf->mac_key, &n) < 0) || (md_cleanup (&mac_ctx) < 0) ) { log_err (EMUNGE_SNAFU, LOG_ERR, "Failed to compute MAC subkey"); } assert (n <= conf->mac_key_len); return; } /***************************************************************************** * Internal Functions *****************************************************************************/ static void _conf_set_cwd (conf_t conf) { /* Set the current working directory in order to fix relative paths so these * locations can still be accessed after chdir() is called. */ char buf [PATH_MAX]; char *rv; rv = getcwd (buf, sizeof (buf)); /* Starting in Linux 2.6.36, the path returned by getcwd() will be * prefixed with "(unreachable)" if the current directory is not below * the root directory of the current process. With glibc 2.27 onwards, * this will instead result in failure with ENOENT. * Since relative paths break the getcwd() API contract requiring an * absolute path, convert anything not starting with an absolute path * (like "(unreachable)") to ENOENT. */ if ((rv != NULL) && (buf[0] != '/')) { rv = NULL; errno = ENOENT; } if (rv == NULL) { conf->cwd = NULL; if (errno == ERANGE) { log_msg (LOG_WARNING, "Failed to set current working directory: " "Exceeded %lu-byte buffer", sizeof (buf)); } else { log_msg (LOG_WARNING, "Failed to set current working directory: %s", strerror (errno)); } } else { conf->cwd = strdup (buf); if (conf->cwd == NULL) { log_errno (EMUNGE_NO_MEMORY, LOG_ERR, "Failed to copy current working directory string"); } } } static void _conf_display_help (char *prog) { /* Displays a help message describing the command-line options. */ const int w = -25; /* pad for width of option string */ assert (prog != NULL); printf ("Usage: %s [OPTIONS]\n", prog); printf ("\n"); printf (" %*s %s\n", w, "-h, --help", "Display this help message"); printf (" %*s %s\n", w, "-L, --license", "Display license information"); printf (" %*s %s\n", w, "-V, --version", "Display version information"); printf ("\n"); printf (" %*s %s\n", w, "-f, --force", "Force daemon to run if possible"); printf (" %*s %s\n", w, "-F, --foreground", "Run daemon in the foreground (do not fork)"); printf (" %*s %s\n", w, "-M, --mlockall", "Lock all pages in memory"); printf (" %*s %s\n", w, "-s, --stop", "Stop daemon bound to socket"); printf (" %*s %s [%s]\n", w, "-S, --socket=PATH", "Specify local socket", MUNGE_SOCKET_NAME); printf (" %*s %s\n", w, "-v, --verbose", "Be verbose"); printf ("\n"); #if defined(AUTH_METHOD_RECVFD_MKFIFO) || defined(AUTH_METHOD_RECVFD_MKNOD) printf (" %*s %s [%s]\n", w, "--auth-server-dir=DIR", "Specify auth-server directory", MUNGE_AUTH_SERVER_DIR); printf (" %*s %s [%s]\n", w, "--auth-client-dir=DIR", "Specify auth-client directory", MUNGE_AUTH_CLIENT_DIR); #endif /* AUTH_METHOD_RECVFD_MKFIFO || AUTH_METHOD_RECVFD_MKNOD */ printf (" %*s %s\n", w, "--benchmark", "Disable timers to reduce noise while benchmarking"); printf (" %*s Specify whether to check \"%s\" mtime [%d]\n", w, "--group-check-mtime=BOOL", GIDS_GROUP_FILE, MUNGE_GROUP_STAT_FLAG); printf (" %*s %s [%d]\n", w, "--group-update-time=SECS", "Specify seconds between group info updates", MUNGE_GROUP_UPDATE_SECS); printf (" %*s %s [%s]\n", w, "--key-file=PATH", "Specify key file", MUNGE_KEYFILE_PATH); printf (" %*s %s [%s]\n", w, "--log-file=PATH", "Specify log file", MUNGE_LOGFILE_PATH); printf (" %*s %s [%d]\n", w, "--max-ttl=SECS", "Specify maximum time-to-live (in seconds)", MUNGE_MAXIMUM_TTL); printf (" %*s %s [%d]\n", w, "--num-threads=INT", "Specify number of threads to spawn", MUNGE_THREADS); printf (" %*s %s\n", w, "--origin=ADDR", "Specify origin address via hostname/IPaddr/interface"); printf (" %*s %s [%s]\n", w, "--pid-file=PATH", "Specify PID file", MUNGE_PIDFILE_PATH); printf (" %*s %s [%s]\n", w, "--seed-file=PATH", "Specify PRNG seed file", MUNGE_SEEDFILE_PATH); printf (" %*s %s\n", w, "--syslog", "Redirect log messages to syslog"); printf (" %*s %s\n", w, "--trusted-group=GID", "Specify trusted group/GID for directory checks"); printf ("\n"); return; } static void _conf_set_string (char **str_p, const char *val, const char *cwd, const char *dsc) { /* Set the string referenced by [str_p] to the string value [val], freeing * an existing string pointed to by [str_p] if needed. If [val] is not an * absolute pathname and the current working directory string [cwd] is set, * that string will be prepended to [val]. * The description string [dsc] will be used in the error message if needed. */ assert (str_p != NULL); assert (val != NULL); assert (dsc != NULL); if (*str_p != NULL) { free (*str_p); } *str_p = (val[0] == '/' || cwd == NULL) ? strdup (val) : strdupf ("%s/%s", cwd, val); if (*str_p == NULL) { log_errno (EMUNGE_NO_MEMORY, LOG_ERR, "Failed to copy %s string", dsc); } } static void _conf_process_stop (conf_t conf) { /* Process the -s/--stop option. * A SIGTERM is sent to the process holding the write-lock. * A SIGKILL is sent afterwards if the process fails to terminate. */ pid_t pid; int rv; assert (conf != NULL); assert (MUNGE_SIGNAL_WAIT_MSECS > 0); /* Obtain pid of daemon bound to socket. */ pid = lock_query (conf); if (pid <= 0) { if (conf->got_verbose) { log_err (EMUNGE_SNAFU, LOG_ERR, "Failed to query socket lockfile \"%s\": %s (%s)", conf->lockfile_name, (pid == 0) ? "Lock not held" : strerror (errno), "Cannot find running process"); } exit (EXIT_FAILURE); } /* Terminate. */ rv = _conf_send_signal (pid, SIGTERM, MUNGE_SIGNAL_WAIT_MSECS); if (rv == 0) { if (conf->got_verbose) { log_msg (LOG_NOTICE, "Terminated daemon bound to socket \"%s\" (pid %d)", conf->socket_name, pid); } exit (EXIT_SUCCESS); } /* Kill. */ rv = _conf_send_signal (pid, SIGKILL, MUNGE_SIGNAL_WAIT_MSECS); if (rv == 0) { if (conf->got_verbose) { log_msg (LOG_NOTICE, "Killed daemon bound to socket \"%s\" (pid %d)", conf->socket_name, pid); } exit (EXIT_SUCCESS); } /* Fail. */ log_err (EMUNGE_SNAFU, LOG_ERR, "Failed to terminate daemon bound to socket \"%s\" (pid %d)", conf->socket_name, pid); exit (EXIT_FAILURE); } static int _conf_send_signal (pid_t pid, int signum, int msecs) { /* Send the signal [signum] to the process specified by [pid]. * Return 1 if the process is still running after a delay of [msecs], * or 0 if the process has terminated. */ struct timespec wait_abstime; int rv; int sig; assert (pid > 0); assert (signum > 0); assert (msecs > 0); assert (MUNGE_SIGNAL_CHECK_MSECS > 0); rv = clock_get_timespec (&wait_abstime, msecs); if (rv < 0) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to get wait time for termination"); } sig = signum; while (1) { rv = kill (pid, sig); if (rv < 0) { if (errno == ESRCH) { return (0); } log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to signal daemon (pid %d, sig %d)", pid, sig); } rv = clock_is_timespec_expired (&wait_abstime); if (rv < 0) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to check if termination wait time has expired"); } if (rv == 1) { break; } /* Now that SIGNUM has been sent, switch to sending the null signal * to check for PID existence. */ if (sig != 0) { sig = 0; } _conf_sleep (MUNGE_SIGNAL_CHECK_MSECS); } return (1); } static void _conf_sleep (int msecs) { /* Sleep for the specified number of milliseconds [msecs]. */ #if HAVE_CLOCK_NANOSLEEP struct timespec check_abstime; int rv; rv = clock_get_timespec (&check_abstime, msecs); if (rv < 0) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to get check time for termination"); } do { rv = clock_nanosleep (CLOCK_REALTIME, TIMER_ABSTIME, &check_abstime, NULL); } while ((rv < 0) && (errno == EINTR)); if (rv < 0) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to sleep before checking for termination"); } #else /* !HAVE_CLOCK_NANOSLEEP */ struct timespec check_reltime; int rv; check_reltime.tv_sec = msecs / 1000; check_reltime.tv_nsec = (msecs % 1000) * 1000 * 1000; do { rv = nanosleep (&check_reltime, &check_reltime); } while ((rv < 0) && (errno == EINTR)); if (rv < 0) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to sleep before checking for termination"); } #endif /* !HAVE_CLOCK_NANOSLEEP */ } static void _conf_set_origin_addr (conf_t conf) { /* Set the origin address to be encoded into credential metadata. * If an origin is explicitly specified, failure to lookup its network address * results in an error which can be overridden. * If an orgin is not specified or the error is overridden, a warning is * logged and the origin address is set to the null address. */ int is_origin_specified; int rv = 0; assert (conf != NULL); memset (&conf->addr, 0, sizeof (conf->addr)); conf->origin_ifname = NULL; is_origin_specified = (conf->origin_name != NULL) ? 1 : 0; if (conf->origin_name == NULL) { rv = net_get_hostname (&conf->origin_name); if (rv < 0) { log_msg (LOG_WARNING, "Failed to get name of current host"); } } if (conf->origin_name != NULL) { errno = 0; rv = net_get_hostaddr (conf->origin_name, &conf->addr, &conf->origin_ifname); if (rv < 0) { log_err_or_warn (conf->got_force || !is_origin_specified, "Failed to lookup origin \"%s\"%s%s", conf->origin_name, (errno != 0) ? ": " : "", (errno != 0) ? strerror (errno) : ""); } } if (rv != 0) { log_msg (LOG_WARNING, "Continuing with origin set to null address"); } return; } static int _conf_open_keyfile (const char *keyfile, int got_force) { /* Returns a valid file-descriptor to the opened [keyfile], or dies trying. */ int is_symlink; struct stat st; int n; char keydir [PATH_MAX]; char ebuf [1024]; int fd; if ((keyfile == NULL) || (*keyfile == '\0')) { log_err (EMUNGE_SNAFU, LOG_ERR, "Keyfile name is undefined"); } is_symlink = (lstat (keyfile, &st) == 0) ? S_ISLNK (st.st_mode) : 0; if (stat (keyfile, &st) < 0) { log_err (EMUNGE_SNAFU, LOG_ERR, "Failed to find keyfile \"%s\": %s (%s)", keyfile, strerror (errno), "Did you run mungekey?"); } if (!S_ISREG (st.st_mode)) { log_err (EMUNGE_SNAFU, LOG_ERR, "Keyfile is insecure: \"%s\" must be a regular file (type=%07o)", keyfile, (st.st_mode & S_IFMT)); } if (is_symlink) { log_err_or_warn (got_force, "Keyfile is insecure: \"%s\" should not be a symbolic link", keyfile); } if (st.st_uid != geteuid ()) { log_err_or_warn (got_force, "Keyfile is insecure: \"%s\" should be owned by UID %u instead of " "UID %u", keyfile, (unsigned) geteuid (), (unsigned) st.st_uid); } if (st.st_mode & (S_IRGRP | S_IWGRP)) { log_err_or_warn (got_force, "Keyfile is insecure: \"%s\" should not be readable or writable " "by group (perms=%04o)", keyfile, (st.st_mode & ~S_IFMT)); } if (st.st_mode & (S_IROTH | S_IWOTH)) { log_err_or_warn (got_force, "Keyfile is insecure: \"%s\" should not be readable or writable " "by other (perms=%04o)", keyfile, (st.st_mode & ~S_IFMT)); } /* Ensure keyfile dir is secure against modification by others. */ if (path_dirname (keyfile, keydir, sizeof (keydir)) < 0) { log_err (EMUNGE_SNAFU, LOG_ERR, "Failed to determine dirname of keyfile \"%s\"", keyfile); } n = path_is_secure (keydir, ebuf, sizeof (ebuf), PATH_SECURITY_NO_FLAGS); if (n < 0) { log_err (EMUNGE_SNAFU, LOG_ERR, "Failed to check keyfile dir \"%s\": %s", keydir, ebuf); } else if (n == 0) { log_err_or_warn (got_force, "Keyfile is insecure: %s", ebuf); } /* Open keyfile for reading only. */ if ((fd = open (keyfile, O_RDONLY)) < 0) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to open keyfile \"%s\"", keyfile); } return (fd); } munge-munge-0.5.15/src/munged/conf.h000066400000000000000000000130531425467526100172100ustar00rootroot00000000000000/***************************************************************************** * Written by Chris Dunlap . * Copyright (C) 2007-2022 Lawrence Livermore National Security, LLC. * Copyright (C) 2002-2007 The Regents of the University of California. * UCRL-CODE-155910. * * This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE). * For details, see . * * MUNGE 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. Additionally for the MUNGE library (libmunge), you * can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation, * either version 3 of the License, or (at your option) any later version. * * MUNGE 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 * and GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * and GNU Lesser General Public License along with MUNGE. If not, see * . *****************************************************************************/ #ifndef MUNGE_CONF_H #define MUNGE_CONF_H #include #include #include #include "gids.h" /***************************************************************************** * Data Types *****************************************************************************/ struct conf { int ld; /* listening socket descriptor */ unsigned got_benchmark:1; /* flag for BENCHMARK option */ unsigned got_clock_skew:1; /* flag for allowing clock skew */ unsigned got_force:1; /* flag for FORCE option */ unsigned got_foreground:1; /* flag for FOREGROUND option */ unsigned got_group_stat:1; /* flag for gids stat'ing /etc/group */ unsigned got_stop:1; /* flag for stopping daemon */ unsigned got_mlockall:1; /* flag for locking all memory pages */ unsigned got_root_auth:1; /* flag if root can decode any cred */ unsigned got_socket_retry:1; /* flag for allowing decode retries */ unsigned got_syslog:1; /* flag if logging to syslog instead */ unsigned got_verbose:1; /* flag for being verbose */ munge_cipher_t def_cipher; /* default cipher type */ munge_zip_t def_zip; /* default compression type */ munge_mac_t def_mac; /* default message auth code type */ munge_ttl_t def_ttl; /* default time-to-live in seconds */ munge_ttl_t max_ttl; /* maximum time-to-live in seconds */ char *cwd; /* current working dir at startup */ char *config_name; /* configuration filename */ int lockfile_fd; /* daemon lockfile fd */ char *lockfile_name; /* daemon lockfile name */ char *logfile_name; /* daemon logfile name */ char *pidfile_name; /* daemon pidfile name */ char *socket_name; /* unix domain socket filename */ char *seed_name; /* random seed filename */ char *key_name; /* symmetric key filename */ unsigned char *dek_key; /* subkey for cipher ops */ int dek_key_len; /* length of cipher subkey */ unsigned char *mac_key; /* subkey for mac ops */ int mac_key_len; /* length of mac subkey */ char *origin_name; /* origin addr hostname/IP string */ char *origin_ifname; /* origin addr n/w interface name */ struct in_addr addr; /* origin addr in n/w byte order */ gids_t gids; /* supplementary group information */ int gids_update_secs; /* gids update interval in seconds */ int nthreads; /* num threads for processing creds */ char *auth_server_dir; /* dir in which to create auth pipe */ char *auth_client_dir; /* dir in which to create auth file */ int auth_rnd_bytes; /* num rnd bytes in auth pipe name */ }; typedef struct conf * conf_t; /***************************************************************************** * External Varables *****************************************************************************/ extern conf_t conf; /* defined in conf.c */ /***************************************************************************** * Prototypes *****************************************************************************/ conf_t create_conf (void); void destroy_conf (conf_t conf, int do_unlink); void parse_cmdline (conf_t conf, int argc, char **argv); void process_conf (conf_t conf); void write_origin_addr (conf_t conf); void create_subkeys (conf_t conf); #endif /* !MUNGE_CONF_H */ munge-munge-0.5.15/src/munged/cred.c000066400000000000000000000050401425467526100171700ustar00rootroot00000000000000/***************************************************************************** * Written by Chris Dunlap . * Copyright (C) 2007-2022 Lawrence Livermore National Security, LLC. * Copyright (C) 2002-2007 The Regents of the University of California. * UCRL-CODE-155910. * * This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE). * For details, see . * * MUNGE 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. Additionally for the MUNGE library (libmunge), you * can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation, * either version 3 of the License, or (at your option) any later version. * * MUNGE 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 * and GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * and GNU Lesser General Public License along with MUNGE. If not, see * . *****************************************************************************/ #if HAVE_CONFIG_H # include #endif /* HAVE_CONFIG_H */ #include #include #include #include "cred.h" #include "m_msg.h" #include "munge_defs.h" #include "str.h" munge_cred_t cred_create (m_msg_t m) { munge_cred_t c; assert (m != NULL); if (!(c = calloc (1, sizeof (*c)))) { m_msg_set_err (m, EMUNGE_NO_MEMORY, NULL); return (NULL); } c->version = MUNGE_CRED_VERSION; c->msg = m; return (c); } void cred_destroy (munge_cred_t c) { if (!c) { return; } if (c->outer_mem) { assert (c->outer_mem_len > 0); memset (c->outer_mem, 0, c->outer_mem_len); free (c->outer_mem); } if (c->inner_mem) { assert (c->inner_mem_len > 0); memset (c->inner_mem, 0, c->inner_mem_len); free (c->inner_mem); } if (c->realm_mem) { assert (c->realm_mem_len > 0); memset (c->realm_mem, 0, c->realm_mem_len); free (c->realm_mem); } memburn (c, 0, sizeof (*c)); /* nuke the msg dek */ free (c); return; } munge-munge-0.5.15/src/munged/cred.h000066400000000000000000000103511425467526100171760ustar00rootroot00000000000000/***************************************************************************** * Written by Chris Dunlap . * Copyright (C) 2007-2022 Lawrence Livermore National Security, LLC. * Copyright (C) 2002-2007 The Regents of the University of California. * UCRL-CODE-155910. * * This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE). * For details, see . * * MUNGE 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. Additionally for the MUNGE library (libmunge), you * can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation, * either version 3 of the License, or (at your option) any later version. * * MUNGE 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 * and GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * and GNU Lesser General Public License along with MUNGE. If not, see * . *****************************************************************************/ #ifndef CRED_H #define CRED_H #include #include #include "munge_defs.h" #include "m_msg.h" /***************************************************************************** * Constants *****************************************************************************/ /* Current version of the munge credential format. */ #define MUNGE_CRED_VERSION 3 #define MAX_DEK MUNGE_MAXIMUM_MD_LEN #define MAX_IV MUNGE_MAXIMUM_BLK_LEN #define MAX_MAC MUNGE_MAXIMUM_MD_LEN #define MAX_SALT MUNGE_CRED_SALT_LEN /***************************************************************************** * Data Types *****************************************************************************/ struct munge_cred { uint8_t version; /* version of the munge cred format */ m_msg_t msg; /* ptr to corresponding munge msg */ int outer_mem_len; /* length of outer credential memory */ unsigned char *outer_mem; /* outer cred memory allocation */ int outer_len; /* length of outer credential data */ unsigned char *outer; /* ptr to outer credential data */ int inner_mem_len; /* length of inner credential memory */ unsigned char *inner_mem; /* inner cred memory allocation */ int inner_len; /* length of inner credential data */ unsigned char *inner; /* ptr to inner credential data */ int realm_mem_len; /* length of realm string memory */ unsigned char *realm_mem; /* realm string memory allocation */ int salt_len; /* length of salt data */ unsigned char salt[MAX_SALT]; /* cryptographic seasoning salt */ int mac_len; /* length of mac data */ unsigned char mac[MAX_MAC]; /* message authentication code */ int dek_len; /* length of dek data */ unsigned char dek[MAX_DEK]; /* symmetric data encryption key */ int iv_len; /* length of iv data */ unsigned char iv[MAX_IV]; /* initialization vector */ unsigned char *outer_zip_ref; /* ref to zip_t in outer cred memory */ }; typedef struct munge_cred * munge_cred_t; /***************************************************************************** * Extern Functions *****************************************************************************/ munge_cred_t cred_create (m_msg_t m); void cred_destroy (munge_cred_t c); #endif /* !CRED_H */ munge-munge-0.5.15/src/munged/dec.c000066400000000000000000001007321425467526100170120ustar00rootroot00000000000000/***************************************************************************** * Written by Chris Dunlap . * Copyright (C) 2007-2022 Lawrence Livermore National Security, LLC. * Copyright (C) 2002-2007 The Regents of the University of California. * UCRL-CODE-155910. * * This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE). * For details, see . * * MUNGE 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. Additionally for the MUNGE library (libmunge), you * can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation, * either version 3 of the License, or (at your option) any later version. * * MUNGE 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 * and GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * and GNU Lesser General Public License along with MUNGE. If not, see * . *****************************************************************************/ #if HAVE_CONFIG_H # include "config.h" #endif /* HAVE_CONFIG_H */ #include #include #include #include /* include before in.h for bsd */ #include #include #include #include #include "auth_recv.h" #include "base64.h" #include "cipher.h" #include "conf.h" #include "cred.h" #include "crypto.h" #include "dec.h" #include "gids.h" #include "log.h" #include "m_msg.h" #include "mac.h" #include "munge_defs.h" #include "random.h" #include "replay.h" #include "str.h" #include "zip.h" /***************************************************************************** * Static Prototypes *****************************************************************************/ static int dec_validate_msg (m_msg_t m); static int dec_timestamp (munge_cred_t c); static int dec_authenticate (munge_cred_t c); static int dec_check_retry (munge_cred_t c); static int dec_unarmor (munge_cred_t c); static int dec_unpack_outer (munge_cred_t c); static int dec_decrypt (munge_cred_t c); static int dec_validate_mac (munge_cred_t c); static int dec_decompress (munge_cred_t c); static int dec_unpack_inner (munge_cred_t c); static int dec_validate_time (munge_cred_t c); static int dec_validate_auth (munge_cred_t c); static int dec_validate_replay (munge_cred_t c); /***************************************************************************** * Extern Functions *****************************************************************************/ int dec_process_msg (m_msg_t m) { munge_cred_t c = NULL; /* aux data for processing this cred */ int rc = -1; /* return code */ if (dec_validate_msg (m) < 0) ; else if (!(c = cred_create (m))) ; else if (dec_timestamp (c) < 0) ; else if (dec_authenticate (c) < 0) ; else if (dec_check_retry (c) < 0) ; else if (dec_unarmor (c) < 0) ; else if (dec_unpack_outer (c) < 0) ; else if (dec_decrypt (c) < 0) ; else if (dec_validate_mac (c) < 0) ; else if (dec_decompress (c) < 0) ; else if (dec_unpack_inner (c) < 0) ; else if (dec_validate_auth (c) < 0) ; else if (dec_validate_time (c) < 0) ; else if (dec_validate_replay (c) < 0) ; else /* success */ rc = 0; /* Since the same m_msg struct is used for both the request and response, * the response message data must be sanitized for most errors. * The exception to this is for a credential that has been successfully * decoded but is invalid due to being expired, rewound, or replayed. */ if ((rc != 0) && (m->error_num != EMUNGE_CRED_EXPIRED) && (m->error_num != EMUNGE_CRED_REWOUND) && (m->error_num != EMUNGE_CRED_REPLAYED) ) { m_msg_reset (m); } /* If the successfully decoded credential isn't successfully returned to * the client, remove it from the replay hash. * * If two instances of the same credential are being decoded at the same * time, dec_validate_replay() will mark the "first" as successful, and * the "second" as replayed. But if the successful response to the * "first" client fails, that credential will then be marked as * "unplayed", and the replayed reponse to the "second" client will now * be in error. */ if (m_msg_send (m, MUNGE_MSG_DEC_RSP, 0) != EMUNGE_SUCCESS) { if (rc == 0) { replay_remove (c); } rc = -1; } cred_destroy (c); return (rc); } /***************************************************************************** * Static Functions *****************************************************************************/ static int dec_validate_msg (m_msg_t m) { /* Validates a credential exists for decoding. */ assert (m != NULL); assert (m->type == MUNGE_MSG_DEC_REQ); if ((m->data_len == 0) || (m->data == NULL)) { return (m_msg_set_err (m, EMUNGE_SNAFU, strdup ("No credential specified in decode request"))); } return (0); } static int dec_timestamp (munge_cred_t c) { /* Queries the current time. */ m_msg_t m = c->msg; time_t now; /* Set the "decode" time. */ if (time (&now) == ((time_t) -1)) { return (m_msg_set_err (m, EMUNGE_SNAFU, strdup ("Failed to query current time"))); } m->time0 = 0; m->time1 = now; /* potential 64b value for 32b var */ return (0); } static int dec_authenticate (munge_cred_t c) { /* Ascertains the UID/GID of the client process. */ m_msg_t m = c->msg; uid_t *p_uid; gid_t *p_gid; p_uid = (uid_t *) &(m->client_uid); p_gid = (gid_t *) &(m->client_gid); /* Determine identity of client process. */ if (auth_recv (m, p_uid, p_gid) != EMUNGE_SUCCESS) { return (m_msg_set_err (m, EMUNGE_SNAFU, strdup ("Failed to determine client identity"))); } return (0); } static int dec_check_retry (munge_cred_t c) { /* Checks whether the transaction is being retried. */ m_msg_t m = c->msg; if (m->retry > 0) { log_msg (LOG_INFO, "Decode retry #%d for client UID=%u GID=%u", m->retry, (unsigned int) m->client_uid, (unsigned int) m->client_gid); } if (m->retry > MUNGE_SOCKET_RETRY_ATTEMPTS) { return (m_msg_set_err (m, EMUNGE_SOCKET, strdupf ("Exceeded maximum number of decode attempts"))); } return (0); } static int dec_unarmor (munge_cred_t c) { /* Removes the credential's armor, converting it into a packed byte array. * The armor consists of PREFIX + BASE64 [ OUTER + MAC + INNER ] + SUFFIX. */ m_msg_t m = c->msg; int prefix_len; /* prefix string length */ int suffix_len; /* prefix string length */ int base64_len; /* length of base64 data */ unsigned char *base64_ptr; /* base64 data (ptr into msg data) */ unsigned char *base64_tmp; /* base64 data tmp ptr */ int n; /* all-purpose int */ prefix_len = strlen (MUNGE_CRED_PREFIX); suffix_len = strlen (MUNGE_CRED_SUFFIX); base64_ptr = m->data; base64_len = m->data_len; /* Consume leading whitespace. */ while ((base64_len > 0) && isspace (*base64_ptr)) { base64_ptr++; base64_len--; } if ((base64_len == 0) || (*base64_ptr == '\0')) { return (m_msg_set_err (m, EMUNGE_BAD_ARG, strdup ("No credential specified"))); } /* Remove the prefix string. * The prefix specifies the start of the base64-encoded data. */ if (prefix_len > 0) { if (strncmp ((char *) base64_ptr, MUNGE_CRED_PREFIX, prefix_len)) { return (m_msg_set_err (m, EMUNGE_BAD_CRED, strdup ("Failed to match armor prefix"))); } base64_ptr += prefix_len; base64_len -= prefix_len; } /* Remove the suffix string. * The suffix specifies the end of the base64-encoded data. * We can't rely on the base64 pad character to detect the end, * since that only exists if the input isn't a multiple of 3 bytes. * However, the suffix isn't strictly necessary since whitespace * is safely ignored by the base64 decoding routine. * Still, it's nice to have a quick visual test to see if it's all there. * * XXX: This may be somewhat inefficient if the suffix isn't there. * If all goes well, the suffix will match on the 3rd comparison * due to the trailing "\n\0". */ if (suffix_len > 0) { base64_tmp = base64_ptr + base64_len - suffix_len; while (base64_tmp >= base64_ptr) { if (!strncmp ((char *) base64_tmp, MUNGE_CRED_SUFFIX, suffix_len)) break; base64_tmp--; } if (base64_tmp < base64_ptr) { return (m_msg_set_err (m, EMUNGE_BAD_CRED, strdup ("Failed to match armor suffix"))); } base64_len = base64_tmp - base64_ptr; } /* Allocate memory for unarmor'd data. */ c->outer_mem_len = base64_decode_length (base64_len); if (!(c->outer_mem = malloc (c->outer_mem_len))) { return (m_msg_set_err (m, EMUNGE_NO_MEMORY, NULL)); } /* Base64-decode the chewy-internals of the credential. */ if (base64_decode_block (c->outer_mem, &n, base64_ptr, base64_len) < 0) { return (m_msg_set_err (m, EMUNGE_BAD_CRED, strdup ("Failed to base64-decode credential"))); } assert (n < c->outer_mem_len); /* Now that the "request data" has been unarmored, it can be free()d. */ free (m->data); m->data = NULL; m->data_len = 0; assert (m->data_is_copy == 0); /* Note outer_len is an upper bound which will be refined when unpacked. * It currently includes OUTER + MAC + INNER. */ c->outer = c->outer_mem; c->outer_len = n; return (0); } static int dec_unpack_outer (munge_cred_t c) { /* Unpacks the "outer" credential data from MSBF (ie, big endian) format. * The "outer" part of the credential does not undergo cryptographic * transformations (ie, compression and encryption). It includes: * cred version, cipher type, mac type, compression type, realm length, * unterminated realm string (if realm_len > 0), and the cipher's * initialization vector (if encrypted). * Validation of the "outer" credential occurs here as well since unpacking * may not be able to continue if an invalid field is found. * While the MAC is not technically part of the "outer" credential data, * it is unpacked here since it resides in outer_mem and its location * (along with the location of the "inner" data) is determined as a * result of unpacking the "outer" data. */ m_msg_t m = c->msg; unsigned char *p; /* ptr into packed data */ int len; /* length of packed data remaining */ int n; /* all-purpose int */ assert (c->outer != NULL); /* Initialize. */ p = c->outer; len = c->outer_len; /* * Unpack the credential version. * Note that only one version (ie, the latest) of the credential format * is currently supported. Support for multiple versions would * require a switch on the version number to invoke the appropriate * unpack routine, but it doesn't really seem worth the effort. */ n = sizeof (c->version); assert (n == 1); if (n > len) { return (m_msg_set_err (m, EMUNGE_BAD_CRED, strdup ("Truncated credential version"))); } c->version = *p; if (c->version != MUNGE_CRED_VERSION) { return (m_msg_set_err (m, EMUNGE_BAD_VERSION, strdupf ("Invalid credential version %d", c->version))); } p += n; len -= n; /* * Unpack the cipher type. */ n = sizeof (m->cipher); assert (n == 1); if (n > len) { return (m_msg_set_err (m, EMUNGE_BAD_CRED, strdup ("Truncated cipher type"))); } m->cipher = *p; if (m->cipher == MUNGE_CIPHER_NONE) { c->iv_len = 0; } else { if (cipher_map_enum (m->cipher, NULL) < 0) { return (m_msg_set_err (m, EMUNGE_BAD_CIPHER, strdupf ("Invalid cipher type %d", m->cipher))); } c->iv_len = cipher_iv_size (m->cipher); if (c->iv_len < 0) { return (m_msg_set_err (m, EMUNGE_SNAFU, strdupf ("Failed to determine IV length for cipher type %d", m->cipher))); } assert (c->iv_len <= sizeof (c->iv)); } p += n; len -= n; /* * Unpack the message authentication code type. */ n = sizeof (m->mac); assert (n == 1); if (n > len) { return (m_msg_set_err (m, EMUNGE_BAD_CRED, strdup ("Truncated MAC type"))); } m->mac = *p; if (mac_map_enum (m->mac, NULL) < 0) { return (m_msg_set_err (m, EMUNGE_BAD_MAC, strdupf ("Invalid MAC type %d", m->mac))); } c->mac_len = mac_size (m->mac); if (c->mac_len <= 0) { return (m_msg_set_err (m, EMUNGE_SNAFU, strdupf ("Failed to determine digest length for MAC type %d", m->mac))); } assert (c->mac_len <= sizeof (c->mac)); p += n; len -= n; /* * Validate the message authentication code type against the cipher type * to ensure the HMAC will generate a DEK of sufficient length for the * cipher. */ if (mac_size (m->mac) < cipher_key_size (m->cipher)) { return (m_msg_set_err (m, EMUNGE_BAD_MAC, strdupf ("Invalid MAC type %d with cipher type %d", m->mac, m->cipher))); } /* * Unpack the compression type. */ n = sizeof (m->zip); assert (n == 1); if (n > len) { return (m_msg_set_err (m, EMUNGE_BAD_CRED, strdup ("Truncated compression type"))); } m->zip = *p; if (m->zip == MUNGE_ZIP_NONE) { ; /* not compressed */ } else { if (!zip_is_valid_type (m->zip)) { return (m_msg_set_err (m, EMUNGE_BAD_ZIP, strdupf ("Invalid compression type %d", m->zip))); } } p += n; len -= n; /* * Unpack the length of realm string. */ n = sizeof (m->realm_len); assert (n == 1); if (n > len) { return (m_msg_set_err (m, EMUNGE_BAD_CRED, strdup ("Truncated security realm length"))); } m->realm_len = *p; p += n; len -= n; /* * Unpack the unterminated realm string (if present). * Note that the realm string is NUL-terminated after unpacking. */ if (m->realm_len > 0) { if (m->realm_len > len) { return (m_msg_set_err (m, EMUNGE_BAD_CRED, strdup ("Truncated security realm string"))); } c->realm_mem_len = m->realm_len + 1; /* * Since the realm len is a uint8, the max memory malloc'd here * for the realm string is 256 bytes. */ if (!(c->realm_mem = malloc (c->realm_mem_len))) { return (m_msg_set_err (m, EMUNGE_NO_MEMORY, NULL)); } memcpy (c->realm_mem, p, m->realm_len); c->realm_mem[m->realm_len] = '\0'; p += m->realm_len; len -= m->realm_len; /* * Update realm & realm_len to refer to the string in "cred memory". */ m->realm_str = (char *) c->realm_mem; m->realm_len = c->realm_mem_len; m->realm_is_copy = 1; } /* Unpack the cipher initialization vector (if needed). * The length of the IV was derived from the cipher type. */ if (c->iv_len > 0) { if (c->iv_len > len) { return (m_msg_set_err (m, EMUNGE_BAD_CRED, strdup ("Truncated cipher IV"))); } assert (c->iv_len <= sizeof (c->iv)); memcpy (c->iv, p, c->iv_len); p += c->iv_len; len -= c->iv_len; } /* Refine outer_len now that we've reached the end of the "outer" data. */ c->outer_len = p - c->outer; /* * Unpack the MAC. */ memcpy (c->mac, p, c->mac_len); p += c->mac_len; len -= c->mac_len; /* * We've finally reached the chewy center of the "inner" data. */ c->inner = p; c->inner_len = len; return (0); } static int dec_decrypt (munge_cred_t c) { /* Decrypts the "inner" credential data. * * Note that if cipher_final() fails, an error condition is set but an error * status is not returned (yet). Here's why: * cipher_final() will return an error code during decryption if padding is * enabled and the final block is not correctly formatted. * If block cipher padding errors are not treated the same as MAC verification * errors, an attacker may be able to launch Vaudenay's attack on padding: * - * - * - * - * Consequently, if cipher_final() returns a failure, the error condition is * set here and the MAC computation in dec_validate_mac() is performed * regardless in order to minimize information leaked via timing. */ m_msg_t m = c->msg; int buf_len; /* length of plaintext buffer */ unsigned char *buf; /* plaintext buffer */ unsigned char *buf_ptr; /* ptr into plaintext buffer */ cipher_ctx x; /* cipher context */ int n_written; /* number of bytes written to buf */ int n; /* all-purpose int */ /* Is this credential encrypted? */ if (m->cipher == MUNGE_CIPHER_NONE) { return (0); } /* Compute DEK. * msg-dek = MAC (msg-mac) using DEK subkey */ c->dek_len = mac_size (m->mac); if (c->dek_len <= 0) { return (m_msg_set_err (m, EMUNGE_SNAFU, strdupf ("Failed to determine DEK key length for MAC type %d", m->mac))); } assert (c->dek_len <= sizeof (c->dek)); n = c->dek_len; if (mac_block (m->mac, conf->dek_key, conf->dek_key_len, c->dek, &n, c->mac, c->mac_len) < 0) { return (m_msg_set_err (m, EMUNGE_SNAFU, strdup ("Failed to compute DEK"))); } assert (n <= c->dek_len); assert (n >= cipher_key_size (m->cipher)); /* Allocate memory for plaintext. * Ensure enough space by allocating an additional cipher block. */ n = cipher_block_size (m->cipher); if (n <= 0) { return (m_msg_set_err (m, EMUNGE_SNAFU, strdupf ("Failed to determine block size for cipher type %d", m->cipher))); } buf_len = c->inner_len + n; if (!(buf = malloc (buf_len))) { return (m_msg_set_err (m, EMUNGE_NO_MEMORY, NULL)); } /* Decrypt "inner" data. */ if (cipher_init (&x, m->cipher, c->dek, c->iv, CIPHER_DECRYPT) < 0) { goto err; } buf_ptr = buf; n_written = 0; n = buf_len; if (cipher_update (&x, buf_ptr, &n, c->inner, c->inner_len) < 0) { goto err_cleanup; } buf_ptr += n; n_written += n; n = buf_len - n_written; if (cipher_final (&x, buf_ptr, &n) < 0) { /* Set but defer error until dec_validate_mac(). */ m_msg_set_err (m, EMUNGE_CRED_INVALID, NULL); } buf_ptr += n; n_written += n; if (cipher_cleanup (&x) < 0) { goto err; } assert (n_written <= buf_len); /* Replace "inner" ciphertext with plaintext. */ assert (c->inner_mem == NULL); assert (c->inner_mem_len == 0); c->inner_mem = buf; c->inner_mem_len = buf_len; c->inner = buf; c->inner_len = n_written; return (0); err_cleanup: cipher_cleanup (&x); err: memset (buf, 0, buf_len); free (buf); return (m_msg_set_err (m, EMUNGE_SNAFU, strdup ("Failed to decrypt credential"))); } static int dec_validate_mac (munge_cred_t c) { /* Validates the Message Authentication Code (MAC) over the entire message * (ie, both "outer" and "inner" data). */ m_msg_t m = c->msg; mac_ctx x; /* message auth code context */ unsigned char mac[MAX_MAC]; /* message authentication code */ int n; /* all-purpose int */ /* Compute MAC. */ if (mac_init (&x, m->mac, conf->mac_key, conf->mac_key_len) < 0) { goto err; } if (mac_update (&x, c->outer, c->outer_len) < 0) { goto err_cleanup; } if (mac_update (&x, c->inner, c->inner_len) < 0) { goto err_cleanup; } n = sizeof (mac); if (mac_final (&x, mac, &n) < 0) { goto err_cleanup; } if (mac_cleanup (&x) < 0) { goto err; } assert (n <= sizeof (mac)); /* Validate new computed MAC against old received MAC. */ if ((n != c->mac_len) || (crypto_memcmp (mac, c->mac, c->mac_len) != 0)) { return (m_msg_set_err (m, EMUNGE_CRED_INVALID, NULL)); } /* Ensure an invalid cred error from before is caught * (if it wasn't somehow already caught by the MAC validation). */ if (m->error_num != EMUNGE_SUCCESS) { return (-1); } return (0); err_cleanup: mac_cleanup (&x); err: return (m_msg_set_err (m, EMUNGE_SNAFU, strdup ("Failed to MAC credential"))); } static int dec_decompress (munge_cred_t c) { /* Decompresses the "inner" credential data. */ m_msg_t m = c->msg; unsigned char *buf; /* decompression buffer */ int buf_len; /* length of decompression buffer */ int n; /* length of decompressed data */ /* Is this credential compressed? */ if (m->zip == MUNGE_ZIP_NONE) { return (0); } /* Compression type already checked by dec_unpack_outer(). */ assert (zip_is_valid_type (m->zip)); /* * Allocate memory for decompressed "inner" data. */ buf = NULL; buf_len = zip_decompress_length (m->zip, c->inner, c->inner_len); if (buf_len <= 0) { goto err; } if (!(buf = malloc (buf_len))) { m_msg_set_err (m, EMUNGE_NO_MEMORY, NULL); goto err; } /* Decompress "inner" data. */ n = buf_len; if (zip_decompress_block (m->zip, buf, &n, c->inner, c->inner_len) < 0) { return (m_msg_set_err (m, EMUNGE_CRED_INVALID, NULL)); } assert (n == buf_len); /* * Replace compressed data with "inner" data. */ if (c->inner_mem) { assert (c->inner_mem_len > 0); memset (c->inner_mem, 0, c->inner_mem_len); free (c->inner_mem); } c->inner_mem = buf; c->inner_mem_len = buf_len; c->inner = buf; c->inner_len = n; return (0); err: return (m_msg_set_err (m, EMUNGE_SNAFU, strdup ("Failed to decompress credential"))); } static int dec_unpack_inner (munge_cred_t c) { /* Unpacks the "inner" credential data from MSBF (ie, big endian) format. * The "inner" part of the credential may have been subjected to cryptographic * transformations (ie, compression and encryption). It includes: * salt, ip addr len, origin ip addr, encode time, ttl, uid, gid, * data length, and data (if present). * Validation of the "inner" credential occurs here as well since unpacking * may not be able to continue if an invalid field is found. * * Note that specific error messages are set here. My initial thought was * to return generic error messages here in order to ensure information was * not leaked that could help further an attack. But the MAC has already * been validated as this point, so it should be safe to be specific. */ m_msg_t m = c->msg; unsigned char *p; /* ptr into packed data */ int len; /* length of packed data remaining */ int n; /* all-purpose int */ uint32_t u; /* all-purpose uint32 */ assert (c->inner != NULL); /* Initialize. */ p = c->inner; len = c->inner_len; /* * Unpack the salt. * Add it to the PRNG entropy pool if it's encrypted. */ c->salt_len = MUNGE_CRED_SALT_LEN; assert (c->salt_len <= sizeof (c->salt)); if (c->salt_len > len) { return (m_msg_set_err (m, EMUNGE_BAD_CRED, strdup ("Truncated salt"))); } memcpy (c->salt, p, c->salt_len); if (m->cipher != MUNGE_CIPHER_NONE) { random_add (c->salt, c->salt_len); } p += c->salt_len; len -= c->salt_len; /* * Unpack the length of the origin IP address. */ n = sizeof (m->addr_len); assert (n == 1); if (n > len) { return (m_msg_set_err (m, EMUNGE_BAD_CRED, strdup ("Truncated origin IP addr length"))); } m->addr_len = *p; /* a single byte is always aligned */ p += n; len -= n; /* * Unpack the origin IP address. */ if (m->addr_len > len) { return (m_msg_set_err (m, EMUNGE_BAD_CRED, strdup ("Truncated origin IP addr"))); } else if (m->addr_len == 4) { assert (sizeof (m->addr) == 4); memcpy (&m->addr, p, m->addr_len); } else if (m->addr_len == 0) { memset (&m->addr, 0, sizeof (m->addr)); } else { return (m_msg_set_err (m, EMUNGE_BAD_CRED, strdup ("Invalid origin IP addr length"))); } p += m->addr_len; len -= m->addr_len; /* * Unpack the encode time. */ n = sizeof (m->time0); assert (n == 4); if (n > len) { return (m_msg_set_err (m, EMUNGE_BAD_CRED, strdup ("Truncated encode time"))); } memcpy (&u, p, n); /* ensure proper byte-alignment */ m->time0 = ntohl (u); p += n; len -= n; /* * Unpack the time-to-live. */ n = sizeof (m->ttl); assert (n == 4); if (n > len) { return (m_msg_set_err (m, EMUNGE_BAD_CRED, strdup ("Truncated time-to-live"))); } memcpy (&u, p, n); /* ensure proper byte-alignment */ m->ttl = ntohl (u); p += n; len -= n; /* * Unpack the UID. */ n = sizeof (m->cred_uid); assert (n == 4); if (n > len) { return (m_msg_set_err (m, EMUNGE_BAD_CRED, strdup ("Truncated UID"))); } memcpy (&u, p, n); /* ensure proper byte-alignment */ m->cred_uid = ntohl (u); p += n; len -= n; /* * Unpack the GID. */ n = sizeof (m->cred_gid); assert (n == 4); if (n > len) { return (m_msg_set_err (m, EMUNGE_BAD_CRED, strdup ("Truncated GID"))); } memcpy (&u, p, n); /* ensure proper byte-alignment */ m->cred_gid = ntohl (u); p += n; len -= n; /* * Unpack the UID restriction for authorization. */ n = sizeof (m->auth_uid); assert (n == 4); if (n > len) { return (m_msg_set_err (m, EMUNGE_BAD_CRED, strdup ("Truncated UID restriction"))); } memcpy (&u, p, n); /* ensure proper byte-alignment */ m->auth_uid = ntohl (u); p += n; len -= n; /* * Unpack the GID restriction for authorization. */ n = sizeof (m->auth_gid); assert (n == 4); if (n > len) { return (m_msg_set_err (m, EMUNGE_BAD_CRED, strdup ("Truncated GID restriction"))); } memcpy (&u, p, n); /* ensure proper byte-alignment */ m->auth_gid = ntohl (u); p += n; len -= n; /* * Unpack the length of auxiliary data. */ n = sizeof (m->data_len); assert (n == 4); if (n > len) { return (m_msg_set_err (m, EMUNGE_BAD_CRED, strdup ("Truncated data length"))); } memcpy (&u, p, n); /* ensure proper byte-alignment */ m->data_len = ntohl (u); p += n; len -= n; /* * Unpack the auxiliary data (if present). * The 'data' memory is owned by the cred struct, so it will be * free()d by cred_destroy() called from dec_process_msg(). */ if (m->data_len > 0) { if (m->data_len > len) { return (m_msg_set_err (m, EMUNGE_BAD_CRED, strdup ("Truncated data"))); } m->data = p; /* data resides in (inner|outer)_mem */ p += m->data_len; len -= m->data_len; m->data_is_copy = 1; } else { m->data = NULL; } assert (len == 0); return (0); } static int dec_validate_auth (munge_cred_t c) { /* Validates whether the client is authorized to view this credential. * But allow root to decode any credential if so configured. */ m_msg_t m = c->msg; if ( (m->auth_uid != MUNGE_UID_ANY) && (m->auth_uid != m->client_uid) && (! (conf->got_root_auth && (m->client_uid == 0)))) { goto unauthorized; } if (m->auth_gid == MUNGE_GID_ANY) { return (0); } else if (m->auth_gid == m->client_gid) { return (0); } else if (gids_is_member (conf->gids, m->client_uid, m->auth_gid)) { return (0); } unauthorized: return (m_msg_set_err (m, EMUNGE_CRED_UNAUTHORIZED, strdupf ("Unauthorized credential for client UID=%u GID=%u", (unsigned int) m->client_uid, (unsigned int) m->client_gid))); } static int dec_validate_time (munge_cred_t c) { /* Validates whether this credential has been generated within an * acceptable time interval. */ m_msg_t m = c->msg; int skew; /* negative clock skew for rewind */ time_t tmin; /* min decode time_t, else rewound */ time_t tmax; /* max decode time_t, else expired */ /* Bound the cred's ttl by the configuration's max ttl. */ if (m->ttl > conf->max_ttl) { m->ttl = conf->max_ttl; } /* Even if no clock skew is allowed, allow the cred's timestamp to be * "rewound" by up to 1 second. Without this, we were seeing an * occasional EMUNGE_CRED_REWOUND in spite of NTP's best efforts. */ skew = (conf->got_clock_skew) ? m->ttl : 1; tmin = m->time0 - skew; tmax = m->time0 + m->ttl; /* * Check the decode time against the allowable min & max. */ if (m->time1 < tmin) { return (m_msg_set_err (m, EMUNGE_CRED_REWOUND, NULL)); } if (m->time1 > tmax) { return (m_msg_set_err (m, EMUNGE_CRED_EXPIRED, NULL)); } return (0); } static int dec_validate_replay (munge_cred_t c) { /* Validates whether this credential has been replayed. */ m_msg_t m = c->msg; int rc; rc = replay_insert (c); if (rc == 0) { return (0); } if (rc > 0) { if ((conf->got_socket_retry) && (m->retry > 0) && (m->retry <= MUNGE_SOCKET_RETRY_ATTEMPTS)) { log_msg (LOG_INFO, "Allowed credential replay for client UID=%u GID=%u", (unsigned int) m->client_uid, (unsigned int) m->client_gid); return (0); } else { return (m_msg_set_err (m, EMUNGE_CRED_REPLAYED, NULL)); } } if (errno == ENOMEM) { return (m_msg_set_err (m, EMUNGE_NO_MEMORY, NULL)); } /* An EPERM error can only happen here if replay_insert() failed * because the replay hash is non-existent. And that can only * happen if replay_insert() was called after replay_fini(). * And that shouldn't happen. */ return (m_msg_set_err (m, EMUNGE_SNAFU, NULL)); } munge-munge-0.5.15/src/munged/dec.h000066400000000000000000000031161425467526100170150ustar00rootroot00000000000000/***************************************************************************** * Written by Chris Dunlap . * Copyright (C) 2007-2022 Lawrence Livermore National Security, LLC. * Copyright (C) 2002-2007 The Regents of the University of California. * UCRL-CODE-155910. * * This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE). * For details, see . * * MUNGE 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. Additionally for the MUNGE library (libmunge), you * can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation, * either version 3 of the License, or (at your option) any later version. * * MUNGE 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 * and GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * and GNU Lesser General Public License along with MUNGE. If not, see * . *****************************************************************************/ #ifndef MUNGE_DEC_H #define MUNGE_DEC_H #include "m_msg.h" int dec_process_msg (m_msg_t m); #endif /* !MUNGE_DEC_H */ munge-munge-0.5.15/src/munged/enc.c000066400000000000000000000556261425467526100170370ustar00rootroot00000000000000/***************************************************************************** * Written by Chris Dunlap . * Copyright (C) 2007-2022 Lawrence Livermore National Security, LLC. * Copyright (C) 2002-2007 The Regents of the University of California. * UCRL-CODE-155910. * * This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE). * For details, see . * * MUNGE 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. Additionally for the MUNGE library (libmunge), you * can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation, * either version 3 of the License, or (at your option) any later version. * * MUNGE 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 * and GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * and GNU Lesser General Public License along with MUNGE. If not, see * . *****************************************************************************/ #if HAVE_CONFIG_H # include "config.h" #endif /* HAVE_CONFIG_H */ #include #include /* include before in.h for bsd */ #include #include #include #include #include "auth_recv.h" #include "base64.h" #include "cipher.h" #include "conf.h" #include "cred.h" #include "enc.h" #include "log.h" #include "m_msg.h" #include "mac.h" #include "munge_defs.h" #include "random.h" #include "str.h" #include "zip.h" /***************************************************************************** * Static Prototypes *****************************************************************************/ static int enc_validate_msg (m_msg_t m); static int enc_init (munge_cred_t c); static int enc_authenticate (munge_cred_t c); static int enc_check_retry (munge_cred_t c); static int enc_timestamp (munge_cred_t c); static int enc_pack_outer (munge_cred_t c); static int enc_pack_inner (munge_cred_t c); static int enc_compress (munge_cred_t c); static int enc_mac (munge_cred_t c); static int enc_encrypt (munge_cred_t c); static int enc_armor (munge_cred_t c); static int enc_fini (munge_cred_t c); /***************************************************************************** * Extern Functions *****************************************************************************/ int enc_process_msg (m_msg_t m) { munge_cred_t c = NULL; /* aux data for processing this cred */ int rc = -1; /* return code */ if (enc_validate_msg (m) < 0) ; else if (!(c = cred_create (m))) ; else if (enc_init (c) < 0) ; else if (enc_authenticate (c) < 0) ; else if (enc_check_retry (c) < 0) ; else if (enc_timestamp (c) < 0) ; else if (enc_pack_outer (c) < 0) ; else if (enc_pack_inner (c) < 0) ; else if (enc_compress (c) < 0) ; else if (enc_mac (c) < 0) ; else if (enc_encrypt (c) < 0) ; else if (enc_armor (c) < 0) ; else if (enc_fini (c) < 0) ; else /* success */ rc = 0; /* Since the same m_msg struct is used for both the request and response, * the response message data must be sanitized for most errors. */ if (rc != 0) { m_msg_reset (m); } if (m_msg_send (m, MUNGE_MSG_ENC_RSP, 0) != EMUNGE_SUCCESS) { rc = -1; } cred_destroy (c); return (rc); } /***************************************************************************** * Static Functions *****************************************************************************/ static int enc_validate_msg (m_msg_t m) { /* Validates message types, setting defaults and limits as needed. */ assert (m != NULL); assert (m->type == MUNGE_MSG_ENC_REQ); /* Validate cipher type. */ if (m->cipher == MUNGE_CIPHER_DEFAULT) { m->cipher = conf->def_cipher; } else if (m->cipher == MUNGE_CIPHER_NONE) { ; /* disable encryption */ } else if (cipher_map_enum (m->cipher, NULL) < 0) { return (m_msg_set_err (m, EMUNGE_BAD_CIPHER, strdupf ("Invalid cipher type %d", m->cipher))); } /* Validate message authentication code type. * Note that MUNGE_MAC_NONE is not valid -- MACs are REQUIRED! */ if (m->mac == MUNGE_MAC_DEFAULT) { m->mac = conf->def_mac; } else if (mac_map_enum (m->mac, NULL) < 0) { return (m_msg_set_err (m, EMUNGE_BAD_MAC, strdupf ("Invalid MAC type %d", m->mac))); } assert (m->mac != MUNGE_MAC_NONE); /* * Validate the message authentication code type against the cipher type * to ensure the HMAC will generate a DEK of sufficient length for the * cipher. */ if (mac_size (m->mac) < cipher_key_size (m->cipher)) { return (m_msg_set_err (m, EMUNGE_BAD_MAC, strdupf ("Invalid MAC type %d with cipher type %d", m->mac, m->cipher))); } /* Validate compression type. * Disable compression if no optional data was specified. */ if (m->zip == MUNGE_ZIP_DEFAULT) { m->zip = conf->def_zip; } else if (m->zip == MUNGE_ZIP_NONE) { ; /* disable compression */ } else if (!zip_is_valid_type (m->zip)) { return (m_msg_set_err (m, EMUNGE_BAD_ZIP, strdupf ("Invalid compression type %d", m->zip))); } if (m->data_len == 0) { m->zip = MUNGE_ZIP_NONE; } /* Validate realm. * * FIXME: Validate realm and set default string if needed. * Validate that the realm string is NUL-terminated. */ /* Validate time-to-live. * Ensure it is bounded by the configuration's max ttl. * A sensible ttl is needed to allow a validated cred's * state to be flushed from the replay hash at some point. */ if (m->ttl == 0) { m->ttl = conf->def_ttl; } else if (m->ttl > conf->max_ttl) { m->ttl = conf->max_ttl; } return (0); } static int enc_init (munge_cred_t c) { /* Initializes state necessary for encoding a credential. */ m_msg_t m = c->msg; /* Generate salt. */ c->salt_len = MUNGE_CRED_SALT_LEN; random_pseudo_bytes (c->salt, c->salt_len); /* Generate cipher initialization vector (if needed). */ if (m->cipher == MUNGE_CIPHER_NONE) { c->iv_len = 0; } else { c->iv_len = cipher_iv_size (m->cipher); if (c->iv_len < 0) { return (m_msg_set_err (m, EMUNGE_SNAFU, strdupf ("Failed to determine IV length for cipher type %d", m->cipher))); } if (c->iv_len > 0) { assert (c->iv_len <= sizeof (c->iv)); random_pseudo_bytes (c->iv, c->iv_len); } } return (0); } static int enc_authenticate (munge_cred_t c) { /* Ascertains the UID/GID of the client process. */ m_msg_t m = c->msg; uid_t *p_uid; gid_t *p_gid; p_uid = (uid_t *) &(m->client_uid); p_gid = (gid_t *) &(m->client_gid); /* Determine identity of client process. */ if (auth_recv (m, p_uid, p_gid) != EMUNGE_SUCCESS) { return (m_msg_set_err (m, EMUNGE_SNAFU, strdup ("Failed to determine client identity"))); } return (0); } static int enc_check_retry (munge_cred_t c) { /* Checks whether the transaction is being retried. */ m_msg_t m = c->msg; if (m->retry > 0) { log_msg (LOG_INFO, "Encode retry #%d for client UID=%u GID=%u", m->retry, (unsigned int) m->client_uid, (unsigned int) m->client_gid); } if (m->retry > MUNGE_SOCKET_RETRY_ATTEMPTS) { return (m_msg_set_err (m, EMUNGE_SOCKET, strdupf ("Exceeded maximum number of encode attempts"))); } return (0); } static int enc_timestamp (munge_cred_t c) { /* Queries the current time. */ m_msg_t m = c->msg; time_t now; /* Set the "encode" time. */ if (time (&now) == ((time_t) -1)) { return (m_msg_set_err (m, EMUNGE_SNAFU, strdup ("Failed to query current time"))); } m->time0 = now; /* potential 64b value for 32b var */ m->time1 = 0; return (0); } static int enc_pack_outer (munge_cred_t c) { /* Packs the "outer" credential data into MSBF (ie, big endian) format. * The "outer" part of the credential does not undergo cryptographic * transformations (ie, compression and encryption). It includes: * cred version, cipher type, mac type, compression type, realm length, * unterminated realm string (if realm_len > 0), and the cipher's * initialization vector (if encrypted). */ m_msg_t m = c->msg; unsigned char *p; /* ptr into packed data */ assert (c->outer_mem == NULL); c->outer_mem_len += sizeof (c->version); c->outer_mem_len += sizeof (m->cipher); c->outer_mem_len += sizeof (m->mac); c->outer_mem_len += sizeof (m->zip); c->outer_mem_len += sizeof (m->realm_len); c->outer_mem_len += m->realm_len; c->outer_mem_len += c->iv_len; if (!(c->outer_mem = malloc (c->outer_mem_len))) { return (m_msg_set_err (m, EMUNGE_NO_MEMORY, NULL)); } p = c->outer = c->outer_mem; c->outer_len = c->outer_mem_len; assert (sizeof (c->version) == 1); *p = c->version; p += sizeof (c->version); assert (sizeof (m->cipher) == 1); *p = m->cipher; p += sizeof (m->cipher); assert (sizeof (m->mac) == 1); *p = m->mac; p += sizeof (m->mac); assert (sizeof (m->zip) == 1); c->outer_zip_ref = p; *p = m->zip; p += sizeof (m->zip); assert (sizeof (m->realm_len) == 1); *p = m->realm_len; p += sizeof (m->realm_len); if (m->realm_len > 0) { memcpy (p, m->realm_str, m->realm_len); p += m->realm_len; } if (c->iv_len > 0) { memcpy (p, c->iv, c->iv_len); p += c->iv_len; } assert (p == (c->outer + c->outer_len)); return (0); } static int enc_pack_inner (munge_cred_t c) { /* Packs the "inner" credential data into MSBF (ie, big endian) format. * The "inner" part of the credential may be subjected to cryptographic * transformations (ie, compression and encryption). It includes: * salt, ip addr len, origin ip addr, encode time, ttl, uid, gid, * data length, and data (if present). */ m_msg_t m = c->msg; unsigned char *p; /* ptr into packed data */ uint32_t u32; /* tmp for packing into MSBF */ assert (c->inner_mem == NULL); c->inner_mem_len += c->salt_len; c->inner_mem_len += sizeof (m->addr_len); c->inner_mem_len += sizeof (m->addr); c->inner_mem_len += sizeof (m->time0); c->inner_mem_len += sizeof (m->ttl); c->inner_mem_len += sizeof (m->client_uid); c->inner_mem_len += sizeof (m->client_gid); c->inner_mem_len += sizeof (m->auth_uid); c->inner_mem_len += sizeof (m->auth_gid); c->inner_mem_len += sizeof (m->data_len); c->inner_mem_len += m->data_len; if (!(c->inner_mem = malloc (c->inner_mem_len))) { return (m_msg_set_err (m, EMUNGE_NO_MEMORY, NULL)); } p = c->inner = c->inner_mem; c->inner_len = c->inner_mem_len; assert (c->salt_len > 0); memcpy (p, c->salt, c->salt_len); p += c->salt_len; assert (sizeof (m->addr_len) == 1); assert (sizeof (conf->addr) == sizeof (m->addr)); assert (sizeof (conf->addr) < 256); *p = m->addr_len = sizeof (m->addr); p += sizeof (m->addr_len); memcpy (p, &conf->addr, sizeof (m->addr)); p += sizeof (m->addr); assert (sizeof (m->time0) == 4); u32 = htonl (m->time0); memcpy (p, &u32, sizeof (m->time0)); p += sizeof (m->time0); assert (sizeof (m->ttl) == 4); u32 = htonl (m->ttl); memcpy (p, &u32, sizeof (m->ttl)); p += sizeof (m->ttl); assert (sizeof (m->client_uid) == 4); u32 = htonl (m->client_uid); memcpy (p, &u32, sizeof (m->client_uid)); p += sizeof (m->client_uid); assert (sizeof (m->client_gid) == 4); u32 = htonl (m->client_gid); memcpy (p, &u32, sizeof (m->client_gid)); p += sizeof (m->client_gid); assert (sizeof (m->auth_uid) == 4); u32 = htonl (m->auth_uid); memcpy (p, &u32, sizeof (m->auth_uid)); p += sizeof (m->auth_uid); assert (sizeof (m->auth_gid) == 4); u32 = htonl (m->auth_gid); memcpy (p, &u32, sizeof (m->auth_gid)); p += sizeof (m->auth_gid); assert (sizeof (m->data_len) == 4); u32 = htonl (m->data_len); memcpy (p, &u32, sizeof (m->data_len)); p += sizeof (m->data_len); if (m->data_len > 0) { memcpy (p, m->data, m->data_len); p += m->data_len; } assert (p == (c->inner + c->inner_len)); return (0); } static int enc_compress (munge_cred_t c) { /* Compresses the "inner" credential data. * If the compressed data is larger than the original data, the * compressed buffer is discarded and compression is disabled. * This requires resetting the compression type in the credential's * "outer" data header. And since that field is included in the MAC, * compression must be attempted before the MAC is computed. */ m_msg_t m = c->msg; unsigned char *buf; /* compression buffer */ int buf_len; /* length of compression buffer */ int n; /* length of compressed data */ /* Is compression disabled? */ if (m->zip == MUNGE_ZIP_NONE) { return (0); } /* Allocate memory for compressed "inner" data. */ buf = NULL; buf_len = zip_compress_length (m->zip, c->inner, c->inner_len); if (buf_len < 0) { goto err; } if (!(buf = malloc (buf_len))) { m_msg_set_err (m, EMUNGE_NO_MEMORY, NULL); goto err; } /* Compress "inner" data. */ n = buf_len; if (zip_compress_block (m->zip, buf, &n, c->inner, c->inner_len) < 0) { goto err; } /* Disable compression and discard compressed data if it's larger. * Replace "inner" data with compressed data if it's not. */ if (n >= c->inner_len) { m->zip = MUNGE_ZIP_NONE; *c->outer_zip_ref = m->zip; memset (buf, 0, buf_len); free (buf); } else { assert (c->inner_mem_len > 0); memset (c->inner_mem, 0, c->inner_mem_len); free (c->inner_mem); c->inner_mem = buf; c->inner_mem_len = buf_len; c->inner = buf; c->inner_len = n; } return (0); err: if ((buf_len > 0) && (buf != NULL)) { memset (buf, 0, buf_len); free (buf); } return (m_msg_set_err (m, EMUNGE_SNAFU, strdup ("Failed to compress credential"))); } static int enc_mac (munge_cred_t c) { /* Computes the Message Authentication Code (MAC) over the entire message * (ie, both "outer" and "inner" data). */ m_msg_t m = c->msg; mac_ctx x; /* message auth code context */ int n; /* all-purpose int */ /* Init MAC. */ c->mac_len = mac_size (m->mac); if (c->mac_len <= 0) { return (m_msg_set_err (m, EMUNGE_SNAFU, strdupf ("Failed to determine digest length for MAC type %d", m->mac))); } assert (c->mac_len <= sizeof (c->mac)); memset (c->mac, 0, c->mac_len); /* Compute MAC. */ if (mac_init (&x, m->mac, conf->mac_key, conf->mac_key_len) < 0) { goto err; } if (mac_update (&x, c->outer, c->outer_len) < 0) { goto err_cleanup; } if (mac_update (&x, c->inner, c->inner_len) < 0) { goto err_cleanup; } n = c->mac_len; if (mac_final (&x, c->mac, &n) < 0) { goto err_cleanup; } if (mac_cleanup (&x) < 0) { goto err; } assert (n == c->mac_len); return (0); err_cleanup: mac_cleanup (&x); err: return (m_msg_set_err (m, EMUNGE_SNAFU, strdup ("Failed to MAC credential"))); } static int enc_encrypt (munge_cred_t c) { /* Encrypts the "inner" credential data. */ m_msg_t m = c->msg; int buf_len; /* length of ciphertext buffer */ unsigned char *buf; /* ciphertext buffer */ unsigned char *buf_ptr; /* ptr into ciphertext buffer */ cipher_ctx x; /* cipher context */ int n_written; /* number of bytes written to buf */ int n; /* all-purpose int */ /* Is encryption disabled? */ if (m->cipher == MUNGE_CIPHER_NONE) { return (0); } /* Compute DEK. * msg-dek = MAC (msg-mac) using DEK subkey */ c->dek_len = mac_size (m->mac); if (c->dek_len <= 0) { return (m_msg_set_err (m, EMUNGE_SNAFU, strdupf ("Failed to determine DEK key length for MAC type %d", m->mac))); } assert (c->dek_len <= sizeof (c->dek)); n = c->dek_len; if (mac_block (m->mac, conf->dek_key, conf->dek_key_len, c->dek, &n, c->mac, c->mac_len) < 0) { return (m_msg_set_err (m, EMUNGE_SNAFU, strdup ("Failed to compute DEK"))); } assert (n <= c->dek_len); assert (n >= cipher_key_size (m->cipher)); /* Allocate memory for ciphertext. * Ensure enough space by allocating an additional cipher block. */ n = cipher_block_size (m->cipher); if (n <= 0) { return (m_msg_set_err (m, EMUNGE_SNAFU, strdupf ("Failed to determine block size for cipher type %d", m->cipher))); } buf_len = c->inner_len + n; if (!(buf = malloc (buf_len))) { return (m_msg_set_err (m, EMUNGE_NO_MEMORY, NULL)); } /* Encrypt "inner" data. */ if (cipher_init (&x, m->cipher, c->dek, c->iv, CIPHER_ENCRYPT) < 0) { goto err; } buf_ptr = buf; n_written = 0; n = buf_len; if (cipher_update (&x, buf_ptr, &n, c->inner, c->inner_len) < 0) { goto err_cleanup; } buf_ptr += n; n_written += n; n = buf_len - n_written; if (cipher_final (&x, buf_ptr, &n) < 0) { goto err_cleanup; } buf_ptr += n; n_written += n; if (cipher_cleanup (&x) < 0) { goto err; } assert (n_written <= buf_len); /* Replace "inner" plaintext with ciphertext. */ assert (c->inner_mem_len > 0); memset (c->inner_mem, 0, c->inner_mem_len); free (c->inner_mem); c->inner_mem = buf; c->inner_mem_len = buf_len; c->inner = buf; c->inner_len = n_written; return (0); err_cleanup: cipher_cleanup (&x); err: memset (buf, 0, buf_len); free (buf); return (m_msg_set_err (m, EMUNGE_SNAFU, strdup ("Failed to encrypt credential"))); } static int enc_armor (munge_cred_t c) { /* Armors the credential allowing it to be sent over virtually any transport. * The armor consists of PREFIX + BASE64 [ OUTER + MAC + INNER ] + SUFFIX. */ m_msg_t m = c->msg; int prefix_len; /* prefix string length */ int suffix_len; /* prefix string length */ int buf_len; /* length of armor'd data buffer */ unsigned char *buf; /* armor'd data buffer */ unsigned char *buf_ptr; /* ptr into armor'd data buffer */ base64_ctx x; /* base64 context */ int n, n2; /* all-purpose ints */ prefix_len = strlen (MUNGE_CRED_PREFIX); suffix_len = strlen (MUNGE_CRED_SUFFIX); /* Allocate memory for armor'd data. */ n = c->outer_len + c->mac_len + c->inner_len; buf_len = prefix_len + base64_encode_length (n) + suffix_len; if (!(buf = malloc (buf_len))) { return (m_msg_set_err (m, EMUNGE_NO_MEMORY, NULL)); } buf_ptr = buf; /* Add the prefix string. */ if (prefix_len > 0) { strcpy ((char *) buf_ptr, MUNGE_CRED_PREFIX); /* strcpy() safe here */ buf_ptr += prefix_len; } /* Base64-encode the chewy-internals of the credential. * The data will be NUL-terminated by in the process. */ if (base64_init (&x) < 0) { goto err; } n = 0; if (base64_encode_update (&x, buf_ptr, &n2, c->outer, c->outer_len) < 0) { goto err_cleanup; } buf_ptr += n2; n += n2; if (base64_encode_update (&x, buf_ptr, &n2, c->mac, c->mac_len) < 0) { goto err_cleanup; } buf_ptr += n2; n += n2; if (base64_encode_update (&x, buf_ptr, &n2, c->inner, c->inner_len) < 0) { goto err_cleanup; } buf_ptr += n2; n += n2; if (base64_encode_final (&x, buf_ptr, &n2) < 0) { goto err_cleanup; } buf_ptr += n2; n += n2; if (base64_cleanup (&x) < 0) { goto err; } n++; /* count the terminating NUL char */ /* Add the suffix string. */ if (suffix_len > 0) { strcpy ((char *) buf_ptr, MUNGE_CRED_SUFFIX); /* strcpy() safe here */ buf_ptr += suffix_len; } assert ((buf_ptr - buf) < buf_len); /* Replace "outer+inner" data with armor'd data. */ assert (c->outer_mem_len > 0); memset (c->outer_mem, 0, c->outer_mem_len); free (c->outer_mem); c->outer_mem = buf; c->outer_mem_len = buf_len; c->outer = buf; c->outer_len = buf_ptr - buf + 1; assert (c->inner_mem_len > 0); memset (c->inner_mem, 0, c->inner_mem_len); free (c->inner_mem); c->inner_mem = NULL; c->inner_mem_len = 0; return (0); err_cleanup: base64_cleanup (&x); err: memset (buf, 0, buf_len); free (buf); return (m_msg_set_err (m, EMUNGE_SNAFU, strdup ("Failed to base64-encode credential"))); } static int enc_fini (munge_cred_t c) { /* Finalizes encoding a credential, ensuring it is ready for transit. */ m_msg_t m = c->msg; /* Free any "request data". */ if (m->data) { assert (m->data_len > 0); assert (m->data_is_copy == 0); free (m->data); } /* Place credential in message "data" payload for transit. * This memory is still owned by the cred struct, so it will be * free()d by cred_destroy() called from enc_process_msg(). */ m->data = c->outer; m->data_len = c->outer_len; m->data_is_copy = 1; return (0); } munge-munge-0.5.15/src/munged/enc.h000066400000000000000000000031161425467526100170270ustar00rootroot00000000000000/***************************************************************************** * Written by Chris Dunlap . * Copyright (C) 2007-2022 Lawrence Livermore National Security, LLC. * Copyright (C) 2002-2007 The Regents of the University of California. * UCRL-CODE-155910. * * This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE). * For details, see . * * MUNGE 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. Additionally for the MUNGE library (libmunge), you * can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation, * either version 3 of the License, or (at your option) any later version. * * MUNGE 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 * and GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * and GNU Lesser General Public License along with MUNGE. If not, see * . *****************************************************************************/ #ifndef MUNGE_ENC_H #define MUNGE_ENC_H #include "m_msg.h" int enc_process_msg (m_msg_t m); #endif /* !MUNGE_ENC_H */ munge-munge-0.5.15/src/munged/gids.c000066400000000000000000000656101425467526100172120ustar00rootroot00000000000000/***************************************************************************** * Written by Chris Dunlap . * Copyright (C) 2007-2022 Lawrence Livermore National Security, LLC. * Copyright (C) 2002-2007 The Regents of the University of California. * UCRL-CODE-155910. * * This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE). * For details, see . * * MUNGE 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. Additionally for the MUNGE library (libmunge), you * can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation, * either version 3 of the License, or (at your option) any later version. * * MUNGE 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 * and GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * and GNU Lesser General Public License along with MUNGE. If not, see * . ***************************************************************************** * Refer to "gids.h" for documentation on public functions. *****************************************************************************/ #if HAVE_CONFIG_H # include "config.h" #endif /* HAVE_CONFIG_H */ #include /* include before grp.h for bsd */ #include #include #include #include #include #include #include #include #include #include "common.h" #include "conf.h" #include "gids.h" #include "hash.h" #include "log.h" #include "munge_defs.h" #include "timer.h" #include "xgetgr.h" #include "xgetpw.h" /***************************************************************************** * Notes ***************************************************************************** * * The gid_hash is used to quickly lookup whether a given UID is a member of a * particular supplementary group GID. It contains a gid_head for each UID * pointing to a singly-linked list of gid_nodes for each supplementary group * of which that UID is a member. The list of gid_nodes is sorted in * increasing order of GIDs without duplicates. This hash is constructed * outside of the gids mutex, and switched in while the mutex is held during * an update to replace the old gid_hash. * * The uid_hash is used to cache positive & negative user lookups during * the construction of a gid_hash, after which it is destroyed. It contains * uid_nodes mapping a unique null-terminated user string to a UID. It is not * persistent across gid_hash updates. * * The ghost_hash is used to identify when a user first goes missing from the * passwd file in order for the event to be logged only once; if the user is * later added, the next gid_hash update will clear this user from the * ghost_hash thereby allowing the event to be re-logged should the user * disappear again. This hash contains unique null-terminated user strings * from calls to xgetpwnam() that fail with ENOENT. Users are added when * xgetpwnam() fails, and removed when xgetpwnam() succeeds. A mutex is not * needed when accessing this hash. It is persistent across gid_hash updates. * * The use of non-reentrant passwd/group functions (i.e., getpwnam & getgrent) * here should not cause problems since they are only called in/from * _gids_map_create(), and only one instance of that routine can be running at * a time. However, crashes have been traced to the use of getgrent() here * (Issue #2) so the reentrant functions are now used. */ /***************************************************************************** * Constants *****************************************************************************/ #define GHOST_HASH_SIZE 1031 #define GID_HASH_SIZE 2053 #define UID_HASH_SIZE 4099 #ifndef _GIDS_DEBUG #define _GIDS_DEBUG 0 #endif /* !_GIDS_DEBUG */ /***************************************************************************** * Data Types *****************************************************************************/ struct gids { pthread_mutex_t mutex; /* mutex for accessing struct */ hash_t gid_hash; /* hash of GIDs mappings */ hash_t ghost_hash; /* hash of missing users (ghosts!) */ long timer; /* timer ID for next GIDs map update */ int interval_secs; /* seconds between GIDs map updates */ int do_group_stat; /* true if updates stat group file */ time_t t_last_update; /* time of last good GIDs map update */ }; struct gid_head { struct gid_node *next; uid_t uid; /* gid_hash key */ }; struct gid_node { struct gid_node *next; gid_t gid; }; struct uid_node { char *user; /* uid_hash key */ uid_t uid; }; typedef struct uid_node * uid_node_p; typedef struct gid_node * gid_node_p; typedef struct gid_head * gid_head_p; /***************************************************************************** * Prototypes *****************************************************************************/ static void _gids_map_update (gids_t gids); static hash_t _gids_map_create (hash_t ghost_hash); static int _gids_user_to_uid (hash_t uid_hash, hash_t ghost_hash, const char *user, uid_t *uid_resultp, xpwbuf_p pwbufp); static int _gids_gid_add (hash_t gid_hash, uid_t uid, gid_t gid); static int _gids_uid_add (hash_t uid_hash, const char *user, uid_t uid); static int _gids_ghost_add (hash_t ghost_hash, const char *user); static int _gids_ghost_del (hash_t ghost_hash, const char *user); static gid_head_p _gids_gid_head_create (uid_t uid); static void _gids_gid_head_destroy (gid_head_p g); static int _gids_gid_head_cmp ( const uid_t *uid1p, const uid_t *uid2p); static unsigned int _gids_gid_head_key (uid_t *uidp); static gid_node_p _gids_gid_node_create (gid_t gid); static uid_node_p _gids_uid_node_create (const char *user, uid_t uid); static void _gids_uid_node_destroy (uid_node_p u); #if _GIDS_DEBUG static void _gids_gid_hash_dump (hash_t gid_hash); static void _gids_gid_node_dump (gid_head_p g, const uid_t *uidp, const void *null); static void _gids_uid_hash_dump (hash_t uid_hash); static void _gids_uid_node_dump (uid_node_p u, const char *user, const void *null); static void _gids_ghost_hash_dump (hash_t ghost_hash); static void _gids_ghost_node_dump (const char *data, const char *user, const void *null); #endif /* _GIDS_DEBUG */ /***************************************************************************** * Public Functions *****************************************************************************/ gids_t gids_create (int interval_secs, int do_group_stat) { gids_t gids; if ((interval_secs < 0) || (conf->got_benchmark)) { log_msg (LOG_INFO, "Disabled supplementary group mapping"); return (NULL); } if (!(gids = malloc (sizeof (*gids)))) { log_errno (EMUNGE_NO_MEMORY, LOG_ERR, "Failed to allocate gids struct"); } if ((errno = pthread_mutex_init (&gids->mutex, NULL)) != 0) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to init gids mutex"); } gids->gid_hash = NULL; gids->ghost_hash = hash_create (GHOST_HASH_SIZE, (hash_key_f) hash_key_string, (hash_cmp_f) strcmp, (hash_del_f) free); if (!gids->ghost_hash) { log_errno (EMUNGE_NO_MEMORY, LOG_ERR, "Failed to allocate ghost hash"); } gids->timer = 0; gids->interval_secs = interval_secs; gids->do_group_stat = do_group_stat; gids->t_last_update = 0; gids_update (gids); if (interval_secs == 0) { log_msg (LOG_INFO, "Disabled updates to supplementary group mapping"); } else { log_msg (LOG_INFO, "Updating supplementary group mapping every %d second%s", interval_secs, (interval_secs == 1) ? "" : "s"); } log_msg (LOG_INFO, "%s supplementary group mtime check of \"%s\"", (do_group_stat ? "Enabled" : "Disabled"), GIDS_GROUP_FILE); return (gids); } void gids_destroy (gids_t gids) { if (!gids) { return; } if ((errno = pthread_mutex_lock (&gids->mutex)) != 0) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to lock gids mutex"); } if (gids->timer > 0) { timer_cancel (gids->timer); gids->timer = 0; } hash_destroy (gids->gid_hash); gids->gid_hash = NULL; hash_destroy (gids->ghost_hash); gids->ghost_hash = NULL; if ((errno = pthread_mutex_unlock (&gids->mutex)) != 0) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to unlock gids mutex"); } if ((errno = pthread_mutex_destroy (&gids->mutex)) != 0) { log_msg (LOG_ERR, "Failed to destroy gids mutex: %s", strerror (errno)); } free (gids); return; } void gids_update (gids_t gids) { if (!gids) { return; } if ((errno = pthread_mutex_lock (&gids->mutex)) != 0) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to lock gids mutex"); } /* Cancel a pending update before scheduling a new one. */ if (gids->timer > 0) { timer_cancel (gids->timer); } /* Compute the GIDs mapping in the background by setting an expired timer. */ gids->timer = timer_set_relative ((callback_f) _gids_map_update, gids, 0); if (gids->timer < 0) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to set gids update timer"); } /* Reset the do_group_stat flag in case it had been disabled on error * (ie, set to -1). */ gids->do_group_stat = !! gids->do_group_stat; if ((errno = pthread_mutex_unlock (&gids->mutex)) != 0) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to unlock gids mutex"); } return; } int gids_is_member (gids_t gids, uid_t uid, gid_t gid) { int is_member = 0; gid_head_p g; gid_node_p node; if (!gids) { return (0); } if ((errno = pthread_mutex_lock (&gids->mutex)) != 0) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to lock gids mutex"); } if ((gids->gid_hash) && (g = hash_find (gids->gid_hash, &uid))) { assert (g->uid == uid); for (node = g->next; node && node->gid <= gid; node = node->next) { if (node->gid == gid) { is_member = 1; break; } } } if ((errno = pthread_mutex_unlock (&gids->mutex)) != 0) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to unlock gids mutex"); } return (is_member); } /***************************************************************************** * Private Functions *****************************************************************************/ static void _gids_map_update (gids_t gids) { /* Update the GIDs mapping [gids] and schedule the next update. */ int do_group_stat; time_t t_last_update; time_t t_now; int do_update = 1; hash_t gid_hash = NULL; assert (gids != NULL); if ((errno = pthread_mutex_lock (&gids->mutex)) != 0) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to lock gids mutex"); } do_group_stat = gids->do_group_stat; t_last_update = gids->t_last_update; if ((errno = pthread_mutex_unlock (&gids->mutex)) != 0) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to unlock gids mutex"); } if (time (&t_now) == (time_t) -1) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to query current time"); } if (do_group_stat > 0) { struct stat st; /* On stat() error, disable future stat()s until reset via SIGHUP. */ if (stat (GIDS_GROUP_FILE, &st) < 0) { do_group_stat = -2; log_msg (LOG_ERR, "Failed to stat \"%s\": %s", GIDS_GROUP_FILE, strerror (errno)); } else if (st.st_mtime <= t_last_update) { do_update = 0; } } /* Update the GIDs mapping without holding the mutex. */ if (do_update) { gid_hash = _gids_map_create (gids->ghost_hash); } if ((errno = pthread_mutex_lock (&gids->mutex)) != 0) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to lock gids mutex"); } /* Replace the old GIDs mapping if the update was successful. */ if (gid_hash != NULL) { hash_t gid_hash_bak = gids->gid_hash; gids->gid_hash = gid_hash; gid_hash = gid_hash_bak; gids->t_last_update = t_now; } /* Change the GIDs do_group_stat flag only when the stat() first fails. * This is done by setting the local do_group_stat flag above to -2 on * error, but storing -1 in the gids struct here after the mutex is * re-acquired. By doing this, a SIGHUP triggered during * _gids_map_update() can still reset the flag. */ if (do_group_stat < -1) { gids->do_group_stat = -1; } /* Schedule the next GIDs map update (if applicable). */ gids->timer = 0; if (gids->interval_secs > 0) { gids->timer = timer_set_relative ((callback_f) _gids_map_update, gids, gids->interval_secs * 1000); if (gids->timer < 0) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to schedule gids map update"); } } if ((errno = pthread_mutex_unlock (&gids->mutex)) != 0) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to unlock gids mutex"); } /* Clean up the old hash now that the mutex has been released. */ if (gid_hash != NULL) { hash_destroy (gid_hash); } return; } static hash_t _gids_map_create (hash_t ghost_hash) { /* Create a new gid_hash to map UIDs to their supplementary groups. * Return a pointer to the new hash on success, or NULL on error. */ static size_t grbuflen = 0; static size_t pwbuflen = 0; hash_t gid_hash = NULL; hash_t uid_hash = NULL; struct timeval t_start; struct timeval t_stop; int do_group_db_close = 0; int num_inits = 0; const int max_inits = 16; struct group gr; xgrbuf_p grbufp = NULL; xpwbuf_p pwbufp = NULL; char **userp; uid_t uid; int n_users; double n_seconds; gid_hash = hash_create (GID_HASH_SIZE, (hash_key_f) _gids_gid_head_key, (hash_cmp_f) _gids_gid_head_cmp, (hash_del_f) _gids_gid_head_destroy); if (!gid_hash) { log_msg (LOG_ERR, "Failed to allocate gid hash"); goto err; } uid_hash = hash_create (UID_HASH_SIZE, (hash_key_f) hash_key_string, (hash_cmp_f) strcmp, (hash_del_f) _gids_uid_node_destroy); if (!uid_hash) { log_msg (LOG_ERR, "Failed to allocate uid hash"); goto err; } if (gettimeofday (&t_start, NULL) < 0) { log_msg (LOG_ERR, "Failed to query current time"); goto err; } /* Allocate memory for both the xgetgrent() and xgetpwnam() buffers here. * The xgetpwnam() buffer will be passed to _gids_user_to_uid() where it * is used, but allocating it here allows the same buffer to be reused * throughout a given gid_hash creation cycle. */ if (!(grbufp = xgetgrbuf_create (grbuflen))) { log_msg (LOG_ERR, "Failed to allocate group entry buffer"); goto err; } if (!(pwbufp = xgetpwbuf_create (pwbuflen))) { log_msg (LOG_ERR, "Failed to allocate passwd entry buffer"); goto err; } do_group_db_close = 1; restart: xgetgrent_init (); num_inits++; while (1) { if (xgetgrent (&gr, grbufp) < 0) { if (errno == ENOENT) { break; } if (errno == EINTR) { continue; } if ((errno == ERANGE) && (num_inits < max_inits)) { hash_reset (gid_hash); goto restart; } log_msg (LOG_ERR, "Failed to query group info: %s", strerror (errno)); goto err; } /* gr_mem is a null-terminated array of pointers to the * null-terminated user strings belonging to the group. */ for (userp = gr.gr_mem; userp && *userp; userp++) { int rv = _gids_user_to_uid (uid_hash, ghost_hash, *userp, &uid, pwbufp); if (rv == 0) { if (_gids_gid_add (gid_hash, uid, gr.gr_gid) < 0) { goto err; } } } } xgetgrent_fini (); /* * Record the final size of the xgetpwnam() and xgetgrent() buffers. * This allows subsequent scans to start with buffers that will * generally not need to be realloc()d. */ pwbuflen = xgetpwbuf_get_len (pwbufp); xgetpwbuf_destroy (pwbufp); grbuflen = xgetgrbuf_get_len (grbufp); xgetgrbuf_destroy (grbufp); if (gettimeofday (&t_stop, NULL) < 0) { log_msg (LOG_ERR, "Failed to query current time"); goto err; } #if _GIDS_DEBUG _gids_uid_hash_dump (uid_hash); _gids_gid_hash_dump (gid_hash); _gids_ghost_hash_dump (ghost_hash); #endif /* _GIDS_DEBUG */ n_users = hash_count (gid_hash); if (n_users < 0) { log_err (EMUNGE_SNAFU, LOG_ERR, "Failed _gids_map_create: Invalid gid hash ptr"); } n_seconds = (t_stop.tv_sec - t_start.tv_sec) + ((t_stop.tv_usec - t_start.tv_usec) / 1e6); log_msg (LOG_INFO, "Found %d user%s with supplementary groups in %0.3f seconds", n_users, ((n_users == 1) ? "" : "s"), n_seconds); hash_destroy (uid_hash); return (gid_hash); err: if (do_group_db_close) { xgetgrent_fini (); } if (pwbufp != NULL) { xgetpwbuf_destroy (pwbufp); } if (grbufp != NULL) { xgetgrbuf_destroy (grbufp); } if (uid_hash != NULL) { hash_destroy (uid_hash); } if (gid_hash != NULL) { hash_destroy (gid_hash); } return (NULL); } static int _gids_user_to_uid (hash_t uid_hash, hash_t ghost_hash, const char *user, uid_t *uid_resultp, xpwbuf_p pwbufp) { /* Lookup the UID of [user]. * [pwbufp] is a pre-allocated buffer for xgetpwnam() (see above comments). * Set [*uid_resultp] (if non-NULL), and return 0 on success or -1 on error. */ uid_node_p u; uid_t uid = UID_SENTINEL; struct passwd pw; if ((u = hash_find (uid_hash, user))) { uid = u->uid; } else if (xgetpwnam (user, &pw, pwbufp) == 0) { uid = pw.pw_uid; (void) _gids_uid_add (uid_hash, user, uid); (void) _gids_ghost_del (ghost_hash, user); } else if (errno == ENOENT) { (void) _gids_uid_add (uid_hash, user, uid); if (!hash_find (ghost_hash, user)) { (void) _gids_ghost_add (ghost_hash, user); log_msg (LOG_INFO, "Failed to query passwd file for \"%s\": User not found", user); } } else { log_msg (LOG_INFO, "Failed to query passwd file for \"%s\": %s", user, strerror (errno)); } if (uid == UID_SENTINEL) { return (-1); } if (uid_resultp != NULL) { *uid_resultp = uid; } return (0); } static int _gids_gid_add (hash_t gid_hash, uid_t uid, gid_t gid) { /* Add supplementary group [gid] for user [uid] to the GIDs map [gid_hash]. * Return 1 if the entry was added, 0 if the entry already exists, * or -1 on error. */ gid_head_p g; gid_node_p node; gid_node_p *nodep; if (!(g = hash_find (gid_hash, &uid))) { if (!(g = _gids_gid_head_create (uid))) { log_msg (LOG_WARNING, "Failed to allocate gid head for uid=%u", (unsigned int) uid); return (-1); } if (!hash_insert (gid_hash, &g->uid, g)) { log_msg (LOG_WARNING, "Failed to insert gid head for uid=%u into gid hash", (unsigned int) uid); _gids_gid_head_destroy (g); return (-1); } } assert (g->uid == uid); nodep = &g->next; while ((*nodep) && ((*nodep)->gid < gid)) { nodep = &(*nodep)->next; } if ((*nodep) && ((*nodep)->gid == gid)) { return (0); } if (!(node = _gids_gid_node_create (gid))) { log_msg (LOG_WARNING, "Failed to allocate gid node for uid=%u gid=%u", (unsigned int) uid, (unsigned int) gid); return (-1); } node->next = *nodep; *nodep = node; return (1); } static int _gids_uid_add (hash_t uid_hash, const char *user, uid_t uid) { /* Add mapping from [user] to [uid] to the hash [uid_hash]. * This assumes [user] does not already exist in the hash. * Return 0 on success, or -1 on error. */ uid_node_p u; if (!(u = _gids_uid_node_create (user, uid))) { log_msg (LOG_WARNING, "Failed to allocate uid node for \"%s\" uid=%u", user, (unsigned int) uid); } else if (!hash_insert (uid_hash, u->user, u)) { log_msg (LOG_WARNING, "Failed to insert uid node for \"%s\" uid=%u into uid hash", user, (unsigned int) uid); _gids_uid_node_destroy (u); } else { return (0); } return (-1); } static int _gids_ghost_add (hash_t ghost_hash, const char *user) { /* Add [user] to the [ghost_hash]. * Return 0 on success, or -1 on error. */ char *p; if (!user) { errno = EINVAL; } else if (!(p = strdup (user))) { log_msg (LOG_WARNING, "Failed to copy string for \"%s\": %s", user, strerror (errno)); } else if (!hash_insert (ghost_hash, p, p)) { log_msg (LOG_WARNING, "Failed to insert \"%s\" into ghost hash", user); free (p); } else { return (0); } return (-1); } static int _gids_ghost_del (hash_t ghost_hash, const char *user) { /* Remove [user] from the [ghost_hash]. * Return 1 if the entry was removed, 0 if the entry was not found, * or -1 on error. */ char *p; if (!user) { errno = EINVAL; return (-1); } p = hash_remove (ghost_hash, user); if (p == NULL) { return (0); } free (p); return (1); } static gid_head_p _gids_gid_head_create (uid_t uid) { /* Allocate and return a gid_head for [uid], or NULL on error. */ gid_head_p g; if (!(g = malloc (sizeof (*g)))) { return (NULL); } g->next = NULL; g->uid = uid; return (g); } static void _gids_gid_head_destroy (gid_head_p g) { /* De-allocate the gid_head [g] and gid_node chain. */ gid_node_p node, node_tmp; if (!g) { return; } node = g->next; free (g); while (node) { node_tmp = node; node = node->next; free (node_tmp); } return; } static int _gids_gid_head_cmp (const uid_t *uid1p, const uid_t *uid2p) { /* Hash comparison function for gid_hash keys [uid1p] and [uid2p]. */ if (*uid1p < *uid2p) { return (-1); } if (*uid1p > *uid2p) { return (1); } return (0); } static unsigned int _gids_gid_head_key (uid_t *uidp) { /* Hash key function for converting [uidp] into a gid_hash key. */ return (*uidp); } static gid_node_p _gids_gid_node_create (gid_t gid) { /* Allocate and return a gid_node for [gid], or NULL on error. * De-allocation is handled by _gids_gid_head_destroy(). */ gid_node_p node; if (!(node = malloc (sizeof (*node)))) { return (NULL); } node->next = NULL; node->gid = gid; return (node); } static uid_node_p _gids_uid_node_create (const char *user, uid_t uid) { /* Allocate and return a uid_node mapping [user] to [uid], or NULL on error. */ uid_node_p u; if ((user == NULL) || (*user == '\0')) { return (NULL); } if (!(u = malloc (sizeof (*u)))) { return (NULL); } if (!(u->user = strdup (user))) { free (u); return (NULL); } u->uid = uid; return (u); } static void _gids_uid_node_destroy (uid_node_p u) { /* De-allocate the uid_node [u]. */ if (!u) { return; } if (u->user) { free (u->user); } free (u); return; } /***************************************************************************** * Debug Functions *****************************************************************************/ #if _GIDS_DEBUG static void _gids_gid_hash_dump (hash_t gid_hash) { int n; n = hash_count (gid_hash); if (n < 0) { log_err (EMUNGE_SNAFU, LOG_ERR, "Failed _gids_gid_hash_dump: Invalid gid hash ptr"); } printf ("* GIDs Dump (%d UID%s):\n", n, ((n == 1) ? "" : "s")); hash_for_each (gid_hash, (hash_arg_f) _gids_gid_node_dump, NULL); return; } static void _gids_gid_node_dump (gid_head_p g, const uid_t *uidp, const void *null) { gid_node_p node; assert (g->uid == *uidp); printf (" %-10u:", (unsigned int) g->uid); for (node = g->next; node; node = node->next) { printf (" %u", (unsigned int) node->gid); } printf ("\n"); return; } static void _gids_uid_hash_dump (hash_t uid_hash) { int n; n = hash_count (uid_hash); if (n < 0) { log_err (EMUNGE_SNAFU, LOG_ERR, "Failed _gids_uid_hash_dump: Invalid uid hash ptr"); } printf ("* UID Dump (%d user%s):\n", n, ((n == 1) ? "" : "s")); hash_for_each (uid_hash, (hash_arg_f) _gids_uid_node_dump, NULL); return; } static void _gids_uid_node_dump (uid_node_p u, const char *user, const void *null) { assert (u->user == user); printf (" %-10u: %s\n", (unsigned int) u->uid, u->user); return; } static void _gids_ghost_hash_dump (hash_t ghost_hash) { int n; n = hash_count (ghost_hash); if (n < 0) { log_err (EMUNGE_SNAFU, LOG_ERR, "Failed _gids_host_hash_dump: Invalid ghost hash ptr"); } printf ("* Ghost Dump (%d user%s):\n", n, ((n == 1) ? "" : "s")); hash_for_each (ghost_hash, (hash_arg_f) _gids_ghost_node_dump, NULL); return; } static void _gids_ghost_node_dump (const char *data, const char *user, const void *null) { assert (data == user); printf (" %s\n", user); return; } #endif /* _GIDS_DEBUG */ munge-munge-0.5.15/src/munged/gids.h000066400000000000000000000056021425467526100172120ustar00rootroot00000000000000/***************************************************************************** * Written by Chris Dunlap . * Copyright (C) 2007-2022 Lawrence Livermore National Security, LLC. * Copyright (C) 2002-2007 The Regents of the University of California. * UCRL-CODE-155910. * * This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE). * For details, see . * * MUNGE 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. Additionally for the MUNGE library (libmunge), you * can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation, * either version 3 of the License, or (at your option) any later version. * * MUNGE 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 * and GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * and GNU Lesser General Public License along with MUNGE. If not, see * . *****************************************************************************/ #ifndef GIDS_H #define GIDS_H /***************************************************************************** * Constants *****************************************************************************/ #define GIDS_GROUP_FILE "/etc/group" /***************************************************************************** * Data Types *****************************************************************************/ typedef struct gids * gids_t; /* * GIDs opaque data type. */ /***************************************************************************** * Functions *****************************************************************************/ gids_t gids_create (int interval_secs, int do_group_stat); /* * Creates a list of supplementary GIDs for each UID based on information * from getgrent(). * The [interval_secs] is the number of seconds between updates. * The [do_group_stat] flag specifies whether the /etc/group mtime is * checked to determine if updates are needed. * Returns a GIDs mapping or dies trying. */ void gids_destroy (gids_t gids); /* * Destroys the GIDs mapping [gids]. */ void gids_update (gids_t gids); /* * Updates the GIDs mapping [gids]. */ int gids_is_member (gids_t gids, uid_t uid, gid_t gid); /* * Returns true (non-zero) if user [uid] is a member of the supplementary * group [gid] according to the GIDs mapping [gids]; o/w, returns false. */ #endif /* !GIDS_H */ munge-munge-0.5.15/src/munged/hash.c000066400000000000000000000300261425467526100172000ustar00rootroot00000000000000/***************************************************************************** * Written by Chris Dunlap . * Copyright (C) 2007-2022 Lawrence Livermore National Security, LLC. * Copyright (C) 2002-2007 The Regents of the University of California. * UCRL-CODE-155910. * * This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE). * For details, see . * * MUNGE 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. Additionally for the MUNGE library (libmunge), you * can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation, * either version 3 of the License, or (at your option) any later version. * * MUNGE 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 * and GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * and GNU Lesser General Public License along with MUNGE. If not, see * . ***************************************************************************** * Refer to "hash.h" for documentation on public functions. *****************************************************************************/ #if HAVE_CONFIG_H # include "config.h" #endif /* HAVE_CONFIG_H */ #include #include #include #include #include "hash.h" #include "thread.h" /***************************************************************************** * Constants *****************************************************************************/ #define HASH_DEF_SIZE 1213 #define HASH_NODE_ALLOC_NUM 1024 /***************************************************************************** * Data Types *****************************************************************************/ struct hash_node { struct hash_node *next; /* next node in list */ void *data; /* ptr to hashed item */ const void *hkey; /* ptr to hashed item's key */ }; struct hash { int count; /* number of items in hash table */ int size; /* num slots allocated in hash table */ struct hash_node **table; /* hash table array of node ptrs */ hash_cmp_f cmp_f; /* key comparison function */ hash_del_f del_f; /* item deletion function */ hash_key_f key_f; /* key hash function */ #if WITH_PTHREADS pthread_mutex_t mutex; /* mutex to protect access to hash */ #endif /* WITH_PTHREADS */ }; /***************************************************************************** * Prototypes *****************************************************************************/ static struct hash_node * hash_node_alloc (void); static void hash_node_free (struct hash_node *node); /***************************************************************************** * Variables *****************************************************************************/ static struct hash_node *hash_mem_list = NULL; /* * Singly-linked list for tracking memory allocations from hash_node_alloc() * for eventual de-allocation via hash_drop_memory(). Each block allocation * begins with a pointer for chaining these allocations together. The block * is broken up into individual hash_node structs and placed on the * hash_free_list. */ static struct hash_node *hash_free_list = NULL; /* * Singly-linked list of hash_node structs available for use. These are * allocated via hash_node_alloc() in blocks of HASH_NODE_ALLOC_NUM. This * bulk approach uses less RAM and CPU than allocating/de-allocating objects * individually as needed. */ #if WITH_PTHREADS static pthread_mutex_t hash_free_list_lock = PTHREAD_MUTEX_INITIALIZER; /* * Mutex for protecting access to hash_mem_list and hash_free_list. */ #endif /* WITH_PTHREADS */ /***************************************************************************** * Functions *****************************************************************************/ hash_t hash_create (int size, hash_key_f key_f, hash_cmp_f cmp_f, hash_del_f del_f) { hash_t h; if (!cmp_f || !key_f) { errno = EINVAL; return (NULL); } if (size <= 0) { size = HASH_DEF_SIZE; } if (!(h = malloc (sizeof (*h)))) { return (NULL); } if (!(h->table = calloc (size, sizeof (struct hash_node *)))) { free (h); return (NULL); } h->count = 0; h->size = size; h->cmp_f = cmp_f; h->del_f = del_f; h->key_f = key_f; lsd_mutex_init (&h->mutex); return (h); } void hash_destroy (hash_t h) { int i; struct hash_node *p, *q; if (!h) { errno = EINVAL; return; } lsd_mutex_lock (&h->mutex); for (i = 0; i < h->size; i++) { for (p = h->table[i]; p != NULL; p = q) { q = p->next; if (h->del_f) h->del_f (p->data); hash_node_free (p); } } lsd_mutex_unlock (&h->mutex); lsd_mutex_destroy (&h->mutex); free (h->table); free (h); return; } void hash_reset (hash_t h) { int i; struct hash_node *p, *q; if (!h) { errno = EINVAL; return; } lsd_mutex_lock (&h->mutex); for (i = 0; i < h->size; i++) { for (p = h->table[i]; p != NULL; p = q) { q = p->next; if (h->del_f) h->del_f (p->data); hash_node_free (p); } h->table[i] = NULL; } h->count = 0; lsd_mutex_unlock (&h->mutex); return; } int hash_is_empty (hash_t h) { int n; if (!h) { errno = EINVAL; return (-1); } lsd_mutex_lock (&h->mutex); n = h->count; lsd_mutex_unlock (&h->mutex); return (n == 0); } int hash_count (hash_t h) { int n; if (!h) { errno = EINVAL; return (-1); } lsd_mutex_lock (&h->mutex); n = h->count; lsd_mutex_unlock (&h->mutex); return (n); } void * hash_find (hash_t h, const void *key) { unsigned int slot; int cmpval; struct hash_node *p; void *data = NULL; if (!h || !key) { errno = EINVAL; return (NULL); } errno = 0; lsd_mutex_lock (&h->mutex); slot = h->key_f (key) % h->size; for (p = h->table[slot]; p != NULL; p = p->next) { cmpval = h->cmp_f (p->hkey, key); if (cmpval < 0) { continue; } if (cmpval == 0) { data = p->data; } break; } lsd_mutex_unlock (&h->mutex); return (data); } void * hash_insert (hash_t h, const void *key, void *data) { unsigned int slot; int cmpval; struct hash_node **pp; struct hash_node *p; if (!h || !key || !data) { errno = EINVAL; return (NULL); } lsd_mutex_lock (&h->mutex); slot = h->key_f (key) % h->size; for (pp = &(h->table[slot]); (p = *pp) != NULL; pp = &(p->next)) { cmpval = h->cmp_f (p->hkey, key); if (cmpval < 0) { continue; } if (cmpval == 0) { errno = EEXIST; data = NULL; goto end; } break; } if (!(p = hash_node_alloc ())) { data = NULL; goto end; } p->hkey = key; p->data = data; p->next = *pp; *pp = p; h->count++; end: lsd_mutex_unlock (&h->mutex); return (data); } void * hash_remove (hash_t h, const void *key) { unsigned int slot; int cmpval; struct hash_node **pp; struct hash_node *p; void *data = NULL; if (!h || !key) { errno = EINVAL; return (NULL); } errno = 0; lsd_mutex_lock (&h->mutex); slot = h->key_f (key) % h->size; for (pp = &(h->table[slot]); (p = *pp) != NULL; pp = &(p->next)) { cmpval = h->cmp_f (p->hkey, key); if (cmpval < 0) { continue; } if (cmpval == 0) { data = p->data; *pp = p->next; hash_node_free (p); h->count--; } break; } lsd_mutex_unlock (&h->mutex); return (data); } int hash_delete_if (hash_t h, hash_arg_f arg_f, void *arg) { int i; struct hash_node **pp; struct hash_node *p; int n = 0; if (!h || !arg_f) { errno = EINVAL; return (-1); } lsd_mutex_lock (&h->mutex); for (i = 0; i < h->size; i++) { pp = &(h->table[i]); while ((p = *pp) != NULL) { if (arg_f (p->data, p->hkey, arg) > 0) { if (h->del_f) h->del_f (p->data); *pp = p->next; hash_node_free (p); h->count--; n++; } else { pp = &(p->next); } } } lsd_mutex_unlock (&h->mutex); return (n); } int hash_for_each (hash_t h, hash_arg_f arg_f, void *arg) { int i; struct hash_node *p; int n = 0; if (!h || !arg_f) { errno = EINVAL; return (-1); } lsd_mutex_lock (&h->mutex); for (i = 0; i < h->size; i++) { for (p = h->table[i]; p != NULL; p = p->next) { if (arg_f (p->data, p->hkey, arg) > 0) { n++; } } } lsd_mutex_unlock (&h->mutex); return (n); } void hash_drop_memory (void) { struct hash_node *p; lsd_mutex_lock (&hash_free_list_lock); while (hash_mem_list != NULL) { p = hash_mem_list; hash_mem_list = p->next; free (p); } hash_free_list = NULL; lsd_mutex_unlock (&hash_free_list_lock); return; } /***************************************************************************** * Hash Functions *****************************************************************************/ unsigned int hash_key_string (const char *str) { unsigned char *p; unsigned int hval = 0; const unsigned int multiplier = 31; for (p = (unsigned char *) str; *p != '\0'; p++) { hval += (multiplier * hval) + *p; } return (hval); } /***************************************************************************** * Internal Functions *****************************************************************************/ static struct hash_node * hash_node_alloc (void) { /* Allocates a hash node from the freelist. * Returns a ptr to the object, or NULL if memory allocation fails. */ size_t size; struct hash_node *p; int i; assert (HASH_NODE_ALLOC_NUM > 0); lsd_mutex_lock (&hash_free_list_lock); if (!hash_free_list) { size = sizeof (p) + (HASH_NODE_ALLOC_NUM * sizeof (*p)); p = malloc (size); if (p != NULL) { p->next = hash_mem_list; hash_mem_list = p; hash_free_list = (struct hash_node *) ((unsigned char *) p + sizeof (p)); for (i = 0; i < HASH_NODE_ALLOC_NUM - 1; i++) { hash_free_list[i].next = &hash_free_list[i+1]; } hash_free_list[i].next = NULL; } } if (hash_free_list) { p = hash_free_list; hash_free_list = p->next; memset (p, 0, sizeof (*p)); } else { errno = ENOMEM; } lsd_mutex_unlock (&hash_free_list_lock); return (p); } static void hash_node_free (struct hash_node *node) { /* De-allocates the object [node], returning it to the freelist. */ assert (node != NULL); lsd_mutex_lock (&hash_free_list_lock); node->next = hash_free_list; hash_free_list = node; lsd_mutex_unlock (&hash_free_list_lock); return; } munge-munge-0.5.15/src/munged/hash.h000066400000000000000000000162011425467526100172040ustar00rootroot00000000000000/***************************************************************************** * Written by Chris Dunlap . * Copyright (C) 2007-2022 Lawrence Livermore National Security, LLC. * Copyright (C) 2002-2007 The Regents of the University of California. * UCRL-CODE-155910. * * This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE). * For details, see . * * MUNGE 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. Additionally for the MUNGE library (libmunge), you * can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation, * either version 3 of the License, or (at your option) any later version. * * MUNGE 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 * and GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * and GNU Lesser General Public License along with MUNGE. If not, see * . *****************************************************************************/ #ifndef HASH_H #define HASH_H /***************************************************************************** * Notes *****************************************************************************/ /* * If an item's key is modified after insertion, the hash will be unable to * locate it if the new key should hash to a different slot in the table. * * If WITH_PTHREADS is defined, these routines will be thread-safe. */ /***************************************************************************** * Data Types *****************************************************************************/ typedef struct hash * hash_t; /* * Hash table opaque data type. */ typedef unsigned int (*hash_key_f) (const void *key); /* * Function prototype for the hash function responsible for converting * the data's [key] into an unsigned integer hash value. */ typedef int (*hash_cmp_f) (const void *key1, const void *key2); /* * Function prototype for comparing two keys. * Returns an integer that is less than zero if [key1] is less than [key2], * equal to zero if [key1] is equal to [key2], and greater than zero if * [key1] is greater than [key2]. */ typedef void (*hash_del_f) (void *data); /* * Function prototype for de-allocating a data item stored within a hash. * This function is responsible for freeing all memory associated with * the [data] item, including any subordinate items. */ typedef int (*hash_arg_f) (void *data, const void *key, void *arg); /* * Function prototype for operating on each element in the hash table. * The function will be invoked once for each [data] item in the hash, * with the item's [key] and the specified [arg] being passed in as args. */ /***************************************************************************** * Functions *****************************************************************************/ hash_t hash_create (int size, hash_key_f key_f, hash_cmp_f cmp_f, hash_del_f del_f); /* * Creates and returns a new hash table on success. * Returns NULL with errno=EINVAL if [keyf] or [cmpf] is not specified. * Returns NULL with errno=ENOMEM if memory allocation fails. * The [size] is the number of slots in the table; a larger table requires * more memory, but generally provide quicker access times. If set <= 0, * the default size is used. * The [keyf] function converts a key into a hash value. * The [cmpf] function determines whether two keys are equal. * The [delf] function de-allocates memory used by items in the hash; * if set to NULL, memory associated with these items will not be freed * when the hash is destroyed. */ void hash_destroy (hash_t h); /* * Destroys hash table [h]. If a deletion function was specified when the * hash was created, it will be called for each item contained within. * Abadoning a hash without calling hash_destroy() will cause a memory leak. */ void hash_reset (hash_t h); /* * Resets hash table [h] back to an empty state. If a deletion function was * specified when the hash was created, it will be called for each item * contained within. */ int hash_is_empty (hash_t h); /* * Returns 1 if hash table [h] is empty, or 0 if not empty. * Returns -1 with errno=EINVAL if [h] is NULL. */ int hash_count (hash_t h); /* * Returns the number of items in hash table [h]. * Returns -1 with errno=EINVAL if [h] is NULL. */ void * hash_find (hash_t h, const void *key); /* * Searches for the item corresponding to [key] in hash table [h]. * Returns a ptr to the found item's data on success. * Returns NULL with errno=0 if no matching item is found. * Returns NULL with errno=EINVAL if [key] is not specified. */ void * hash_insert (hash_t h, const void *key, void *data); /* * Inserts [data] with the corresponding [key] into hash table [h]; * note that it is permissible for [key] to be set equal to [data]. * Returns a ptr to the inserted item's data on success. * Returns NULL with errno=EEXIST if [key] already exists in the hash. * Returns NULL with errno=EINVAL if [key] or [data] is not specified. * Returns NULL with errno=ENOMEM if memory allocation fails. */ void * hash_remove (hash_t h, const void *key); /* * Removes the item corresponding to [key] from hash table [h]. * Returns a ptr to the removed item's data on success. * Returns NULL with errno=0 if no matching item is found. * Returns NULL with errno=EINVAL if [key] is not specified. */ int hash_delete_if (hash_t h, hash_arg_f argf, void *arg); /* * Conditionally deletes (and de-allocates) items from hash table [h]. * The [argf] function is invoked once for each item in the hash, with * [arg] being passed in as an argument. Items for which [argf] returns * greater-than-zero are deleted. * Returns the number of items deleted. * Returns -1 with errno=EINVAL if [argf] is not specified. */ int hash_for_each (hash_t h, hash_arg_f argf, void *arg); /* * Invokes the [argf] function once for each item in hash table [h], * with [arg] being passed in as an argument. * Returns the number of items for which [argf] returns greater-than-zero. * Returns -1 with errno=EINVAL if [argf] is not specified. */ unsigned int hash_key_string (const char *str); /* * A hash_key_f function that hashes the string [str]. */ void hash_drop_memory (void); /* * Frees memory that has been internally allocated. No reference counting is * performed to determine whether memory regions are still in use. * This may be useful for explicitly de-allocating memory before program * termination when checking for memory leaks. * WARNING: Do not call this routine until ALL hashes have been destroyed. */ #endif /* !HASH_H */ munge-munge-0.5.15/src/munged/job.c000066400000000000000000000210151425467526100170250ustar00rootroot00000000000000/***************************************************************************** * Written by Chris Dunlap . * Copyright (C) 2007-2022 Lawrence Livermore National Security, LLC. * Copyright (C) 2002-2007 The Regents of the University of California. * UCRL-CODE-155910. * * This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE). * For details, see . * * MUNGE 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. Additionally for the MUNGE library (libmunge), you * can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation, * either version 3 of the License, or (at your option) any later version. * * MUNGE 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 * and GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * and GNU Lesser General Public License along with MUNGE. If not, see * . *****************************************************************************/ #if HAVE_CONFIG_H # include "config.h" #endif /* HAVE_CONFIG_H */ #include /* for inet_ntop() */ #include #include #include #include /* for INET_ADDRSTRLEN */ #include #include #include #include #include "conf.h" #include "dec.h" #include "enc.h" #include "fd.h" #include "log.h" #include "m_msg.h" #include "munge_defs.h" #include "str.h" #include "work.h" /***************************************************************************** * Constants *****************************************************************************/ #define LOG_LIMIT_SECS 60 /***************************************************************************** * Extern Variables *****************************************************************************/ extern volatile sig_atomic_t got_reconfig; /* defined in munged.c */ extern volatile sig_atomic_t got_terminate; /* defined in munged.c */ /***************************************************************************** * Private Prototypes *****************************************************************************/ static void _job_exec (m_msg_t m); /***************************************************************************** * Public Functions *****************************************************************************/ void job_accept (conf_t conf) { work_p w; m_msg_t m; int sd; int curr_errno; time_t curr_time; int last_log_errno = 0; time_t last_log_time = 0; assert (conf != NULL); assert (conf->ld >= 0); if (!(w = work_init ((work_func_t) _job_exec, conf->nthreads))) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to create %d work thread%s", conf->nthreads, ((conf->nthreads > 1) ? "s" : "")); } log_msg (LOG_INFO, "Created %d work thread%s", conf->nthreads, ((conf->nthreads > 1) ? "s" : "")); while (!got_terminate) { if (got_reconfig) { log_msg (LOG_NOTICE, "Processing signal %d (%s)", got_reconfig, strsignal (got_reconfig)); got_reconfig = 0; gids_update (conf->gids); } sd = accept (conf->ld, NULL, NULL); if (sd < 0) { switch (errno) { case ECONNABORTED: case EINTR: continue; case EMFILE: case ENFILE: case ENOBUFS: case ENOMEM: curr_errno = errno; /* save errno before calling time() */ curr_time = time (NULL); if (curr_time == (time_t) -1) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to query current time"); } if ((curr_time > last_log_time + LOG_LIMIT_SECS) || (curr_errno != last_log_errno)) { log_msg (LOG_INFO, "Failed to accept connection: %s", strerror (curr_errno)); last_log_errno = curr_errno; last_log_time = curr_time; } /* Process backlog before accepting new connections. */ work_wait (w); continue; default: log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to accept connection"); break; } } /* With fd_timed_read_n(), a poll() is performed before any read() * in order to provide timeouts and ensure the read() won't block. * As such, it shouldn't be necessary to set the client socket as * non-blocking. However according to the Linux poll(2) and * select(2) manpages, spurious readiness notifications can occur. * poll()/select() may report a socket as ready for reading while * the subsequent read() blocks. This could happen when data has * arrived, but upon examination is discarded due to an invalid * checksum. To protect against this, the client socket is set * non-blocking and EAGAIN is handled appropriately. */ if (fd_set_nonblocking (sd) < 0) { close (sd); log_msg (LOG_WARNING, "Failed to set nonblocking client socket: %s", strerror (errno)); } else if (m_msg_create (&m) != EMUNGE_SUCCESS) { close (sd); log_msg (LOG_WARNING, "Failed to create client request"); } else if (m_msg_bind (m, sd) != EMUNGE_SUCCESS) { m_msg_destroy (m); log_msg (LOG_WARNING, "Failed to bind socket for client request"); } else if (work_queue (w, m) < 0) { m_msg_destroy (m); log_msg (LOG_WARNING, "Failed to queue client request"); } } log_msg (LOG_NOTICE, "Exiting on signal %d (%s)", got_terminate, strsignal (got_terminate)); work_fini (w, 1); return; } /***************************************************************************** * Private Functions *****************************************************************************/ static void _job_exec (m_msg_t m) { /* Receives and responds to the message request [m]. */ munge_err_t e; const char *p; assert (m != NULL); e = m_msg_recv (m, MUNGE_MSG_UNDEF, MUNGE_MAXIMUM_REQ_LEN); if (e == EMUNGE_SUCCESS) { switch (m->type) { case MUNGE_MSG_ENC_REQ: enc_process_msg (m); break; case MUNGE_MSG_DEC_REQ: dec_process_msg (m); break; default: m_msg_set_err (m, EMUNGE_SNAFU, strdupf ("Invalid message type %d", m->type)); break; } } /* For certain MUNGE "cred" errors, the credential has been successfully * decoded but is deemed invalid for other reasons. In these cases, * the origin IP address is added to the logged error message to aid * in troubleshooting. */ if (m->error_num != EMUNGE_SUCCESS) { p = (m->error_str != NULL) ? m->error_str : munge_strerror (m->error_num); switch (m->error_num) { case EMUNGE_CRED_EXPIRED: case EMUNGE_CRED_REWOUND: case EMUNGE_CRED_REPLAYED: if (m->addr_len == 4) { char ip_addr_buf [INET_ADDRSTRLEN]; if (inet_ntop (AF_INET, &m->addr, ip_addr_buf, sizeof (ip_addr_buf)) != NULL) { log_msg (LOG_INFO, "%s from %s", p, ip_addr_buf); break; } } /* fall-through */ default: log_msg (LOG_INFO, "%s", p); break; } } m_msg_destroy (m); return; } munge-munge-0.5.15/src/munged/job.h000066400000000000000000000030721425467526100170350ustar00rootroot00000000000000/***************************************************************************** * Written by Chris Dunlap . * Copyright (C) 2007-2022 Lawrence Livermore National Security, LLC. * Copyright (C) 2002-2007 The Regents of the University of California. * UCRL-CODE-155910. * * This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE). * For details, see . * * MUNGE 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. Additionally for the MUNGE library (libmunge), you * can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation, * either version 3 of the License, or (at your option) any later version. * * MUNGE 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 * and GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * and GNU Lesser General Public License along with MUNGE. If not, see * . *****************************************************************************/ #ifndef JOB_H #define JOB_H #include "m_msg.h" void job_accept (conf_t conf); #endif /* !JOB_H */ munge-munge-0.5.15/src/munged/lock.c000066400000000000000000000212341425467526100172060ustar00rootroot00000000000000/***************************************************************************** * Written by Chris Dunlap . * Copyright (C) 2007-2022 Lawrence Livermore National Security, LLC. * Copyright (C) 2002-2007 The Regents of the University of California. * UCRL-CODE-155910. * * This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE). * For details, see . * * MUNGE 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. Additionally for the MUNGE library (libmunge), you * can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation, * either version 3 of the License, or (at your option) any later version. * * MUNGE 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 * and GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * and GNU Lesser General Public License along with MUNGE. If not, see * . *****************************************************************************/ #if HAVE_CONFIG_H # include "config.h" #endif /* HAVE_CONFIG_H */ #include #include #include #include #include #include #include #include "conf.h" #include "log.h" #include "str.h" /***************************************************************************** * Prototypes *****************************************************************************/ static void _lock_create_name (conf_t conf); static void _lock_stat (int fd, const char *name); static int _lock_set (int fd); static pid_t _lock_is_set (int fd); /***************************************************************************** * Public Functions *****************************************************************************/ void lock_create (conf_t conf) { /* Creates a lockfile to ensure exclusive access to the Unix domain socket. */ int rv; mode_t mask; if (conf == NULL) { log_err (EMUNGE_SNAFU, LOG_ERR, "Failed to create lock: conf undefined"); } _lock_create_name (conf); /* If unable to unlink() the lockfile, log a warning instead of an error * since this code path is being executed with "--force". */ if (conf->got_force) { do { rv = unlink (conf->lockfile_name); } while ((rv < 0) && (errno == EINTR)); if ((rv < 0) && (errno != ENOENT)) { log_msg (LOG_WARNING, "Failed to remove \"%s\": %s", conf->lockfile_name, strerror (errno)); } } if (conf->lockfile_fd >= 0) { rv = close (conf->lockfile_fd); if (rv < 0) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to close \"%s\"", conf->lockfile_name); } } mask = umask (0); conf->lockfile_fd = open (conf->lockfile_name, O_CREAT | O_TRUNC | O_WRONLY, S_IWUSR); umask (mask); /* If the lockfile creation fails, either log an error and exit, * or log a warning and immediately return. */ if (conf->lockfile_fd < 0) { log_err_or_warn (conf->got_force, "Failed to create \"%s\": %s", conf->lockfile_name, strerror (errno)); return; /* no lock, so nothing more to do */ } _lock_stat (conf->lockfile_fd, conf->lockfile_name); rv = _lock_set (conf->lockfile_fd); if (rv < 0) { log_err_or_warn (conf->got_force, "Failed to lock \"%s\"", conf->lockfile_name); } else if (rv > 0) { pid_t pid = _lock_is_set (conf->lockfile_fd); if (pid < 0) { log_err_or_warn (conf->got_force, "Failed to test \"%s\": %s", conf->lockfile_name, strerror (errno)); } else if (pid > 0) { log_err_or_warn (conf->got_force, "Failed to lock \"%s\": pid %d bound to socket \"%s\"", conf->lockfile_name, pid, conf->socket_name); } else { /* _lock_set() reported lock was held by another process, * but _lock_is_set() found no lock. TOCTOU. */ log_err_or_warn (conf->got_force, "Failed to lock \"%s\": Inconsistent lock state", conf->lockfile_name); } } return; } pid_t lock_query (conf_t conf) { /* Tests the lockfile for an exclusive advisory lock to see if * another process is already holding it. * Returns the pid of a running process (>0) if the lock is held, * 0 if the lock is not held, or -1 on error. */ int rv; pid_t pid; if (conf == NULL) { log_err (EMUNGE_SNAFU, LOG_ERR, "Failed to create lock: conf undefined"); } _lock_create_name (conf); if (conf->lockfile_fd >= 0) { rv = close (conf->lockfile_fd); if (rv < 0) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to close \"%s\"", conf->lockfile_name); } } conf->lockfile_fd = open (conf->lockfile_name, O_WRONLY, S_IWUSR); if (conf->lockfile_fd < 0) { return (-1); } pid = _lock_is_set (conf->lockfile_fd); return (pid); } /***************************************************************************** * Private Functions *****************************************************************************/ static void _lock_create_name (conf_t conf) { /* Creates the lockfile name based on the socket name. */ assert (conf != NULL); if (conf->socket_name == NULL) { log_err (EMUNGE_SNAFU, LOG_ERR, "Failed to create lockfile_name: socket_name undefined"); } if (conf->lockfile_name) { free (conf->lockfile_name); } conf->lockfile_name = strdupf ("%s.lock", conf->socket_name); if (conf->lockfile_name == NULL) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to create lockfile_name"); } return; } static void _lock_stat (int fd, const char *name) { /* Stats the lockfile [name] via the file-descriptor [fd] to prevent TOCTOU * and checks for peculiarities. */ int rv; struct stat st; assert (fd >= 0); assert (name != NULL); rv = fstat (fd, &st); if (rv < 0) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to validate lockfile: cannot stat \"%s\"", name); } else if (!S_ISREG(st.st_mode)) { log_err (EMUNGE_SNAFU, LOG_ERR, "Failed to validate lockfile: \"%s\" should be a regular file", name); } else if ((st.st_mode & 07777) != S_IWUSR) { log_err (EMUNGE_SNAFU, LOG_ERR, "Failed to validate lockfile: \"%s\" should only have " "permissions for write by user (file mode 0200)", name); } else if (st.st_uid != geteuid()) { log_err (EMUNGE_SNAFU, LOG_ERR, "Failed to validate lockfile: \"%s\" should be owned by " "UID %u", name, (unsigned) geteuid()); } return; } static int _lock_set (int fd) { /* Sets an exclusive advisory lock on the open file descriptor 'fd'. * Returns 0 on success, 1 if a conflicting lock is held by another process, * or -1 on error (with errno set). */ struct flock fl; int rv; if (fd < 0) { errno = EBADF; return (-1); } fl.l_type = F_WRLCK; fl.l_whence = SEEK_SET; fl.l_start = 0; fl.l_len = 0; rv = fcntl (fd, F_SETLK, &fl); if (rv < 0) { if ((errno == EACCES) || (errno == EAGAIN)) { return (1); } return (-1); } return (0); } static pid_t _lock_is_set (int fd) { /* Tests whether an exclusive advisory lock could be obtained for the open * file descriptor 'fd'. * Returns 0 if the file is not locked, >0 for the pid of another process * holding a conflicting lock, or -1 on error (with errno set). */ struct flock fl; int rv; if (fd < 0) { errno = EBADF; return (-1); } fl.l_type = F_WRLCK; fl.l_whence = SEEK_SET; fl.l_start = 0; fl.l_len = 0; rv = fcntl (fd, F_GETLK, &fl); if (rv < 0) { return (-1); } if (fl.l_type == F_UNLCK) { return (0); } return (fl.l_pid); } munge-munge-0.5.15/src/munged/lock.h000066400000000000000000000032041425467526100172100ustar00rootroot00000000000000/***************************************************************************** * Written by Chris Dunlap . * Copyright (C) 2007-2022 Lawrence Livermore National Security, LLC. * Copyright (C) 2002-2007 The Regents of the University of California. * UCRL-CODE-155910. * * This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE). * For details, see . * * MUNGE 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. Additionally for the MUNGE library (libmunge), you * can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation, * either version 3 of the License, or (at your option) any later version. * * MUNGE 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 * and GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * and GNU Lesser General Public License along with MUNGE. If not, see * . *****************************************************************************/ #ifndef MUNGE_LOCK_H #define MUNGE_LOCK_H #include #include "conf.h" void lock_create (conf_t conf); pid_t lock_query (conf_t conf); #endif /* !MUNGE_LOCK_H */ munge-munge-0.5.15/src/munged/munged.8.in000066400000000000000000000216441425467526100200740ustar00rootroot00000000000000.\"**************************************************************************** .\" Written by Chris Dunlap . .\" Copyright (C) 2007-2022 Lawrence Livermore National Security, LLC. .\" Copyright (C) 2002-2007 The Regents of the University of California. .\" UCRL-CODE-155910. .\" .\" This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE). .\" For details, see . .\" .\" MUNGE 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. Additionally for the MUNGE library (libmunge), you .\" can redistribute it and/or modify it under the terms of the GNU Lesser .\" General Public License as published by the Free Software Foundation, .\" either version 3 of the License, or (at your option) any later version. .\" .\" MUNGE 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 .\" and GNU Lesser General Public License for more details. .\" .\" You should have received a copy of the GNU General Public License .\" and GNU Lesser General Public License along with MUNGE. If not, see .\" . .\"**************************************************************************** .TH MUNGED 8 "@DATE@" "@PACKAGE@-@VERSION@" "MUNGE Uid 'N' Gid Emporium" .SH NAME munged \- MUNGE daemon .SH SYNOPSIS .B munged [\fIOPTION\fR]... .SH DESCRIPTION The \fBmunged\fR daemon is responsible for authenticating local MUNGE clients and servicing their credential encode & decode requests. .PP All \fBmunged\fR daemons within a security realm share a common key. All hosts within this realm are expected to have common users/UIDs and groups/GIDs. The key is used to cryptographically protect the credentials; it is created with the \fBmungekey\fR command. .PP When a credential is created, \fBmunged\fR embeds metadata within it including the effective UID and GID of the requesting client (as determined by \fBmunged\fR) and the current time (as determined by the local clock). It then compresses the data, computes a message authentication code, encrypts the data, and base64-encodes the result before returning the credential to the client. .PP When a credential is validated, \fBmunged\fR first checks the message authentication code to ensure the credential has not been subsequently altered. Next, it checks the embedded UID/GID restrictions to determine whether the requesting client is allowed to decode it. Then, it checks the embedded encode time against the current time; if this difference exceeds the embedded time-to-live, the credential has expired. Finally, it checks whether this credential has been previously decoded on this host; if so, the credential has been replayed. If all checks pass, the credential metadata and payload are returned to the client. .SH OPTIONS .TP .BI "\-h, \-\-help" Display a summary of the command-line options. .TP .BI "\-L, \-\-license" Display license information. .TP .BI "\-V, \-\-version" Display version information. .TP .BI "\-f, \-\-force" Force the daemon to run if at all possible. This overrides warnings for an existing local domain socket, a lack of entropy for the PRNG, and insecure file/directory permissions. Use with caution as overriding these warnings can affect security. .TP .BI "\-F, \-\-foreground" Run the daemon in the foreground. .TP .BI "\-M, \-\-mlockall" Lock all current and future pages in the virtual memory address space. Access to locked pages will never be delayed by a page fault. This can improve performance and help the daemon remain responsive when the system is under heavy memory pressure. This typically requires root privileges or the CAP_IPC_LOCK capability. .TP .BI "\-s, \-\-stop" Stop the daemon bound to the socket and wait for it to shut down. Use with the \fB\-\-socket\fR option to target a daemon bound to a non-default socket location. This option exits with a zero status if the specified daemon was successfully stopped, or a non-zero status otherwise. .TP .BI "\-S, \-\-socket " path Specify the local domain socket for communicating with clients. .TP .BI "\-v, \-\-verbose" Be verbose. .TP .BI "\-\-auth\-server\-dir " directory Specify an alternate directory in which the daemon will create the pipe used to authenticate clients. The recommended permissions for this directory are 0711. This option is only valid on platforms where client authentication is performed via a file-descriptor passing mechanism. .TP .BI "\-\-auth\-client\-dir " directory Specify an alternate directory in which clients will create the file used to authenticate themselves to the daemon. The recommended permissions for this directory are 1733. This option is only valid on platforms where client authentication is performed via a file-descriptor passing mechanism. .TP .BI "\-\-benchmark" Disable recurring timers in order to reduce some noise while benchmarking. This affects the PRNG entropy pool, supplementary group mapping, and credential replay hash. Do not enable this option when running in production. .TP .BI "\-\-group\-check\-mtime " boolean Specify whether the modification time of \fI/etc/group\fR should be checked before updating the supplementary group membership mapping. If this value is non-zero, the check will be enabled and the mapping will not be updated unless the file has been modified since the last update. .TP .BI "\-\-group\-update\-time " seconds Specify the number of seconds between updates to the supplementary group membership mapping; this mapping is used when restricting credentials by GID. A value of 0 causes it to be computed initially but never updated (unless triggered by a \fBSIGHUP\fR). A value of \-1 causes it to be disabled. .TP .BI "\-\-key\-file " path Specify an alternate pathname to the key file. .TP .BI "\-\-log\-file " path Specify an alternate pathname to the log file. .TP .BI "\-\-max\-ttl " integer Specify the maximum allowable time-to-live value (in seconds) for a credential. This setting has an upper-bound imposed by the hard-coded MUNGE_MAXIMUM_TTL value. Reducing it will limit the maximum growth of the credential replay cache. This is viable if clocks within the MUNGE realm can be kept in sync with minimal skew. .TP .BI "\-\-num\-threads " integer Specify the number of threads to spawn for processing credential requests. .TP .BI "\-\-origin " address Specify the origin address that will be encoded into credential metadata. This can be a hostname or IPv4 address; it can also be the name of a local network interface, in which case the first IPv4 address found assigned to that interface will be used. The default value is the IPv4 address of the hostname returned by \fBgethostname()\fR. Failure to lookup the address will result in an error; if overridden, the origin will be set to the null address. .TP .BI "\-\-pid\-file " path Specify an alternate pathname for storing the Process ID of the daemon. .TP .BI "\-\-seed\-file " path Specify an alternate pathname to the PRNG seed file. .TP .BI "\-\-syslog" Redirect log messages to syslog when the daemon is running in the background. .TP .BI "\-\-trusted\-group " group Specify the group name or GID of the "trusted group". This is used for permission checks on a directory hierarchy. Directories with group write permissions are allowed if they are owned by the trusted group (or the sticky bit is set). .SH SIGNALS .TP .B SIGHUP Immediately update the supplementary group membership mapping instead of waiting for the next scheduled update; this mapping is used when restricting credentials by GID. .TP .B SIGTERM Terminate the daemon. .\" .SH FILES .SH NOTES All clocks within a security realm must be kept in sync within the credential time-to-live setting. .PP While \fBmunged\fR prevents a given credential from being decoded on a particular host more than once, nothing prevents a credential from being decoded on multiple hosts within the security realm before it expires. .SH AUTHOR Chris Dunlap .SH COPYRIGHT Copyright (C) 2007-2022 Lawrence Livermore National Security, LLC. .br Copyright (C) 2002-2007 The Regents of the University of California. .PP MUNGE 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. .PP Additionally for the MUNGE library (libmunge), you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. .SH "SEE ALSO" .BR munge (1), .BR remunge (1), .BR unmunge (1), .BR munge (3), .BR munge_ctx (3), .BR munge_enum (3), .BR munge (7), .BR mungekey (8). .PP \fBhttps://dun.github.io/munge/\fR munge-munge-0.5.15/src/munged/munged.c000066400000000000000000000542031425467526100175370ustar00rootroot00000000000000/***************************************************************************** * Written by Chris Dunlap . * Copyright (C) 2007-2022 Lawrence Livermore National Security, LLC. * Copyright (C) 2002-2007 The Regents of the University of California. * UCRL-CODE-155910. * * This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE). * For details, see . * * MUNGE 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. Additionally for the MUNGE library (libmunge), you * can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation, * either version 3 of the License, or (at your option) any later version. * * MUNGE 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 * and GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * and GNU Lesser General Public License along with MUNGE. If not, see * . *****************************************************************************/ #if HAVE_CONFIG_H # include "config.h" #endif /* HAVE_CONFIG_H */ #include #include #include #include #include #include #include #if HAVE_MLOCKALL #include #endif /* HAVE_MLOCKALL */ #include /* include before resource.h for bsd */ #include #include #include #include #include #include #include "auth_recv.h" #include "cipher.h" #include "common.h" #include "conf.h" #include "crypto.h" #include "daemonpipe.h" #include "gids.h" #include "hash.h" #include "job.h" #include "lock.h" #include "log.h" #include "md.h" #include "missing.h" #include "munge_defs.h" #include "path.h" #include "random.h" #include "replay.h" #include "str.h" #include "timer.h" #include "xsignal.h" /***************************************************************************** * Prototypes *****************************************************************************/ static void disable_core_dumps (void); static void daemonize_init (char *progname, conf_t conf); static void daemonize_fini (void); static void open_logfile (const char *logfile, int priority, int got_force); static void handle_signals (void); static void sig_handler (int sig); static void write_pidfile (const char *pidfile, int got_force); static void lock_memory (void); static void sock_create (conf_t conf); static void sock_destroy (conf_t conf); /***************************************************************************** * Global Variables *****************************************************************************/ volatile sig_atomic_t got_reconfig = 0; /* signum if HUP received */ volatile sig_atomic_t got_terminate = 0; /* signum if INT/TERM received */ /***************************************************************************** * Functions *****************************************************************************/ int main (int argc, char *argv[]) { char *log_identity = argv[0]; int log_priority = LOG_INFO; int log_options = LOG_OPT_PRIORITY; #ifndef NDEBUG log_priority = LOG_DEBUG; log_options |= LOG_OPT_TIMESTAMP; #endif /* NDEBUG */ log_open_file (stderr, log_identity, log_priority, log_options); disable_core_dumps (); conf = create_conf (); parse_cmdline (conf, argc, argv); process_conf (conf); auth_recv_init (conf->auth_server_dir, conf->auth_client_dir, conf->got_force); if (!conf->got_foreground) { daemonize_init (argv[0], conf); if (conf->got_syslog) { log_close_file (); log_open_syslog (log_identity, LOG_DAEMON); } else { open_logfile (conf->logfile_name, log_priority, conf->got_force); } } log_msg (LOG_NOTICE, "Starting %s-%s daemon (pid %d)", PACKAGE, VERSION, (int) getpid ()); handle_signals (); write_origin_addr (conf); if (conf->got_mlockall) { lock_memory (); } crypto_init (); cipher_init_subsystem (); md_init_subsystem (); if (random_init (conf->seed_name) < 0) { if (conf->seed_name) { free (conf->seed_name); conf->seed_name = NULL; } } create_subkeys (conf); conf->gids = gids_create (conf->gids_update_secs, conf->got_group_stat); replay_init (); timer_init (); sock_create (conf); write_pidfile (conf->pidfile_name, conf->got_force); if (!conf->got_foreground) { daemonize_fini (); } job_accept (conf); sock_destroy (conf); timer_fini (); replay_fini (); gids_destroy (conf->gids); hash_drop_memory (); random_fini (conf->seed_name); crypto_fini (); destroy_conf (conf, 1); log_msg (LOG_NOTICE, "Stopping %s-%s daemon (pid %d)", PACKAGE, VERSION, (int) getpid ()); log_close_all (); exit (EMUNGE_SUCCESS); } static void disable_core_dumps (void) { /* Disable creation of core dump files. */ #ifdef NDEBUG struct rlimit limit; limit.rlim_cur = 0; limit.rlim_max = 0; if (setrlimit (RLIMIT_CORE, &limit) < 0) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to disable core dumps"); } #endif /* NDEBUG */ return; } static void daemonize_init (char *progname, conf_t conf) { /* Begins the daemonization of the process. * Despite the fact that this routine backgrounds the process, control * will not be returned to the shell until daemonize_fini() is called. */ pid_t pid; int status; int priority; char buf [1024]; /* Clear file mode creation mask. */ umask (0); /* Create a daemonpipe to have the parent process wait until signaled by * its double-forked grandchild process that startup is complete. */ if (daemonpipe_create () < 0) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to create daemonpipe"); } /* Automatically background the process and * ensure child process is not a process group leader. */ if ((pid = fork ()) < 0) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to fork child process"); } else if (pid > 0) { /* * Parent process waits for notification that startup is complete * before exiting. */ if (daemonpipe_close_writes () < 0) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to close write-end of daemonpipe"); } if (daemonpipe_read (&status, &priority, buf, sizeof (buf)) < 0) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to read from daemonpipe"); } if (status != 0) { if ((priority >= 0) && (buf[0] != '\0')) { log_msg (priority, "%s", buf); } exit (EXIT_FAILURE); } destroy_conf (conf, 0); log_close_all (); exit (EXIT_SUCCESS); } /* Child process continues. */ if (daemonpipe_close_reads () < 0) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to close read-end of daemonpipe"); } /* Become a session leader and process group leader * with no controlling tty. */ if (setsid () < 0) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to disassociate controlling tty"); } /* Ignore SIGHUP to keep child process from terminating when * the session leader (i.e., the parent proces) terminates. */ xsignal_ignore (SIGHUP); /* Abdicate session leader position to ensure the daemon cannot * automatically re-acquire a controlling tty. */ if ((pid = fork ()) < 0) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to fork grandchild process"); } else if (pid > 0) { destroy_conf (conf, 0); log_close_all (); exit (EXIT_SUCCESS); } /* Grandchild process continues. */ return; } static void daemonize_fini (void) { /* Completes the daemonization of the process. */ int dev_null; /* Ensure process does not keep a directory in use. * Avoid relative pathnames from this point on! */ if (chdir ("/") < 0) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to change CWD to root directory"); } /* Discard data to/from stdin, stdout, and stderr. */ if ((dev_null = open ("/dev/null", O_RDWR)) < 0) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to open \"/dev/null\""); } if (dup2 (dev_null, STDIN_FILENO) < 0) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to dup \"/dev/null\" onto stdin"); } if (dup2 (dev_null, STDOUT_FILENO) < 0) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to dup \"/dev/null\" onto stdout"); } if (dup2 (dev_null, STDERR_FILENO) < 0) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to dup \"/dev/null\" onto stderr"); } if ((dev_null > STDERR_FILENO) && (close (dev_null)) < 0) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to close \"/dev/null\""); } /* Signal parent process to exit now that startup is complete. * The daemonpipe_write() below is not strictly necessary since * daemonpipe_close_writes() closes the daemonpipe which will cause * daemonpipe_read() to read an EOF. */ if (daemonpipe_write (0, 0, NULL) < 0) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to signal parent process that startup is complete"); } if (daemonpipe_close_writes () < 0) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to close write-end of daemonpipe"); } return; } static void open_logfile (const char *logfile, int priority, int got_force) { int is_symlink; int is_missing; struct stat st; int rv; char logdir [PATH_MAX]; char ebuf [1024]; mode_t mask; FILE *fp; if ((logfile == NULL) || (*logfile == '\0')) { log_err (EMUNGE_SNAFU, LOG_ERR, "Logfile name is undefined"); } is_symlink = (lstat (logfile, &st) == 0) ? S_ISLNK (st.st_mode) : 0; if (is_symlink) { log_err_or_warn (got_force, "Logfile is insecure: \"%s\" should not be a symbolic link", logfile); } rv = stat (logfile, &st); is_missing = (rv < 0) && (errno == ENOENT); if (!is_missing) { if (rv < 0) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to check logfile \"%s\"", logfile); } if (!S_ISREG (st.st_mode)) { log_err (EMUNGE_SNAFU, LOG_ERR, "Logfile is insecure: \"%s\" must be a regular file " "(type=%07o)", logfile, (st.st_mode & S_IFMT)); } if (st.st_uid != geteuid ()) { log_err_or_warn (got_force, "Logfile is insecure: \"%s\" should be owned by UID %u " "instead of UID %u", logfile, (unsigned) geteuid (), (unsigned) st.st_uid); } if (st.st_mode & S_IWGRP) { log_err_or_warn (got_force, "Logfile is insecure: \"%s\" should not be writable by group " "(perms=%04o)", logfile, (st.st_mode & ~S_IFMT)); } if (st.st_mode & S_IWOTH) { log_err_or_warn (got_force, "Logfile is insecure: \"%s\" should not be writable by other " "(perms=%04o)", logfile, (st.st_mode & ~S_IFMT)); } } /* Ensure logfile dir is secure against modification by others. */ rv = path_dirname (logfile, logdir, sizeof (logdir)); if (rv < 0) { log_err (EMUNGE_SNAFU, LOG_ERR, "Failed to determine dirname of logfile \"%s\"", logfile); } rv = path_is_secure (logdir, ebuf, sizeof (ebuf), PATH_SECURITY_IGNORE_GROUP_WRITE); if (rv < 0) { log_err (EMUNGE_SNAFU, LOG_ERR, "Failed to check logfile dir \"%s\": %s", logdir, ebuf); } else if (rv == 0) { log_err_or_warn (got_force, "Logfile is insecure: %s", ebuf); } /* Protect logfile against unauthorized access by removing write-access * from group and all access from other. */ mask = umask (0); umask (mask | 027); fp = fopen (logfile, "a"); umask (mask); if (!fp) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to open logfile \"%s\"", logfile); } log_open_file (fp, NULL, priority, LOG_OPT_JUSTIFY | LOG_OPT_PRIORITY | LOG_OPT_TIMESTAMP); return; } static void handle_signals (void) { struct sigaction sa; int sig; int rv; sa.sa_handler = sig_handler; sa.sa_flags = 0; rv = sigfillset (&sa.sa_mask); if (rv == -1) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to initialize signal set to full"); } sig = SIGHUP; rv = sigaction (sig, &sa, NULL); if (rv == -1) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to set handler for signal %d (%s)", sig, strsignal (sig)); } sig = SIGINT; rv = sigaction (sig, &sa, NULL); if (rv == -1) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to set handler for signal %d (%s)", sig, strsignal (sig)); } sig = SIGTERM; rv = sigaction (sig, &sa, NULL); if (rv == -1) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to set handler for signal %d (%s)", sig, strsignal (sig)); } xsignal_ignore (SIGPIPE); return; } static void sig_handler (int sig) { if (sig == SIGHUP) { got_reconfig = sig; } else if ((sig == SIGINT) || (sig == SIGTERM)) { got_terminate = sig; } return; } static void write_pidfile (const char *pidfile, int got_force) { /* Creates the specified pidfile. * The pidfile must be created after the daemon has finished forking. * It should be written after validation checks that might prevent the * daemon from starting (e.g., after creating the socket and obtaining * the lock), but before the original parent process terminates (i.e., * before daemonize_fini()). */ char piddir [PATH_MAX]; char ebuf [1024]; int rv; mode_t mask; FILE *fp; if ((pidfile == NULL) || (*pidfile == '\0')) { log_err (EMUNGE_SNAFU, LOG_ERR, "PIDfile name is undefined"); } /* The pidfile must be specified with an absolute pathname; o/w, the * unlink() call in destroy_conf() will fail because the daemon has * chdir()'d. */ if (pidfile[0] != '/') { log_err (EMUNGE_SNAFU, LOG_ERR, "PIDfile \"%s\" requires an absolute path", pidfile); } /* Ensure pidfile dir is secure against modification by others. */ if (path_dirname (pidfile, piddir, sizeof (piddir)) < 0) { log_err (EMUNGE_SNAFU, LOG_ERR, "Failed to determine dirname of PIDfile \"%s\"", pidfile); } rv = path_is_secure (piddir, ebuf, sizeof (ebuf), PATH_SECURITY_NO_FLAGS); if (rv < 0) { log_err (EMUNGE_SNAFU, LOG_ERR, "Failed to check PIDfile dir \"%s\": %s", piddir, ebuf); } else if (rv == 0) { log_err_or_warn (got_force, "PIDfile is insecure: %s", ebuf); } /* Protect pidfile against unauthorized access by removing write-access * from group and other. * An error removing an old pidfile is not considered fatal. */ mask = umask (0); umask (mask | 022); do { rv = unlink (pidfile); } while ((rv < 0) && (errno == EINTR)); if ((rv < 0) && (errno != ENOENT)) { log_msg (LOG_WARNING, "Failed to remove PIDfile \"%s\": %s", pidfile, strerror (errno)); } fp = fopen (pidfile, "w"); umask (mask); /* * An error in creating the pidfile is not considered fatal. */ if (!fp) { log_msg (LOG_WARNING, "Failed to open PIDfile \"%s\": %s", pidfile, strerror (errno)); } else if (fprintf (fp, "%d\n", (int) getpid ()) == EOF) { log_msg (LOG_WARNING, "Failed to write to PIDfile \"%s\": %s", pidfile, strerror (errno)); (void) fclose (fp); } else if (fclose (fp) == EOF) { log_msg (LOG_WARNING, "Failed to close PIDfile \"%s\": %s", pidfile, strerror (errno)); } else { return; /* success */ } do { rv = unlink (pidfile); } while ((rv < 0) && (errno == EINTR)); if ((rv < 0) && (errno != ENOENT)) { log_msg (LOG_WARNING, "Failed to remove PIDfile \"%s\": %s", pidfile, strerror (errno)); } return; /* failure */ } static void lock_memory (void) { /* Lock all current and future pages in the virtual memory address space. * Access to locked pages will never be delayed by a page fault. * EAGAIN is tested for up to max_tries in case this is a transient error. * Should there be a nanosleep() between attempts? */ #if ! HAVE_MLOCKALL errno = ENOSYS; log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to lock pages in memory"); #else int rv; int i = 0; const int max_tries = 10; while (1) { i++; rv = mlockall (MCL_CURRENT | MCL_FUTURE); if (rv == 0) { break; } if ((errno == EAGAIN) && (i < max_tries)) { continue; } log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to lock pages in memory"); } log_msg (LOG_INFO, "Locked all pages in memory"); #endif /* ! HAVE_MLOCKALL */ return; } static void sock_create (conf_t conf) { char sockdir [PATH_MAX]; char ebuf [1024]; int sd; struct sockaddr_un addr; mode_t mask; int rv; size_t n; assert (conf != NULL); if ((conf->socket_name == NULL) || (*conf->socket_name == '\0')) { log_err (EMUNGE_SNAFU, LOG_ERR, "MUNGE socket name is undefined"); } /* Ensure socket dir is secure against modification by others. */ rv = path_dirname (conf->socket_name, sockdir, sizeof (sockdir)); if (rv < 0) { log_err (EMUNGE_SNAFU, LOG_ERR, "Failed to determine dirname of socket \"%s\"", conf->socket_name); } rv = path_is_secure (sockdir, ebuf, sizeof (ebuf), PATH_SECURITY_NO_FLAGS); if (rv < 0) { log_err (EMUNGE_SNAFU, LOG_ERR, "Failed to check socket dir \"%s\": %s", sockdir, ebuf); } else if (rv == 0) { log_err_or_warn (conf->got_force, "Socket is insecure: %s", ebuf); } /* Ensure socket dir is accessible by all. */ rv = path_is_accessible (sockdir, ebuf, sizeof (ebuf)); if (rv < 0) { log_err (EMUNGE_SNAFU, LOG_ERR, "Failed to check socket dir \"%s\": %s", sockdir, ebuf); } else if (rv == 0) { log_err_or_warn (conf->got_force, "Socket is inaccessible: %s", ebuf); } /* Create lockfile for exclusive access to the socket. */ lock_create (conf); /* * Remove existing socket from previous instance. */ do { rv = unlink (conf->socket_name); } while ((rv < 0) && (errno == EINTR)); if ((rv < 0) && (errno != ENOENT)) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to remove socket \"%s\"", conf->socket_name); } else if (rv == 0) { log_msg (LOG_INFO, "Removed existing socket \"%s\"", conf->socket_name); } /* Create socket for communicating with clients. */ sd = socket (PF_UNIX, SOCK_STREAM, 0); if (sd < 0) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to create socket"); } memset (&addr, 0, sizeof (addr)); addr.sun_family = AF_UNIX; n = strlcpy (addr.sun_path, conf->socket_name, sizeof (addr.sun_path)); if (n >= sizeof (addr.sun_path)) { log_err (EMUNGE_SNAFU, LOG_ERR, "Exceeded maximum length of %lu bytes for socket pathname", sizeof (addr.sun_path)); } /* Ensure socket is accessible by all. */ mask = umask (0); rv = bind (sd, (struct sockaddr *) &addr, sizeof (addr)); umask (mask); if (rv < 0) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to bind socket \"%s\"", conf->socket_name); } if (listen (sd, MUNGE_SOCKET_BACKLOG) < 0) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to listen on socket \"%s\"", conf->socket_name); } conf->ld = sd; log_msg (LOG_INFO, "Created socket \"%s\"", conf->socket_name); return; } static void sock_destroy (conf_t conf) { int rv; assert (conf != NULL); assert (conf->ld >= 0); assert (conf->socket_name != NULL); if (conf->socket_name) { do { rv = unlink (conf->socket_name); } while ((rv < 0) && (errno == EINTR)); if (rv < 0) { log_msg (LOG_WARNING, "Failed to remove socket \"%s\": %s", conf->socket_name, strerror (errno)); } } if (conf->ld >= 0) { rv = close (conf->ld); if (rv < 0) { log_msg (LOG_WARNING, "Failed to close socket \"%s\": %s", conf->socket_name, strerror (errno)); } conf->ld = -1; } if (conf->lockfile_name) { do { rv = unlink (conf->lockfile_name); } while ((rv < 0) && (errno == EINTR)); if (rv < 0) { log_msg (LOG_WARNING, "Failed to remove lockfile \"%s\": %s", conf->lockfile_name, strerror (errno)); } } if (conf->lockfile_fd >= 0) { rv = close (conf->lockfile_fd); if (rv < 0) { log_msg (LOG_WARNING, "Failed to close lockfile \"%s\": %s", conf->lockfile_name, strerror (errno)); } conf->lockfile_fd = -1; } return; } munge-munge-0.5.15/src/munged/net.c000066400000000000000000000222451425467526100170470ustar00rootroot00000000000000/***************************************************************************** * Written by Chris Dunlap . * Copyright (C) 2007-2022 Lawrence Livermore National Security, LLC. * Copyright (C) 2002-2007 The Regents of the University of California. * UCRL-CODE-155910. * * This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE). * For details, see . * * MUNGE 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. Additionally for the MUNGE library (libmunge), you * can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation, * either version 3 of the License, or (at your option) any later version. * * MUNGE 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 * and GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * and GNU Lesser General Public License along with MUNGE. If not, see * . *****************************************************************************/ #if HAVE_CONFIG_H # include #endif /* HAVE_CONFIG_H */ #include #include #include /* before ifaddrs.h for NetBSD 7.1.2 */ #if HAVE_IFADDRS_H #include #endif /* HAVE_IFADDRS_H */ #include /* _POSIX_HOST_NAME_MAX */ #include #include /* in_addr, sockaddr_in */ #include #include #include /* AF_INET, sockaddr */ #include #include #include "net.h" /* _HOST_NAME_MAX: * The maximum length of a hostname as returned by gethostname(), * not including the terminating null byte. * _POSIX_HOST_NAME_MAX is the most restrictive value for this according to * POSIX.1-2001. If it is not defined, assume a conservative value. */ #ifdef _POSIX_HOST_NAME_MAX #define _HOST_NAME_MAX _POSIX_HOST_NAME_MAX #else /* !_POSIX_HOST_NAME_MAX */ #define _HOST_NAME_MAX 255 #endif /* !_POSIX_HOST_NAME_MAX */ /***************************************************************************** * Internal Prototypes *****************************************************************************/ static int _net_get_hostaddr_via_ifaddrs ( const char *name, struct in_addr *inaddrp, char **ifnamep); #if HAVE_GETIFADDRS static const struct ifaddrs * _net_get_ifa_via_ifname ( const char *name, const struct ifaddrs *ifa_list); static const struct ifaddrs * _net_get_ifa_via_addr ( const struct hostent *h, const struct ifaddrs *ifa_list); #endif /* HAVE_GETIFADDRS */ /***************************************************************************** * External Functions *****************************************************************************/ /* Lookup the hostname for the current machine. * Return 0 on success with [result] set to a null-terminated string, * or -1 on error. */ int net_get_hostname (char **result) { char buf[_HOST_NAME_MAX + 1]; /* +1 for terminating null byte */ char *p; if (result == NULL) { errno = EINVAL; return -1; } /* When gethostname() is passed an array of insufficient length, the * returned name shall be truncated, and it is unspecified whether * the string will be null-terminated. * When gethostname() fails, it is unspecified whether it sets errno. */ if (gethostname (buf, sizeof (buf)) == -1) { return -1; } p = strdup (buf); if (p == NULL) { return -1; } *result = p; return 0; } /* Lookup the network address for the [name] string which can be a hostname, * IPv4 address, or local network interface name. * Return 0 on success, or -1 on error. * On success, [inaddrp] will be set to this address, and [ifnamep] will be * set to either a new string containing the name of the corresponding local * network interface (if available) or NULL (if not). The caller is * responsible for freeing this new string. */ int net_get_hostaddr (const char *name, struct in_addr *inaddrp, char **ifnamep) { struct hostent *h; int rv; if ((name == NULL) || (inaddrp == NULL) || (ifnamep == NULL)) { errno = EINVAL; return -1; } rv = _net_get_hostaddr_via_ifaddrs (name, inaddrp, ifnamep); /* * If unable to set addr via getifaddrs(), fallback to traditional lookup. * FIXME: gethostbyname() obsolete as of POSIX.1-2001. Use getaddrinfo(). */ if (rv < 0) { h = gethostbyname (name); if ((h != NULL) && (h->h_addrtype == AF_INET)) { *inaddrp = * (struct in_addr *) h->h_addr; rv = 0; } } return rv; } /***************************************************************************** * Internal Functions *****************************************************************************/ /* Check if [name] matches an address assigned to a local network interface. * Return 0 if a matching address is found, or -1 on error. * On success, [inaddrp] will be set to this address, and [ifnamep] will be * set to either a new string containing the name of the corresponding local * network interface (if available) or NULL (if not). The caller is * responsible for freeing this new string. * Note: getifaddrs() is not in POSIX.1-2001. */ static int _net_get_hostaddr_via_ifaddrs (const char *name, struct in_addr *inaddrp, char **ifnamep) { #if HAVE_GETIFADDRS struct ifaddrs *ifa_list; const struct ifaddrs *ifa; struct hostent *h; int rv = -1; assert (name != NULL); assert (inaddrp != NULL); assert (ifnamep != NULL); if (getifaddrs (&ifa_list) < 0) { return -1; } /* Check if NAME matches the name of a local network interface. */ ifa = _net_get_ifa_via_ifname (name, ifa_list); /* * Check if NAME matches a hostname or IP address assigned to a local * network interface. * FIXME: gethostbyname() obsolete as of POSIX.1-2001. Use getaddrinfo(). */ if (ifa == NULL) { h = gethostbyname (name); if (h != NULL) { ifa = _net_get_ifa_via_addr (h, ifa_list); } } /* If a match is found... */ if (ifa != NULL) { *inaddrp = ((struct sockaddr_in *) ifa->ifa_addr)->sin_addr; *ifnamep = ((ifa->ifa_name != NULL) && (ifa->ifa_name[0] != '\0')) ? strdup (ifa->ifa_name) : NULL; rv = 0; } /* If a match is not found, but host lookup succeeded... */ else if ((h != NULL) && (h->h_addrtype == AF_INET)) { *inaddrp = * (struct in_addr *) h->h_addr; *ifnamep = NULL; rv = 0; } freeifaddrs (ifa_list); return rv; #else /* !HAVE_GETIFADDRS */ errno = ENOTSUP; return -1; #endif /* !HAVE_GETIFADDRS */ } #if HAVE_GETIFADDRS /* Search the linked list of structures returned by getifaddrs() [ifa_list] * for an interface name matching the string [name]. * Return a ptr to the matching ifaddrs struct, or NULL if no match is found. */ static const struct ifaddrs * _net_get_ifa_via_ifname (const char *name, const struct ifaddrs *ifa_list) { const struct ifaddrs *ifa; assert (name != NULL); assert (ifa_list != NULL); for (ifa = ifa_list; ifa != NULL; ifa = ifa->ifa_next) { if (ifa->ifa_addr == NULL) { continue; } if (ifa->ifa_addr->sa_family != AF_INET) { continue; } if (ifa->ifa_name == NULL) { continue; } if (strcmp (ifa->ifa_name, name) == 0) { return ifa; } } return NULL; } /* Search the linked list of structures returned by getifaddrs() [ifa_list] * for an interface IPv4 address matching [name], where [name] is either a * hostname or IP address. * Return a ptr to the matching ifaddrs struct, or NULL if no match is found. */ static const struct ifaddrs * _net_get_ifa_via_addr (const struct hostent *h, const struct ifaddrs *ifa_list) { const struct ifaddrs *ifa; struct sockaddr_in *sai; struct in_addr **hap; assert (h != NULL); assert (ifa_list != NULL); if (h->h_addrtype != AF_INET) { return NULL; } for (ifa = ifa_list; ifa != NULL; ifa = ifa->ifa_next) { if (ifa->ifa_addr == NULL) { continue; } if (ifa->ifa_addr->sa_family == AF_INET) { sai = (struct sockaddr_in *) ifa->ifa_addr; for (hap = (struct in_addr **) h->h_addr_list; *hap; hap++) { if ((**hap).s_addr == sai->sin_addr.s_addr) { return ifa; } } } } return NULL; } #endif /* HAVE_GETIFADDRS */ munge-munge-0.5.15/src/munged/net.h000066400000000000000000000032631425467526100170530ustar00rootroot00000000000000/***************************************************************************** * Written by Chris Dunlap . * Copyright (C) 2007-2022 Lawrence Livermore National Security, LLC. * Copyright (C) 2002-2007 The Regents of the University of California. * UCRL-CODE-155910. * * This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE). * For details, see . * * MUNGE 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. Additionally for the MUNGE library (libmunge), you * can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation, * either version 3 of the License, or (at your option) any later version. * * MUNGE 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 * and GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * and GNU Lesser General Public License along with MUNGE. If not, see * . *****************************************************************************/ #ifndef MUNGE_NET_H #define MUNGE_NET_H #include int net_get_hostname (char **result); int net_get_hostaddr (const char *name, struct in_addr *inaddrp, char **ifnamep); #endif /* !MUNGE_NET_H */ munge-munge-0.5.15/src/munged/path.c000066400000000000000000000223321425467526100172120ustar00rootroot00000000000000/***************************************************************************** * Written by Chris Dunlap . * Copyright (C) 2007-2022 Lawrence Livermore National Security, LLC. * Copyright (C) 2002-2007 The Regents of the University of California. * UCRL-CODE-155910. * * This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE). * For details, see . * * MUNGE 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. Additionally for the MUNGE library (libmunge), you * can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation, * either version 3 of the License, or (at your option) any later version. * * MUNGE 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 * and GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * and GNU Lesser General Public License along with MUNGE. If not, see * . ***************************************************************************** * Refer to "path.h" for documentation on public functions. *****************************************************************************/ #if HAVE_CONFIG_H # include "config.h" #endif /* HAVE_CONFIG_H */ #include #include #include #include #include #include #include #include "common.h" #include "path.h" #include "query.h" #include "strlcpy.h" /***************************************************************************** * Internal Variables *****************************************************************************/ static gid_t _path_trusted_gid = GID_SENTINEL; /***************************************************************************** * Internal Prototypes *****************************************************************************/ static int _path_set_err (int rc, char *buf, size_t buflen, const char *format, ...); /***************************************************************************** * External Functions *****************************************************************************/ int path_canonicalize (const char *src, char *dst, int dstlen) { char buf [PATH_MAX]; int n = 0; if (!src || !*src) { errno = EINVAL; return (-1); } if (!realpath (src, buf)) { return (-1); } if (buf[0] != '/') { errno = EINVAL; return (-1); } if ((dst != NULL) && (dstlen > 0)) { n = strlcpy (dst, buf, dstlen); } return (n); } int path_dirname (const char *src, char *dst, size_t dstlen) { char *p = NULL; enum { start, last_slash, last_word, prev_slash } state = start; if ((src == NULL) || (dst == NULL) || (dstlen <= 1)) { errno = EINVAL; return (-1); } if (strlcpy (dst, src, dstlen) >= dstlen) { errno = ENAMETOOLONG; return (-1); } for (p = dst + strlen (dst) - 1; p >= dst; p--) { if (state == start) { state = (*p == '/') ? last_slash : last_word; } else if (state == last_slash) { if (*p != '/') state = last_word; } else if (state == last_word) { if (*p == '/') state = prev_slash; } else if (state == prev_slash) { if (*p != '/') break; } *p = '\0'; } if (p < dst) { dst[0] = (state == prev_slash || state == last_slash) ? '/' : '.'; dst[1] = '\0'; } return (0); } int path_is_accessible (const char *path, char *errbuf, size_t errbuflen) { int n; char buf [PATH_MAX]; struct stat st; char *p; n = path_canonicalize (path, buf, sizeof (buf)); if (n < 0) { return (_path_set_err (-1, errbuf, errbuflen, "cannot canonicalize \"%s\": %s", path, strerror (errno))); } if (n >= sizeof (buf)) { errno = ENAMETOOLONG; return (_path_set_err (-1, errbuf, errbuflen, "cannot canonicalize \"%s\": exceeded max path length", path)); } if (lstat (buf, &st) < 0) { return (_path_set_err (-1, errbuf, errbuflen, "cannot stat \"%s\": %s", buf, strerror (errno))); } if (!S_ISDIR (st.st_mode)) { if ((p = strrchr (buf, '/'))) { *p = '\0'; } } while (buf[0] != '\0') { if (lstat (buf, &st) < 0) { return (_path_set_err (-1, errbuf, errbuflen, "cannot stat \"%s\": %s", buf, strerror (errno))); } if (!S_ISDIR (st.st_mode)) { errno = EINVAL; return (_path_set_err (-1, errbuf, errbuflen, "cannot check \"%s\": unexpected file type", buf)); } if ((st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) != (S_IXUSR | S_IXGRP | S_IXOTH)) { return (_path_set_err (0, errbuf, errbuflen, "execute permissions for all required on \"%s\"", buf)); } if (!(p = strrchr (buf, '/'))) { errno = EINVAL; return (_path_set_err (-1, errbuf, errbuflen, "cannot check \"%s\": internal error", buf)); } if ((p == buf) && (buf[1] != '\0')) { p++; } *p = '\0'; } return (1); } int path_is_secure (const char *path, char *errbuf, size_t errbuflen, path_security_flag_t flags) { int n; char buf [PATH_MAX]; struct stat st; char *p; uid_t euid; n = path_canonicalize (path, buf, sizeof (buf)); if (n < 0) { return (_path_set_err (-1, errbuf, errbuflen, "cannot canonicalize \"%s\": %s", path, strerror (errno))); } if (n >= sizeof (buf)) { errno = ENAMETOOLONG; return (_path_set_err (-1, errbuf, errbuflen, "cannot canonicalize \"%s\": exceeded max path length", path)); } if (lstat (buf, &st) < 0) { return (_path_set_err (-1, errbuf, errbuflen, "cannot stat \"%s\": %s", buf, strerror (errno))); } if (!S_ISDIR (st.st_mode)) { if ((p = strrchr (buf, '/'))) { *p = '\0'; } } euid = geteuid (); while (buf[0] != '\0') { if (lstat (buf, &st) < 0) { return (_path_set_err (-1, errbuf, errbuflen, "cannot stat \"%s\": %s", buf, strerror (errno))); } if (!S_ISDIR (st.st_mode)) { errno = EINVAL; return (_path_set_err (-1, errbuf, errbuflen, "cannot check \"%s\": unexpected file type", buf)); } if ((st.st_uid != 0) && (st.st_uid != euid)) { return (_path_set_err (0, errbuf, errbuflen, "invalid ownership of \"%s\"", buf)); } if (!(flags & PATH_SECURITY_IGNORE_GROUP_WRITE) && (st.st_mode & S_IWGRP) && !(st.st_mode & S_ISVTX) && ((st.st_gid != _path_trusted_gid) || (_path_trusted_gid == GID_SENTINEL))) { return (_path_set_err (0, errbuf, errbuflen, "group-writable permissions without sticky bit set on \"%s\"", buf)); } if ((st.st_mode & S_IWOTH) && !(st.st_mode & S_ISVTX)) { return (_path_set_err (0, errbuf, errbuflen, "world-writable permissions without sticky bit set on \"%s\"", buf)); } if (!(p = strrchr (buf, '/'))) { errno = EINVAL; return (_path_set_err (-1, errbuf, errbuflen, "cannot check \"%s\": internal error", buf)); } if ((p == buf) && (buf[1] != '\0')) { p++; } *p = '\0'; } return (1); } int path_get_trusted_group (gid_t *gid_ptr) { if (_path_trusted_gid == GID_SENTINEL) { errno = ERANGE; return (-1); } if (gid_ptr != NULL) { *gid_ptr = _path_trusted_gid; } return (0); } int path_set_trusted_group (const char *group) { if (group == NULL) { _path_trusted_gid = GID_SENTINEL; return (0); } return (query_gid (group, &_path_trusted_gid)); } /***************************************************************************** * Internal Functions *****************************************************************************/ static int _path_set_err (int rc, char *buf, size_t buflen, const char *format, ...) { /* Sets an error condition to be returned to the caller. * If [buf] is non-NULL, the [format] string will be expanded and written * to the buffer [buf] of length [buflen]. * Returns [rc]. */ va_list vargs; if ((buf != NULL) && (buflen > 0)) { va_start (vargs, format); (void) vsnprintf (buf, buflen, format, vargs); buf [buflen - 1] = '\0'; va_end (vargs); } return (rc); } munge-munge-0.5.15/src/munged/path.h000066400000000000000000000104221425467526100172140ustar00rootroot00000000000000/***************************************************************************** * Written by Chris Dunlap . * Copyright (C) 2007-2022 Lawrence Livermore National Security, LLC. * Copyright (C) 2002-2007 The Regents of the University of California. * UCRL-CODE-155910. * * This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE). * For details, see . * * MUNGE 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. Additionally for the MUNGE library (libmunge), you * can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation, * either version 3 of the License, or (at your option) any later version. * * MUNGE 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 * and GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * and GNU Lesser General Public License along with MUNGE. If not, see * . *****************************************************************************/ #ifndef PATH_H #define PATH_H #if HAVE_CONFIG_H # include "config.h" #endif /* HAVE_CONFIG_H */ #include #include #ifndef PATH_MAX # define PATH_MAX 4096 #endif /* !PATH_MAX */ typedef enum path_security_flags { PATH_SECURITY_NO_FLAGS = 0x00, PATH_SECURITY_IGNORE_GROUP_WRITE = 0x01 } path_security_flag_t; int path_canonicalize (const char *src, char *dst, int dstlen); /* * Canonicalizes the path [src], returning an absolute pathname in the * buffer [dst] of length [dstlen]. * Canonicalization expands all symbolic links and resolves references to * '/./', '/../', and extra '/' characters. * Returns the strlen() of the canonicalized path; if retval >= dstlen, * truncation occurred. * Returns -1 on error (with errno set). */ int path_dirname (const char *src, char *dst, size_t dstlen); /* * Copies the parent directory name of [src] into the buffer [dst] of * length [dstlen]. Trailing '/' characters in the path are removed. * If [src] does not contain a '/', then [dst] is set to the string ".". * Returns 0 on success, or -1 on error (with errno set). */ int path_is_accessible (const char *path, char *errbuf, size_t errbuflen); /* * Checks if the specified [path] is accessible by all users. * Returns 1 if all checks pass, 0 if any checks fail, or -1 on error * (with errno set). * If [errbuf] is non-NULL, a message describing the inaccessibility or error * will be written to the buffer [errbuf] of length [errbuflen]. */ int path_is_secure (const char *path, char *errbuf, size_t errbuflen, path_security_flag_t flags); /* * Checks if the specified [path] is secure, ensuring that the base directory * cannot be modified by anyone other than the current user, the trusted * group (if set), or root. * Returns 1 if all checks pass, 0 if any checks fail, or -1 on error * (with errno set). * If [errbuf] is non-NULL, a message describing the insecurity or error * will be written to the buffer [errbuf] of length [errbuflen]. */ int path_get_trusted_group (gid_t *gid_ptr); /* * Gets the "trusted group" for permission checks on a directory hierarchy, * storing the GID at [gid_ptr]. * Returns 0 on success with the "trusted group" GID stored at [gid_ptr] * (if non-NULL). Returns -1 on error without updating [gid_ptr]. * Warning: Not thread-safe. */ int path_set_trusted_group (const char *group); /* * Sets the "trusted group" for permission checks on a directory hierarchy. * Directories with write permissions for group are allowed if they are * owned by the trusted group. * The [group] string can specify either a group name or GID. * If [group] is NULL, the trusted group setting is cleared. * Returns 0 on success, or -1 on error. * Warning: Not thread-safe. */ #endif /* !PATH_H */ munge-munge-0.5.15/src/munged/random.c000066400000000000000000000467211425467526100175460ustar00rootroot00000000000000/***************************************************************************** * Written by Chris Dunlap . * Copyright (C) 2007-2022 Lawrence Livermore National Security, LLC. * Copyright (C) 2002-2007 The Regents of the University of California. * UCRL-CODE-155910. * * This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE). * For details, see . * * MUNGE 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. Additionally for the MUNGE library (libmunge), you * can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation, * either version 3 of the License, or (at your option) any later version. * * MUNGE 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 * and GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * and GNU Lesser General Public License along with MUNGE. If not, see * . *****************************************************************************/ #if HAVE_CONFIG_H # include #endif /* HAVE_CONFIG_H */ #include #include #include #include #include #include #include #include #include "common.h" #include "conf.h" #include "crypto.h" #include "entropy.h" #include "log.h" #include "munge_defs.h" #include "path.h" #include "random.h" #include "timer.h" /***************************************************************************** * Constants *****************************************************************************/ /* Integer for the number of bytes to read from the random number source * device when seeding the PRNG entropy pool. * Note that an upper limit of 256 bytes is imposed when using either * getentropy() or getrandom(). */ #define RANDOM_SOURCE_BYTES 128 /* Integer for the number of bytes to read from (and write to) the seed file. */ #define RANDOM_SEED_BYTES 1024 /* Integer for the minimum number of bytes needed to adequately seed the * PRNG entropy pool. */ #define RANDOM_BYTES_MIN 128 /* Integer for the minimum number of bytes wanted to seed the PRNG entropy * pool. This is set such that "enhanced stirring" (i.e., starting the PRNG * stir timer's exponential backoff interval at 1) will be enabled unless * there is entropy from both the kernel source and the seed file. */ #define RANDOM_BYTES_WANTED 1152 /* Integer for the maximum number of seconds between stirrings of the PRNG * entropy pool. If set to 0, entropy pool stirrings will be disabled. */ #define RANDOM_STIR_MAX_SECS 32768 /***************************************************************************** * Private Data *****************************************************************************/ static long _random_timer_id = 0; /* timer ID for entropy pool stir */ static int _random_stir_secs; /* secs between entropy pool stirs */ /***************************************************************************** * Private Prototypes *****************************************************************************/ static int _random_read_entropy_from_kernel (void); static int _random_read_entropy_from_file (const char *path); static int _random_read_entropy_from_process (void); static int _random_read_seed (const char *path, int num_bytes); static int _random_write_seed (const char *path, int num_bytes); static int _random_check_entropy (unsigned char *buf, int n); static void _random_stir_entropy (void *_arg_not_used_); static void _random_cleanup (void); static void _random_add (const void *buf, int n); static void _random_bytes (void *buf, int n); static void _random_pseudo_bytes (void *buf, int n); /***************************************************************************** * Public Functions *****************************************************************************/ int random_init (const char *seed_path) { int num_bytes_entropy = 0; int got_bad_seed = 0; int n; /* Fill the entropy pool. */ n = _random_read_entropy_from_kernel (); if (n > 0) { num_bytes_entropy += n; } if (seed_path) { n = _random_read_entropy_from_file (seed_path); if (n > 0) { num_bytes_entropy += n; } else if (n < 0) { got_bad_seed = 1; } } n = _random_read_entropy_from_process (); if (n > 0) { num_bytes_entropy += n; } if (num_bytes_entropy < RANDOM_BYTES_MIN) { log_err_or_warn (conf->got_force, "Failed to seed PRNG with sufficient entropy"); } /* Compute the initial time interval for stirring the entropy pool. * If the desired amount of entropy is not available, increase the * initial rate of stirring to mix stuff up. Otherwise, just stir * at the max interval. */ if (conf->got_benchmark || (RANDOM_STIR_MAX_SECS <= 0)) { _random_stir_secs = 0; log_msg (LOG_INFO, "Disabled PRNG entropy pool stirring"); } else if (num_bytes_entropy < RANDOM_BYTES_WANTED) { _random_stir_secs = 1; log_msg (LOG_INFO, "Enabled PRNG entropy pool enhanced stirring"); } else { _random_stir_secs = RANDOM_STIR_MAX_SECS; } /* Schedule repeated stirring of the entropy pool. */ if (_random_stir_secs > 0) { _random_stir_entropy (NULL); } if (got_bad_seed) { return (-1); } if (num_bytes_entropy < RANDOM_BYTES_WANTED) { return (0); } return (1); } void random_fini (const char *seed_path) { if (_random_timer_id > 0) { timer_cancel (_random_timer_id); } if (seed_path != NULL) { (void) _random_write_seed (seed_path, RANDOM_SEED_BYTES); } _random_cleanup (); return; } void random_add (const void *buf, int n) { if (!buf || (n <= 0)) { return; } _random_add (buf, n); return; } void random_bytes (void *buf, int n) { if (!buf || (n <= 0)) { return; } _random_bytes (buf, n); return; } void random_pseudo_bytes (void *buf, int n) { if (!buf || (n <= 0)) { return; } _random_pseudo_bytes (buf, n); return; } /***************************************************************************** * Private Functions (Common) *****************************************************************************/ static int _random_read_entropy_from_kernel (void) { /* Reads entropy from the kernel's CSPRNG. * Returns the number of bytes of entropy added, or -1 on error. */ int n; const char *src; unsigned char buf [RANDOM_SOURCE_BYTES]; n = entropy_read (buf, sizeof (buf), &src); if (n > 0) { if (_random_check_entropy (buf, n) < 0) { n = 0; log_msg (LOG_WARNING, "Ignoring entropy from kernel: does not appear random"); } else { _random_add (buf, n); log_msg (LOG_INFO, "Seeded PRNG with %d byte%s from %s", n, (n == 1 ? "" : "s"), (src != NULL) ? src : "???"); } } return (n); } static int _random_read_entropy_from_file (const char *path) { /* Reads entropy from the seed file specified by 'path'. * Returns the number of bytes of entropy added, or -1 on error. */ int is_path_secure = 0; int n; char dir [PATH_MAX]; char ebuf [1024]; int rv; if ((path == NULL) || (path[0] == '\0')) { errno = EINVAL; return (-1); } if (path_dirname (path, dir, sizeof (dir)) < 0) { log_err (EMUNGE_SNAFU, LOG_ERR, "Failed to determine dirname of PRNG seed \"%s\"", path); } n = path_is_secure (dir, ebuf, sizeof (ebuf), PATH_SECURITY_NO_FLAGS); if (n < 0) { log_err (EMUNGE_SNAFU, LOG_ERR, "Failed to check PRNG seed dir \"%s\": %s", dir, ebuf); } else if (n == 0) { log_err_or_warn (conf->got_force, "PRNG seed dir is insecure: %s", ebuf); } else { is_path_secure = 1; } n = _random_read_seed (path, RANDOM_SEED_BYTES); if (n < 0) { do { rv = unlink (path); } while ((rv < 0) && (errno == EINTR)); if ((rv < 0) && (errno != ENOENT)) { log_msg (LOG_WARNING, "Failed to remove insecure PRNG seed \"%s\": %s", path, strerror (errno)); } else if (rv == 0) { log_msg (LOG_INFO, "Removed insecure PRNG seed \"%s\"", path); } n = 0; } return (!is_path_secure ? -1 : n); } static int _random_read_entropy_from_process (void) { /* Reads entropy from sources related to the process. * Returns the number of bytes of entropy added, or -1 on error. */ unsigned buf; int n = 0; if (entropy_read_uint (&buf) != -1) { _random_add (&buf, sizeof (buf)); n += sizeof (buf); } return (n); } static int _random_read_seed (const char *path, int num_bytes) { /* Reads up to 'num_bytes' from the seed file specified by 'path', * and adds them to the PRNG entropy pool. * Returns the number of bytes read, or -1 on error. */ int fd; int is_symlink; int is_valid = 0; int num_left = num_bytes; int num_want; int n; struct stat st; unsigned char buf [RANDOM_SEED_BYTES]; assert (path != NULL); assert (num_bytes > 0); /* Do not allow symbolic links in 'path' since the parent directories in * the path of the actual file have not been checked to ensure they are * secure. */ is_symlink = (lstat (path, &st) == 0) ? S_ISLNK (st.st_mode) : 0; if (is_symlink) { log_msg (LOG_WARNING, "Ignoring PRNG seed \"%s\": must not be a symbolic link", path); return (-1); } do { fd = open (path, O_RDONLY); } while ((fd < 0) && (errno == EINTR)); if (fd < 0) { if (errno == ENOENT) { return (0); } log_msg (LOG_WARNING, "Failed to open PRNG seed \"%s\": %s", path, strerror (errno)); return (-1); } /* File is now open. Do not prematurely return until it has been closed. */ if (fstat (fd, &st) < 0) { log_msg (LOG_WARNING, "Failed to stat PRNG seed \"%s\": %s", path, strerror (errno)); } else if (!S_ISREG (st.st_mode)) { log_msg (LOG_WARNING, "Ignoring PRNG seed \"%s\": must be a regular file " "(type=%07o)", path, (st.st_mode & S_IFMT)); } else if (st.st_uid != geteuid ()) { log_msg (LOG_WARNING, "Ignoring PRNG seed \"%s\": must be owned by " "UID %u instead of UID %u", path, (unsigned) geteuid (), (unsigned) st.st_uid); } else if (st.st_mode & (S_IRGRP | S_IWGRP)) { log_msg (LOG_WARNING, "Ignoring PRNG seed \"%s\": must not be readable or writable " "by group (perms=%04o)", path, (st.st_mode & ~S_IFMT)); } else if (st.st_mode & (S_IROTH | S_IWOTH)) { log_msg (LOG_WARNING, "Ignoring PRNG seed \"%s\": must not be readable or writable " "by other (perms=%04o)", path, (st.st_mode & ~S_IFMT)); } else { is_valid = 1; while (num_left > 0) { num_want = (num_left < sizeof (buf)) ? num_left : sizeof (buf); n = fd_read_n (fd, buf, num_want); if (n < 0) { log_msg (LOG_WARNING, "Failed to read from PRNG seed \"%s\": %s", path, strerror (errno)); break; } if (n == 0) { break; } _random_add (buf, n); num_left -= n; } } if (close (fd) < 0) { log_msg (LOG_WARNING, "Failed to close PRNG seed \"%s\": %s", path, strerror (errno)); } n = num_bytes - num_left; if (n > 0) { log_msg (LOG_INFO, "Seeded PRNG with %d byte%s from \"%s\"", n, (n == 1 ? "" : "s"), path); } return (!is_valid ? -1 : n); } static int _random_write_seed (const char *path, int num_bytes) { /* Writes 'num_bytes' of random bytes to the seed file specified by 'path'. * Returns the number of bytes written, or -1 on error. */ int rv; int fd; int num_left; int num_want; int n; unsigned char buf [RANDOM_SEED_BYTES]; assert (path != NULL); assert (num_bytes > 0); do { rv = unlink (path); } while ((rv < 0) && (errno == EINTR)); if ((rv < 0) && (errno != ENOENT)) { log_msg (LOG_WARNING, "Failed to unlink old PRNG seed \"%s\": %s", path, strerror (errno)); } do { fd = open (path, O_WRONLY | O_CREAT | O_TRUNC, 0600); } while ((fd < 0) && (errno == EINTR)); if (fd < 0) { log_msg (LOG_WARNING, "Failed to create PRNG seed \"%s\": %s", path, strerror (errno)); return (-1); } num_left = num_bytes; while (num_left > 0) { num_want = (num_left < sizeof (buf)) ? num_left : sizeof (buf); _random_bytes (buf, num_want); n = fd_write_n (fd, buf, num_want); if (n < 0) { log_msg (LOG_WARNING, "Failed to write to PRNG seed \"%s\": %s", path, strerror (errno)); break; } num_left -= n; } if (close (fd) < 0) { log_msg (LOG_WARNING, "Failed to close PRNG seed \"%s\": %s", path, strerror (errno)); } n = num_bytes - num_left; if (n > 0) { log_msg (LOG_INFO, "Wrote %d byte%s to PRNG seed \"%s\"", n, (n == 1 ? "" : "s"), path); } return (n); } static int _random_check_entropy (unsigned char *buf, int n) { /* Checks if the buffer 'buf' of length 'n' contains sufficient entropy. * This is just a simple approximation to guard against an egregiously * broken or fraudulent entropy source. * Returns 0 if entropy appears sufficient; o/w returns -1. */ unsigned char c; int i; int cnt; int lim; assert (buf != NULL); assert (n > 0); c = buf[0]; for (i = 0, cnt = 0; i < n; i++) { if (buf[i] == c) { cnt++; } } /* This just checks if 'buf' is entirely filled with the same byte. */ lim = n; if (cnt >= lim) { return (-1); } return (0); } static void _random_stir_entropy (void *_arg_not_used_) { /* Periodically stirs the entropy pool by mixing in new entropy. */ unsigned buf; int msecs; assert (RANDOM_STIR_MAX_SECS > 0); if (_random_stir_secs <= 0) { return; } _random_timer_id = 0; log_msg (LOG_DEBUG, "Stirring PRNG entropy pool"); if (entropy_read_uint (&buf) != -1) { _random_add (&buf, sizeof (buf)); } /* Perform an exponential backoff up to the maximum timeout. This allows * for vigorous stirring of the entropy pool when the daemon is started. */ if (_random_stir_secs < RANDOM_STIR_MAX_SECS) { _random_stir_secs = MIN(_random_stir_secs * 2, RANDOM_STIR_MAX_SECS); } /* The 10 low-order bits are used to stagger subsequent timer callbacks * by up to 1023ms. */ msecs = (_random_stir_secs * 1000) + (buf & 0x3FF); _random_timer_id = timer_set_relative ( (callback_f) _random_stir_entropy, NULL, msecs); if (_random_timer_id < 0) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to set PRNG stir timer"); } return; } /***************************************************************************** * Private Functions (Libgcrypt) *****************************************************************************/ #if HAVE_LIBGCRYPT #include #include "fd.h" static void _random_cleanup (void) { return; } static void _random_add (const void *buf, int n) { gcry_error_t e; assert (buf != NULL); assert (n > 0); e = gcry_random_add_bytes (buf, n, -1); if (e) { log_msg (LOG_WARNING, "Failed to add %d byte%s to entropy pool: %s", n, (n == 1 ? "" : "s"), gcry_strerror (e)); } gcry_fast_random_poll (); return; } static void _random_bytes (void *buf, int n) { assert (buf != NULL); assert (n > 0); gcry_randomize (buf, n, GCRY_STRONG_RANDOM); return; } static void _random_pseudo_bytes (void *buf, int n) { assert (buf != NULL); assert (n > 0); gcry_create_nonce (buf, n); return; } #endif /* HAVE_LIBGCRYPT */ /***************************************************************************** * Private Functions (OpenSSL) *****************************************************************************/ #if HAVE_OPENSSL #include #include #include static void _random_cleanup (void) { #if HAVE_RAND_CLEANUP /* OpenSSL < 1.1.0 */ RAND_cleanup (); #endif /* HAVE_RAND_CLEANUP */ return; } static void _random_add (const void *buf, int n) { assert (buf != NULL); assert (n > 0); RAND_seed (buf, n); return; } static void _random_bytes (void *buf, int n) { int rc; assert (buf != NULL); assert (n > 0); rc = RAND_bytes (buf, n); if (rc == -1) { log_msg (LOG_ERR, "RAND_bytes failed: not supported by OpenSSL RAND method"); } else if (rc == 0) { unsigned long e = ERR_get_error (); log_msg (LOG_WARNING, "RAND_bytes failed: %s", ERR_reason_error_string (e)); } return; } static void _random_pseudo_bytes (void *buf, int n) { int rc; assert (buf != NULL); assert (n > 0); /* RAND_pseudo_bytes() was deprecated in OpenSSL 1.1.0. Unfortunately, * AC_CHECK_FUNCS(RAND_pseudo_bytes) still sets HAVE_RAND_PSEUDO_BYTES * since the function exists (albeit with the "deprecated" attribute). * This results in a deprecated-declarations warning when compiling * against OpenSSL >1.1.0. And that warning will break the build if * "-Werror" is specified (as is the case for the Travis CI build). * The check for OPENSSL_VERSION_NUMBER from * handles this case. */ #if HAVE_RAND_PSEUDO_BYTES && (OPENSSL_VERSION_NUMBER < 0x10100000L) /* OpenSSL >= 0.9.5, < 1.1.0 */ rc = RAND_pseudo_bytes (buf, n); if (rc == -1) { log_msg (LOG_ERR, "RAND_pseudo_bytes failed: " "not supported by OpenSSL RAND method"); } else if (rc == 0) { unsigned long e = ERR_get_error (); log_msg (LOG_WARNING, "RAND_pseudo_bytes failed: %s", ERR_reason_error_string (e)); } #else /* !HAVE_RAND_PSEUDO_BYTES */ _random_bytes (buf, n); (void) rc; /* suppress unused-variable warning */ #endif /* !HAVE_RAND_PSEUDO_BYTES */ return; } #endif /* HAVE_OPENSSL */ munge-munge-0.5.15/src/munged/random.h000066400000000000000000000044471425467526100175520ustar00rootroot00000000000000/***************************************************************************** * Written by Chris Dunlap . * Copyright (C) 2007-2022 Lawrence Livermore National Security, LLC. * Copyright (C) 2002-2007 The Regents of the University of California. * UCRL-CODE-155910. * * This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE). * For details, see . * * MUNGE 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. Additionally for the MUNGE library (libmunge), you * can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation, * either version 3 of the License, or (at your option) any later version. * * MUNGE 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 * and GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * and GNU Lesser General Public License along with MUNGE. If not, see * . *****************************************************************************/ #ifndef RANDOM_H #define RANDOM_H int random_init (const char *seed_path); /* * Initializes the PRNG from [seed_path] and other sources. * Returns 1 if sufficient entropy is gathered, 0 if insufficient entropy * is gathered but no errors were detected, or -1 on error. */ void random_fini (const char *seed_path); /* * Shuts down the PRNG, writing the state of the entropy pool to [seed_path]. */ void random_add (const void *buf, int n); /* * Adds [n] bytes of entropy from [buf] to the PRNG entropy pool. */ void random_bytes (void *buf, int n); /* * Places [n] bytes of cryptographically-strong pseudo-random data into [buf]. */ void random_pseudo_bytes (void *buf, int n); /* * Places [n] bytes of pseudo-random data into [buf]. * This should not be used for purposes such as key generation. */ #endif /* !RANDOM_H */ munge-munge-0.5.15/src/munged/replay.c000066400000000000000000000266321425467526100175610ustar00rootroot00000000000000/***************************************************************************** * Written by Chris Dunlap . * Copyright (C) 2007-2022 Lawrence Livermore National Security, LLC. * Copyright (C) 2002-2007 The Regents of the University of California. * UCRL-CODE-155910. * * This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE). * For details, see . * * MUNGE 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. Additionally for the MUNGE library (libmunge), you * can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation, * either version 3 of the License, or (at your option) any later version. * * MUNGE 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 * and GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * and GNU Lesser General Public License along with MUNGE. If not, see * . *****************************************************************************/ #if HAVE_CONFIG_H # include #endif /* HAVE_CONFIG_H */ #include #include #include #include #include #include "conf.h" #include "cred.h" #include "hash.h" #include "log.h" #include "m_msg.h" #include "munge_defs.h" #include "replay.h" #include "thread.h" #include "timer.h" /***************************************************************************** * Private Constants *****************************************************************************/ #define REPLAY_HASH_SIZE 65537 #define REPLAY_NODE_ALLOC_NUM 1024 /***************************************************************************** * Private Data Types *****************************************************************************/ union replay_node { struct { union replay_node *next; /* ptr for chaining by allocator */ } alloc; struct { time_t t_expired; /* time after which cred expires */ unsigned char mac [MUNGE_MINIMUM_MD_LEN]; /* msg auth code */ } data; }; typedef union replay_node * replay_t; /***************************************************************************** * Private Prototypes *****************************************************************************/ static unsigned int replay_key_f (const replay_t r); static int replay_cmp_f (const replay_t r1, const replay_t r2); static int replay_is_expired (replay_t r, void *key, time_t *pnow); static replay_t replay_alloc (void); static void replay_free (replay_t r); static void replay_drop_memory (void); /***************************************************************************** * Private Variables *****************************************************************************/ static hash_t replay_hash = NULL; /* * Hash table for tracking decoded credentials until they have expired * in order to prevent reuse. */ static replay_t replay_mem_list = NULL; /* * Singly-linked list for tracking memory allocations from replay_alloc() for * eventual de-allocation via replay_drop_memory(). Each block allocation * begins with a pointer for chaining these allocations together. The block * is broken up into individual replay_t objects and placed on the * replay_free_list. */ static replay_t replay_free_list = NULL; /* * Singly-linked list of replay_t objects available for use. These are * allocated via replay_alloc() in blocks of REPLAY_NODE_ALLOC_NUM. This * bulk approach uses less RAM and CPU than allocating/de-allocating objects * individually as needed. */ static pthread_mutex_t replay_free_list_lock = PTHREAD_MUTEX_INITIALIZER; /* * Mutex for protecting access to replay_mem_list and replay_free_list. */ /***************************************************************************** * Public Functions *****************************************************************************/ void replay_init (void) { /* Initializes the replay detection engine. */ hash_key_f keyf = (hash_key_f) replay_key_f; hash_cmp_f cmpf = (hash_cmp_f) replay_cmp_f; hash_del_f delf = (hash_del_f) replay_free; if (replay_hash != NULL) { return; } if (conf->got_benchmark) { log_msg (LOG_INFO, "Disabled replay hash"); return; } if (!(replay_hash = hash_create (REPLAY_HASH_SIZE, keyf, cmpf, delf))) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to allocate replay hash"); } if (timer_set_relative ( (callback_f) replay_purge, NULL, MUNGE_REPLAY_PURGE_SECS * 1000) < 0) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to set replay purge timer"); } return; } void replay_fini (void) { /* Terminates the replay detection engine. * * Race conditions may result if the replay hash is removed while * replay_purge() timers are active. Consequently, the timer thread * is canceled via timer_fini() as soon as munged's event loop is exited. * And shortly _thereafter_, this routine is invoked. */ if (!replay_hash) { return; } hash_destroy (replay_hash); replay_hash = NULL; replay_drop_memory (); return; } int replay_insert (munge_cred_t c) { /* Inserts the credential [c] into the replay hash. * The credential is identified by the first N bytes of the MAC, where N * is the minimum message digest length used by MUNGE. Limiting the MAC * length here helps to reduce the replay cache memory requirements. * Returns 0 if the credential is successfully inserted. * Returns 1 if the credential is already present (ie, replay). * Returns -1 on error with errno set. */ m_msg_t m; int e; replay_t r; if (!replay_hash) { if (conf->got_benchmark) return (0); errno = EPERM; return (-1); } if (c == NULL) { errno = EINVAL; return (-1); } m = c->msg; if (!(r = replay_alloc ())) { return (-1); } r->data.t_expired = (time_t) (m->time0 + m->ttl); assert (c->mac_len >= sizeof (r->data.mac)); memcpy (r->data.mac, c->mac, sizeof (r->data.mac)); /* * The replay hash key is just the replay_t object itself. */ if (hash_insert (replay_hash, r, r) != NULL) { return (0); } e = errno; replay_free (r); if (e == EEXIST) { return (1); } if (e == EINVAL) { log_err (EMUNGE_SNAFU, LOG_ERR, "Attempted to insert cred into hash using invalid args"); } return (-1); } int replay_remove (munge_cred_t c) { /* Removes the credential [c] from the replay hash. */ m_msg_t m; union replay_node rnode; replay_t r; if (!replay_hash) { if (conf->got_benchmark) return (0); errno = EPERM; return (-1); } if (c == NULL) { errno = EINVAL; return (-1); } m = c->msg; /* Compute the cred's "hash key". */ rnode.data.t_expired = (time_t) (m->time0 + m->ttl); assert (c->mac_len >= sizeof (rnode.data.mac)); memcpy (rnode.data.mac, c->mac, sizeof (rnode.data.mac)); r = hash_remove (replay_hash, &rnode); if (r != NULL) { replay_free (r); } return (r ? 0 : -1); } void replay_purge (void) { /* Purges the replay hash of any expired credentials. */ time_t now; int n; if (!replay_hash) { return; } if (time (&now) == (time_t) -1) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to query current time"); } n = hash_delete_if (replay_hash, (hash_arg_f) replay_is_expired, &now); assert (n >= 0); if (n > 0) { log_msg (LOG_DEBUG, "Purged %d credential%s from replay hash", n, ((n == 1) ? "" : "s")); } if (timer_set_relative ( (callback_f) replay_purge, NULL, MUNGE_REPLAY_PURGE_SECS * 1000) < 0) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to set replay purge timer"); } return; } /***************************************************************************** * Private Functions *****************************************************************************/ static unsigned int replay_key_f (const replay_t r) { /* Use the first 4 bytes of the cred's mac as the hash key. * While the results of this conversion are dependent on byte sex, * we can ignore it since this data is local to the node. */ return (* (unsigned int *) r->data.mac); } static int replay_cmp_f (const replay_t r1, const replay_t r2) { /* Returns an integer that is less than zero if [r1] is less than [r2], * equal to zero if [r1] is equal to [r2], and greater than zero * if [r1] is greater than [r2]. */ int cmpval; cmpval = memcmp (r1->data.mac, r2->data.mac, sizeof (r1->data.mac)); if (cmpval != 0) { return (cmpval); } if (r1->data.t_expired < r2->data.t_expired) { return (-1); } if (r1->data.t_expired > r2->data.t_expired) { return (1); } return (0); } static int replay_is_expired (replay_t r, void *key, time_t *pnow) { /* Returns true if replay_t object [r] has expired based on the time [pnow]. */ if (r->data.t_expired < *pnow) { return (1); } return (0); } static replay_t replay_alloc (void) { /* Allocates a replay_t object. * Returns a ptr to the object, or NULL if memory allocation fails. */ size_t size; replay_t r; int i; assert (REPLAY_NODE_ALLOC_NUM > 0); lsd_mutex_lock (&replay_free_list_lock); if (!replay_free_list) { size = sizeof (r) + (REPLAY_NODE_ALLOC_NUM * sizeof (*r)); r = malloc (size); if (r != NULL) { r->alloc.next = replay_mem_list; replay_mem_list = r; replay_free_list = (replay_t) ((unsigned char *) r + sizeof (r)); for (i = 0; i < REPLAY_NODE_ALLOC_NUM - 1; i++) { replay_free_list[i].alloc.next = &replay_free_list[i+1]; } replay_free_list[i].alloc.next = NULL; } } if (replay_free_list) { r = replay_free_list; replay_free_list = r->alloc.next; memset (r, 0, sizeof (*r)); } else { errno = ENOMEM; } lsd_mutex_unlock (&replay_free_list_lock); return (r); } static void replay_free (replay_t r) { /* De-allocates the replay_t object [r]. */ assert (r != NULL); lsd_mutex_lock (&replay_free_list_lock); r->alloc.next = replay_free_list; replay_free_list = r; lsd_mutex_unlock (&replay_free_list_lock); return; } static void replay_drop_memory (void) { /* Frees memory that has been internally allocated for replay_t objects. * This routine should only be called via replay_fini() after replay_hash * has been destroyed. */ replay_t r; lsd_mutex_lock (&replay_free_list_lock); while (replay_mem_list != NULL) { r = replay_mem_list; replay_mem_list = r->alloc.next; free (r); } replay_free_list = NULL; lsd_mutex_unlock (&replay_free_list_lock); return; } munge-munge-0.5.15/src/munged/replay.h000066400000000000000000000035601425467526100175610ustar00rootroot00000000000000/***************************************************************************** * Written by Chris Dunlap . * Copyright (C) 2007-2022 Lawrence Livermore National Security, LLC. * Copyright (C) 2002-2007 The Regents of the University of California. * UCRL-CODE-155910. * * This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE). * For details, see . * * MUNGE 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. Additionally for the MUNGE library (libmunge), you * can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation, * either version 3 of the License, or (at your option) any later version. * * MUNGE 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 * and GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * and GNU Lesser General Public License along with MUNGE. If not, see * . *****************************************************************************/ #ifndef REPLAY_H #define REPLAY_H #include "cred.h" /***************************************************************************** * Public Functions *****************************************************************************/ void replay_init (void); void replay_fini (void); int replay_insert (munge_cred_t c); int replay_remove (munge_cred_t c); void replay_purge (void); #endif /* !REPLAY_H */ munge-munge-0.5.15/src/munged/thread.c000066400000000000000000000036421425467526100175300ustar00rootroot00000000000000/***************************************************************************** * Written by Chris Dunlap . * Copyright (C) 2007-2022 Lawrence Livermore National Security, LLC. * Copyright (C) 2002-2007 The Regents of the University of California. * UCRL-CODE-155910. * * This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE). * For details, see . * * MUNGE 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. Additionally for the MUNGE library (libmunge), you * can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation, * either version 3 of the License, or (at your option) any later version. * * MUNGE 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 * and GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * and GNU Lesser General Public License along with MUNGE. If not, see * . *****************************************************************************/ #if HAVE_CONFIG_H # include "config.h" #endif /* HAVE_CONFIG_H */ #include #include #include #include "thread.h" #if WITH_PTHREADS #ifndef NDEBUG int lsd_mutex_is_locked (pthread_mutex_t *mutex) { /* Returns true if the mutex is locked; o/w, returns false. */ int rc; assert (mutex != NULL); rc = pthread_mutex_trylock (mutex); return (rc == EBUSY ? 1 : 0); } #endif /* !NDEBUG */ #endif /* WITH_PTHREADS */ munge-munge-0.5.15/src/munged/thread.h000066400000000000000000000120521425467526100175300ustar00rootroot00000000000000/***************************************************************************** * Written by Chris Dunlap . * Copyright (C) 2007-2022 Lawrence Livermore National Security, LLC. * Copyright (C) 2002-2007 The Regents of the University of California. * UCRL-CODE-155910. * * This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE). * For details, see . * * MUNGE 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. Additionally for the MUNGE library (libmunge), you * can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation, * either version 3 of the License, or (at your option) any later version. * * MUNGE 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 * and GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * and GNU Lesser General Public License along with MUNGE. If not, see * . *****************************************************************************/ #ifndef LSD_THREAD_H #define LSD_THREAD_H #if WITH_PTHREADS # include # include # include #endif /* WITH_PTHREADS */ /***************************************************************************** * Macros *****************************************************************************/ #if WITH_PTHREADS # ifdef WITH_LSD_FATAL_ERROR_FUNC # undef lsd_fatal_error extern void lsd_fatal_error (char *file, int line, char *mesg); # else /* !WITH_LSD_FATAL_ERROR_FUNC */ # ifndef lsd_fatal_error # define lsd_fatal_error(file, line, mesg) (abort ()) # endif /* !lsd_fatal_error */ # endif /* !WITH_LSD_FATAL_ERROR_FUNC */ # define lsd_mutex_init(pmutex) \ do { \ int e = pthread_mutex_init (pmutex, NULL); \ if (e != 0) { \ errno = e; \ lsd_fatal_error (__FILE__, __LINE__, "mutex_init"); \ abort (); \ } \ } while (0) # define lsd_mutex_lock(pmutex) \ do { \ int e = pthread_mutex_lock (pmutex); \ if (e != 0) { \ errno = e; \ lsd_fatal_error (__FILE__, __LINE__, "mutex_lock"); \ abort (); \ } \ } while (0) # define lsd_mutex_unlock(pmutex) \ do { \ int e = pthread_mutex_unlock (pmutex); \ if (e != 0) { \ errno = e; \ lsd_fatal_error (__FILE__, __LINE__, "mutex_unlock"); \ abort (); \ } \ } while (0) # define lsd_mutex_destroy(pmutex) \ do { \ int e = pthread_mutex_destroy (pmutex); \ if (e != 0) { \ errno = e; \ lsd_fatal_error (__FILE__, __LINE__, "mutex_destroy"); \ abort (); \ } \ } while (0) # ifndef NDEBUG int lsd_mutex_is_locked (pthread_mutex_t *pmutex); # endif /* !NDEBUG */ #else /* !WITH_PTHREADS */ # define lsd_mutex_init(mutex) # define lsd_mutex_lock(mutex) # define lsd_mutex_unlock(mutex) # define lsd_mutex_destroy(mutex) # define lsd_mutex_is_locked(mutex) (1) #endif /* !WITH_PTHREADS */ #endif /* !LSD_THREAD_H */ munge-munge-0.5.15/src/munged/timer.c000066400000000000000000000374261425467526100174100ustar00rootroot00000000000000/***************************************************************************** * Written by Chris Dunlap . * Copyright (C) 2007-2022 Lawrence Livermore National Security, LLC. * Copyright (C) 2002-2007 The Regents of the University of California. * UCRL-CODE-155910. * * This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE). * For details, see . * * MUNGE 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. Additionally for the MUNGE library (libmunge), you * can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation, * either version 3 of the License, or (at your option) any later version. * * MUNGE 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 * and GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * and GNU Lesser General Public License along with MUNGE. If not, see * . ***************************************************************************** * Based on ideas from: * - David R. Butenhof's "Programming with POSIX Threads" (Section 3.3.4) * - Jon C. Snader's "Effective TCP/IP Programming" (Tip #20) ***************************************************************************** * Refer to "timer.h" for documentation on public functions. *****************************************************************************/ #if HAVE_CONFIG_H # include #endif /* HAVE_CONFIG_H */ #include #include #include #include #include #include #include #include #include "clock.h" #include "log.h" #include "thread.h" #include "timer.h" /***************************************************************************** * Private Data Types *****************************************************************************/ struct timer { long id; /* timer ID */ struct timespec ts; /* expiration time */ callback_f f; /* callback function */ void *arg; /* callback function arg */ struct timer *next; /* next timer in list */ }; typedef struct timer * timer_p; /***************************************************************************** * Private Prototypes *****************************************************************************/ static void * _timer_thread (void *arg); static void _timer_thread_cleanup (void *arg); static timer_p _timer_alloc (void); /***************************************************************************** * Private Variables *****************************************************************************/ static pthread_t _timer_tid = 0; static pthread_cond_t _timer_cond = PTHREAD_COND_INITIALIZER; static pthread_mutex_t _timer_mutex = PTHREAD_MUTEX_INITIALIZER; /* The _timer_id is the ID of the last timer that was set. */ static long _timer_id = 0; /* The _timer_active list contains timers waiting to be dispatched, sorted in * order of increasing timespecs; the list head is the next timer to expire. */ static timer_p _timer_active = NULL; /* The _timer_inactive list contains timers that have been dispatched and can * be reused without allocating more memory. */ static timer_p _timer_inactive = NULL; /***************************************************************************** * Public Functions *****************************************************************************/ void timer_init (void) { pthread_attr_t tattr; size_t stacksize = 256 * 1024; if (_timer_tid != 0) { return; } if ((errno = pthread_attr_init (&tattr)) != 0) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to init timer thread attribute"); } #ifdef _POSIX_THREAD_ATTR_STACKSIZE if ((errno = pthread_attr_setstacksize (&tattr, stacksize)) != 0) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to set timer thread stacksize"); } if ((errno = pthread_attr_getstacksize (&tattr, &stacksize)) != 0) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to get timer thread stacksize"); } log_msg (LOG_DEBUG, "Set timer thread stacksize to %d", (int) stacksize); #endif /* _POSIX_THREAD_ATTR_STACKSIZE */ if ((errno = pthread_create (&_timer_tid, &tattr, _timer_thread, NULL)) != 0) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to create timer thread"); } if ((errno = pthread_attr_destroy (&tattr)) != 0) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to destroy timer thread attribute"); } return; } void timer_fini (void) { void *result; timer_p *t_prev_ptr; timer_p t; if (_timer_tid == 0) { return; } if ((errno = pthread_cancel (_timer_tid)) != 0) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to cancel timer thread"); } if ((errno = pthread_join (_timer_tid, &result)) != 0) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to join timer thread"); } if (result != PTHREAD_CANCELED) { log_err (EMUNGE_SNAFU, LOG_ERR, "Timer thread was not canceled"); } _timer_tid = 0; if ((errno = pthread_mutex_lock (&_timer_mutex)) != 0) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to lock timer mutex"); } /* Cancel pending timers by moving active timers to the inactive list. */ if (_timer_active) { t_prev_ptr = &_timer_active; while (*t_prev_ptr) { t_prev_ptr = &(*t_prev_ptr)->next; } *t_prev_ptr = _timer_inactive; _timer_inactive = _timer_active; _timer_active = NULL; } /* De-allocate timers. */ while (_timer_inactive) { t = _timer_inactive; _timer_inactive = _timer_inactive->next; free (t); } if ((errno = pthread_mutex_unlock (&_timer_mutex)) != 0) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to unlock timer mutex"); } return; } long timer_set_absolute (callback_f cb, void *arg, const struct timespec *tsp) { timer_p t; timer_p *t_prev_ptr; int do_signal = 0; if (!cb || !tsp) { errno = EINVAL; return (-1); } if ((errno = pthread_mutex_lock (&_timer_mutex)) != 0) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to lock timer mutex"); } if (!(t = _timer_alloc ())) { log_errno (EMUNGE_NO_MEMORY, LOG_ERR, "Failed to allocate timer"); } /* Initialize the timer. */ _timer_id++; if (_timer_id <= 0) { _timer_id = 1; } t->id = _timer_id; t->f = cb; t->arg = arg; t->ts = *tsp; /* Insert the timer into the active list. */ t_prev_ptr = &_timer_active; while (*t_prev_ptr && clock_is_timespec_le (&(*t_prev_ptr)->ts, &t->ts)) { t_prev_ptr = &(*t_prev_ptr)->next; } t->next = *t_prev_ptr; *t_prev_ptr = t; /* Only signal the timer thread if the active timer has changed. * Set a flag here so the signal can be done outside the monitor lock. */ if (t_prev_ptr == &_timer_active) { do_signal = 1; } if ((errno = pthread_mutex_unlock (&_timer_mutex)) != 0) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to unlock timer mutex"); } if (do_signal) { if ((errno = pthread_cond_signal (&_timer_cond)) != 0) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to signal timer condition"); } } assert (t->id > 0); return (t->id); } long timer_set_relative (callback_f cb, void *arg, long msec) { struct timespec ts; int rv; /* Convert the relative time offset into an absolute timespec from now. */ rv = clock_get_timespec (&ts, msec); if (rv < 0) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to query current time"); } return (timer_set_absolute (cb, arg, &ts)); } int timer_cancel (long id) { timer_p *t_prev_ptr; timer_p t = NULL; int do_signal = 0; if (id <= 0) { errno = EINVAL; return (-1); } if ((errno = pthread_mutex_lock (&_timer_mutex)) != 0) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to lock timer mutex"); } /* Locate the active timer specified by [id]. */ t_prev_ptr = &_timer_active; while (*t_prev_ptr && (id != (*t_prev_ptr)->id)) { t_prev_ptr = &(*t_prev_ptr)->next; } /* Remove the located timer from the active list. */ if (*t_prev_ptr) { t = *t_prev_ptr; *t_prev_ptr = t->next; t->next = _timer_inactive; _timer_inactive = t; /* * Only signal the timer thread if the active timer was canceled. * Set a flag here so the signal can be done outside the monitor lock. */ if (t_prev_ptr == &_timer_active) { do_signal = 1; } } if ((errno = pthread_mutex_unlock (&_timer_mutex)) != 0) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to unlock timer mutex"); } if (do_signal) { if ((errno = pthread_cond_signal (&_timer_cond)) != 0) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to signal timer condition"); } } return (t ? 1 : 0); } /***************************************************************************** * Private Functions *****************************************************************************/ static void * _timer_thread (void *arg) { /* The timer thread. It waits until the next active timer expires, * at which point it invokes the timer's callback function. */ sigset_t sigset; int cancel_state; struct timespec ts_now; timer_p *t_prev_ptr; timer_p timer_expired; int rv; if (sigfillset (&sigset)) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to init timer sigset"); } if (pthread_sigmask (SIG_SETMASK, &sigset, NULL) != 0) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to set timer sigset"); } if ((errno = pthread_mutex_lock (&_timer_mutex)) != 0) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to lock timer mutex"); } pthread_cleanup_push (_timer_thread_cleanup, NULL); for (;;) { /* * Wait until a timer has been added to the active list. */ while (!_timer_active) { /* * Cancellation point. */ if ((errno = pthread_cond_wait (&_timer_cond, &_timer_mutex)) != 0) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to wait on timer condition"); } } /* Disable the thread's cancellation state in case any * callback functions contain cancellation points. */ errno = pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, &cancel_state); if (errno != 0) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to disable timer thread cancellation"); } rv = clock_get_timespec (&ts_now, 0); if (rv < 0) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to query current time"); } /* Select expired timers. */ t_prev_ptr = &_timer_active; while (*t_prev_ptr && clock_is_timespec_le (&(*t_prev_ptr)->ts, &ts_now)) { t_prev_ptr = &(*t_prev_ptr)->next; } if (t_prev_ptr != &_timer_active) { /* * Move expired timers from the active list onto an expired list. * All expired timers are dispatched before the active list is * rescanned. This protects against an erroneous ts_now set in * the future from causing recurring timers to be continually * dispatched since ts_now will be requeried once the expired * list is processed. (Issue 15) */ timer_expired = _timer_active; _timer_active = *t_prev_ptr; *t_prev_ptr = NULL; /* * Unlock the mutex while dispatching callback functions in case * any need to set/cancel timers. */ if ((errno = pthread_mutex_unlock (&_timer_mutex)) != 0) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to unlock timer mutex"); } /* Dispatch expired timers. */ t_prev_ptr = &timer_expired; while (*t_prev_ptr) { (*t_prev_ptr)->f ((*t_prev_ptr)->arg); t_prev_ptr = &(*t_prev_ptr)->next; } if ((errno = pthread_mutex_lock (&_timer_mutex)) != 0) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to lock timer mutex"); } /* Move the expired timers onto the inactive list. * At the end of the previous while-loop, t_prev_ptr is the * address of the terminating NULL of the timer_expired list. */ *t_prev_ptr = _timer_inactive; _timer_inactive = timer_expired; } /* Enable the thread's cancellation state. * Since enabling cancellation is not a cancellation point, * a pending cancel request must be tested for. But a * pthread_testcancel() is not needed here. If active timers * are present, the pthread_cond_timedwait() at the bottom of * the for-loop will serve as the cancellation point; otherwise, * the pthread_cond_wait() at the top of the for-loop will. */ errno = pthread_setcancelstate (cancel_state, &cancel_state); if (errno != 0) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to enable timer thread cancellation"); } /* Wait until the next active timer is set to expire, * or until the active timer changes. */ while (_timer_active) { /* * Cancellation point. */ errno = pthread_cond_timedwait ( &_timer_cond, &_timer_mutex, &(_timer_active->ts)); if (errno == EINTR) { continue; } if ((errno == ETIMEDOUT) || (errno == 0)) { break; } log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to wait on timer condition"); } } assert (1); /* not reached */ pthread_cleanup_pop (1); return (NULL); } static void _timer_thread_cleanup (void *arg) { /* The cleanup routine for the timer thread. * It ensures the mutex is released when the thread is canceled. */ if ((errno = pthread_mutex_unlock (&_timer_mutex)) != 0) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to unlock timer mutex"); } return; } static timer_p _timer_alloc (void) { /* Returns a new timer, or NULL on memory allocation failure. * The mutex must be locked before calling this routine. */ timer_p t; assert (lsd_mutex_is_locked (&_timer_mutex)); if (_timer_inactive) { t = _timer_inactive; _timer_inactive = _timer_inactive->next; t->next = NULL; } else { t = malloc (sizeof (struct timer)); } return (t); } munge-munge-0.5.15/src/munged/timer.h000066400000000000000000000061471425467526100174110ustar00rootroot00000000000000/***************************************************************************** * Written by Chris Dunlap . * Copyright (C) 2007-2022 Lawrence Livermore National Security, LLC. * Copyright (C) 2002-2007 The Regents of the University of California. * UCRL-CODE-155910. * * This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE). * For details, see . * * MUNGE 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. Additionally for the MUNGE library (libmunge), you * can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation, * either version 3 of the License, or (at your option) any later version. * * MUNGE 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 * and GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * and GNU Lesser General Public License along with MUNGE. If not, see * . *****************************************************************************/ #ifndef TIMER_H #define TIMER_H #if HAVE_CONFIG_H # include #endif /* HAVE_CONFIG_H */ #include /***************************************************************************** * Data Types *****************************************************************************/ typedef void (*callback_f) (void *arg); /* * Function prototype for a timer callback function. */ /***************************************************************************** * Prototypes *****************************************************************************/ void timer_init (void); /* * Initialize the timer thread. Timers can be set before calling this * routine, but expired timers will not be processed until it is called. */ void timer_fini (void); /* * Cancels the timer thread and all pending timers. */ long timer_set_absolute (callback_f cb, void *arg, const struct timespec *tsp); /* * Sets a timer to expire at the absolute time specified by [tsp]. * At expiration, the callback function [cb] will be invoked with [arg]. * Returns a timer ID > 0, or -1 on error (with errno set appropriately). */ long timer_set_relative (callback_f cb, void *arg, long msec); /* * Sets a timer to expire at [msec] milliseconds past the current time. * At expiration, the callback function [cb] will be invoked with [arg]. * Returns a timer ID > 0, or -1 on error (with errno set appropriately). */ int timer_cancel (long id); /* * Cancels the timer specified by [id] before it expires. * Returns 1 on success, 0 if the [id] did not match an active timer, * and -1 on error (with errno set appropriately). */ #endif /* !TIMER_H */ munge-munge-0.5.15/src/munged/work.c000066400000000000000000000364441425467526100172510ustar00rootroot00000000000000/***************************************************************************** * Written by Chris Dunlap . * Copyright (C) 2007-2022 Lawrence Livermore National Security, LLC. * Copyright (C) 2002-2007 The Regents of the University of California. * UCRL-CODE-155910. * * This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE). * For details, see . * * MUNGE 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. Additionally for the MUNGE library (libmunge), you * can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation, * either version 3 of the License, or (at your option) any later version. * * MUNGE 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 * and GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * and GNU Lesser General Public License along with MUNGE. If not, see * . ***************************************************************************** * Refer to "work.h" for documentation on public functions. *****************************************************************************/ #if HAVE_CONFIG_H # include "config.h" #endif /* HAVE_CONFIG_H */ #include #include #include #include #include #include #include #include #include "log.h" #include "work.h" /***************************************************************************** * Private Data Types *****************************************************************************/ typedef struct work_arg { struct work_arg *next; /* next work element in queue */ void *arg; /* arg describing work to be done */ } work_arg_t, *work_arg_p; typedef struct work { pthread_mutex_t lock; /* mutex for accessing struct */ pthread_cond_t received_work; /* cond for when new work is recv'd */ pthread_cond_t finished_work; /* cond for when all work is done */ pthread_t *workers; /* ptr to array of worker thread IDs */ work_func_t work_func; /* function to perform work in queue */ work_arg_p work_head; /* head of the work queue */ work_arg_p work_tail; /* tail of the work queue */ int n_workers; /* number of worker threads (total) */ int n_working; /* number of worker threads working */ int got_fini; /* true prevents new work after fini */ } work_t; /***************************************************************************** * Private Prototypes *****************************************************************************/ static void * _work_exec (void *arg); static void _work_exec_cleanup (void *arg); static void * _work_enqueue (work_p wp, void *work); static void * _work_dequeue (work_p wp); /***************************************************************************** * Public Functions *****************************************************************************/ work_p work_init (work_func_t f, int n_threads) { work_p wp; pthread_attr_t tattr; size_t stacksize = 256 * 1024; int i; /* Check args. */ if (f == NULL) { errno = EINVAL; return (NULL); } if (n_threads <= 0) { errno = EINVAL; return (NULL); } /* Allocate memory. */ if (!(wp = malloc (sizeof (work_t)))) { log_errno (EMUNGE_NO_MEMORY, LOG_ERR, "Failed to allocate work thread struct"); } if (!(wp->workers = malloc (sizeof (*wp->workers) * n_threads))) { log_errno (EMUNGE_NO_MEMORY, LOG_ERR, "Failed to allocate tid array for work thread struct"); } /* Initialize struct. */ if ((errno = pthread_attr_init (&tattr)) != 0) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to init work thread attribute"); } #ifdef _POSIX_THREAD_ATTR_STACKSIZE if ((errno = pthread_attr_setstacksize (&tattr, stacksize)) != 0) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to set work thread stacksize"); } if ((errno = pthread_attr_getstacksize (&tattr, &stacksize)) != 0) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to get work thread stacksize"); } log_msg (LOG_DEBUG, "Set work thread stacksize to %d", (int) stacksize); #endif /* _POSIX_THREAD_ATTR_STACKSIZE */ if ((errno = pthread_mutex_init (&wp->lock, NULL)) != 0) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to init work thread mutex"); } if ((errno = pthread_cond_init (&wp->received_work, NULL)) != 0) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to init work thread condition for received work"); } if ((errno = pthread_cond_init (&wp->finished_work, NULL)) != 0) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to init work thread condition for finished work"); } wp->work_func = f; wp->work_head = wp->work_tail = NULL; wp->n_workers = n_threads; wp->n_working = 0; wp->got_fini = 0; /* * Start worker thread(s). */ for (i = 0; i < wp->n_workers; i++) { if ((errno = pthread_create (&wp->workers[i], &tattr, _work_exec, wp)) != 0) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to create work thread #%d", i+1); } } /* Cleanup. */ if ((errno = pthread_attr_destroy (&tattr)) != 0) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to destroy work thread attribute"); } return (wp); } void work_fini (work_p wp, int do_wait) { int i; if (!wp) { errno = EINVAL; return; } if ((errno = pthread_mutex_lock (&wp->lock)) != 0) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to lock work thread mutex"); } /* Prevent new work from being queued. */ wp->got_fini = 1; /* * Process remaining work if requested. */ if (do_wait) { /* * Calling work_wait() won't work here since the wait wouldn't * be atomic with the mutex being dropped between function calls. */ while ((wp->n_working != 0) && (wp->work_head != NULL)) { if ((errno = pthread_cond_wait (&wp->finished_work, &wp->lock)) != 0) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to wait on work thread for finished work"); } } } /* Stop worker thread(s). * The mutex must be unlocked in order to cancel the worker * thread(s) which may be blocked on pthread_cond_wait(). * When a pthread_cond_wait() is canceled, the mutex is * re-acquired before the cleanup handlers are invoked. */ if ((errno = pthread_mutex_unlock (&wp->lock)) != 0) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to unlock work thread mutex"); } for (i = 0; i < wp->n_workers; i++) { if ((errno = pthread_cancel (wp->workers[i])) != 0) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to cancel work thread #%d", i+1); } } for (i = 0; i < wp->n_workers; i++) { void *result; if ((errno = pthread_join (wp->workers[i], &result)) != 0) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to join work thread #%d", i+1); } if (result != PTHREAD_CANCELED) { log_err (EMUNGE_SNAFU, LOG_ERR, "Work thread #%d was not canceled", i+1); } wp->workers[i] = 0; } /* Reclaim allocated resources. */ if ((errno = pthread_cond_destroy (&wp->finished_work)) != 0) { log_msg (LOG_ERR, "Failed to destroy work thread condition for finished work: %s", strerror (errno)); } if ((errno = pthread_cond_destroy (&wp->received_work)) != 0) { log_msg (LOG_ERR, "Failed to destroy work thread condition for received work: %s", strerror (errno)); } if ((errno = pthread_mutex_destroy (&wp->lock)) != 0) { log_msg (LOG_ERR, "Failed to destroy work thread mutex: %s", strerror (errno)); } free (wp->workers); free (wp); return; } int work_queue (work_p wp, void *work) { int rc = 0; int do_signal = 0; if (!wp || !work) { errno = EINVAL; return (-1); } if ((errno = pthread_mutex_lock (&wp->lock)) != 0) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to lock work thread mutex"); } if (wp->got_fini) { errno = EPERM; rc = -1; } else if (_work_enqueue (wp, work) == NULL) { errno = EINVAL; rc = -1; } else if ((wp->n_workers - wp->n_working) > 0) { /* * Awaken an idle worker if possible. * Set a flag here so the signal can be done outside the monitor lock. */ do_signal = 1; } if ((errno = pthread_mutex_unlock (&wp->lock)) != 0) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to unlock work thread mutex"); } if (do_signal) { if ((errno = pthread_cond_signal (&wp->received_work)) != 0) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to signal work thread for received work"); } } return (rc); } void work_wait (work_p wp) { if (!wp) { errno = EINVAL; return; } if ((errno = pthread_mutex_lock (&wp->lock)) != 0) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to lock work thread mutex"); } /* Wait until all the queued work is finished. */ while ((wp->n_working != 0) && (wp->work_head != NULL)) { if ((errno = pthread_cond_wait (&wp->finished_work, &wp->lock)) != 0) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to wait on work thread for finished work"); } } if ((errno = pthread_mutex_unlock (&wp->lock)) != 0) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to unlock work thread mutex"); } return; } /***************************************************************************** * Private Functions *****************************************************************************/ static void * _work_exec (void *arg) { /* The worker thread. It continually removes the next element * from the work queue and processes it -- until it's canceled. */ work_p wp; sigset_t sigset; int cancel_state; void *work; assert (arg != NULL); wp = arg; if (sigfillset (&sigset)) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to init work thread sigset"); } if (pthread_sigmask (SIG_SETMASK, &sigset, NULL) != 0) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to set work thread sigset"); } if ((errno = pthread_mutex_lock (&wp->lock)) != 0) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to lock work thread mutex"); } pthread_cleanup_push (_work_exec_cleanup, wp); for (;;) { pthread_testcancel (); /* * Wait for new work if none is currently queued. */ while (!wp->work_head) { if ((errno = pthread_cond_wait (&wp->received_work, &wp->lock)) != 0) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to wait on work thread for received work"); } } /* Disable the thread's cancellation state. */ if ((errno = pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, &cancel_state)) != 0) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to disable work thread cancellation"); } /* Process the work. */ work = _work_dequeue (wp); assert (work != NULL); wp->n_working++; if ((errno = pthread_mutex_unlock (&wp->lock)) != 0) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to unlock work thread mutex"); } wp->work_func (work); if ((errno = pthread_mutex_lock (&wp->lock)) != 0) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to lock work thread mutex"); } wp->n_working--; /* * Enable the thread's cancellation state. * Since enabling cancellation is not a cancellation point, * a pending cancel request must be tested for. Consequently, * pthread_testcancel() is called at the top of the for-loop * (in case work is queued and pthread_cond_wait() isn't invoked). */ if ((errno = pthread_setcancelstate (cancel_state, &cancel_state)) != 0) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to enable work thread cancellation"); } /* Check to see if all the queued work is now finished. */ if ((wp->n_working == 0) && (!wp->work_head)) { if ((errno = pthread_cond_signal (&wp->finished_work)) != 0) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to signal work thread for finished work"); } } } assert (1); /* not reached */ pthread_cleanup_pop (1); return (NULL); } static void _work_exec_cleanup (void *arg) { /* The cleanup routine for the _work_exec() thread(s). * It ensures the mutex is released when the thread is canceled. */ work_p wp; assert (arg != NULL); wp = arg; if ((errno = pthread_mutex_unlock (&wp->lock)) != 0) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to unlock work thread mutex"); } return; } static void * _work_enqueue (work_p wp, void *work) { /* Enqueue the [work] element at the tail of the [wp] work queue. * * LOCKING PROTOCOL: * This routine requires the caller to have locked the [wp]'s mutex. */ work_arg_p wap; assert (wp != NULL); if (!work) { return (NULL); } if (!(wap = malloc (sizeof (*wap)))) { log_errno (EMUNGE_NO_MEMORY, LOG_ERR, "Failed to enqueue work"); } wap->next = NULL; wap->arg = work; if (!wp->work_tail) { wp->work_tail = wp->work_head = wap; } else { wp->work_tail->next = wap; wp->work_tail = wap; } return (work); } static void * _work_dequeue (work_p wp) { /* Dequeue the work element at the head of the [wp] work queue. * * LOCKING PROTOCOL: * This routine requires the caller to have locked the [wp]'s mutex. */ work_arg_p wap; void *work; assert (wp != NULL); wap = wp->work_head; if (!wap) { return (NULL); } wp->work_head = wap->next; work = wap->arg; free (wap); if (!wp->work_head) { wp->work_tail = NULL; } return (work); } munge-munge-0.5.15/src/munged/work.h000066400000000000000000000057141425467526100172520ustar00rootroot00000000000000/***************************************************************************** * Written by Chris Dunlap . * Copyright (C) 2007-2022 Lawrence Livermore National Security, LLC. * Copyright (C) 2002-2007 The Regents of the University of California. * UCRL-CODE-155910. * * This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE). * For details, see . * * MUNGE 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. Additionally for the MUNGE library (libmunge), you * can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation, * either version 3 of the License, or (at your option) any later version. * * MUNGE 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 * and GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * and GNU Lesser General Public License along with MUNGE. If not, see * . *****************************************************************************/ #ifndef WORK_H #define WORK_H #if HAVE_CONFIG_H # include #endif /* HAVE_CONFIG_H */ /***************************************************************************** * Data Types *****************************************************************************/ typedef struct work * work_p; typedef void (*work_func_t) (void *); /***************************************************************************** * Functions *****************************************************************************/ work_p work_init (work_func_t f, int n_threads); /* * Initializes the work crew comprised of [n_threads] workers. * The work function [f] will be invoked to process each work element * queued by work_queue(). * Returns a ptr to the work crew, or NULL on error (with errno set). */ void work_fini (work_p wp, int do_wait); /* * Stops the work crew [wp], canceling all worker threads and releasing * associated resources. If [do_wait] is non-zero, all currently-queued * work will be processed before the work crew is stopped; new work is * prevented from being added to the queue during this time. */ int work_queue (work_p wp, void *work); /* * Queues the [work] element for processing by the work crew [wp]. * The [work] will be passed to the function specified during work_init(). * Returns 0 on success, or -1 on error (with errno set). */ void work_wait (work_p wp); /* * Waits until all queued work is processed by the work crew [wp]. */ #endif /* WORK_H */ munge-munge-0.5.15/src/munged/zip.c000066400000000000000000000207601425467526100170630ustar00rootroot00000000000000/***************************************************************************** * Written by Chris Dunlap . * Copyright (C) 2007-2022 Lawrence Livermore National Security, LLC. * Copyright (C) 2002-2007 The Regents of the University of California. * UCRL-CODE-155910. * * This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE). * For details, see . * * MUNGE 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. Additionally for the MUNGE library (libmunge), you * can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation, * either version 3 of the License, or (at your option) any later version. * * MUNGE 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 * and GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * and GNU Lesser General Public License along with MUNGE. If not, see * . *****************************************************************************/ #if HAVE_CONFIG_H # include #endif /* HAVE_CONFIG_H */ #if HAVE_BZLIB_H # include /* for Solaris */ # include #endif /* HAVE_BZLIB_H */ #if HAVE_ZLIB_H # include #endif /* HAVE_ZLIB_H */ #include #include #include #include #include #include "common.h" #include "zip.h" /***************************************************************************** * Notes *****************************************************************************/ /* * Neither the zlib nor bzlib compression routines encode the original length * of the uncompressed data in the compressed output. * The following "zip" routines allocate an additional 8 bytes of metadata * (zip_meta_t) that is prepended to the compressed output for this purpose. * The first 4 bytes contain a sentinel to check if the metadata is valid. * The next 4 bytes contain the original length of the uncompressed data. * Both values are in MSBF (ie, big endian) format. */ /***************************************************************************** * Constants *****************************************************************************/ #define ZIP_MAGIC 0xCACACACA /***************************************************************************** * Data Types *****************************************************************************/ typedef struct { uint32_t magic; uint32_t length; } zip_meta_t; /***************************************************************************** * Public Functions *****************************************************************************/ int zip_is_valid_type (munge_zip_t type) { #if HAVE_PKG_BZLIB if (type == MUNGE_ZIP_BZLIB) return (1); #endif /* HAVE_PKG_BZLIB */ #if HAVE_PKG_ZLIB if (type == MUNGE_ZIP_ZLIB) return (1); #endif /* HAVE_PKG_ZLIB */ return (0); } int zip_compress_block (munge_zip_t type, void *dst, int *pdstlen, const void *src, int srclen) { unsigned char *xdst; unsigned int xdstlen; unsigned char *xsrc; unsigned int xsrclen; zip_meta_t *pmeta; assert (dst != NULL); assert (pdstlen != NULL); assert (src != NULL); if (!zip_is_valid_type (type)) { return (-1); } if (*pdstlen < sizeof (zip_meta_t)) { return (-1); } if (srclen <= 0) { return (-1); } xdst = (unsigned char *) dst + sizeof (zip_meta_t); xdstlen = *pdstlen - sizeof (zip_meta_t); xsrc = (unsigned char *) src; xsrclen = srclen; #if HAVE_PKG_BZLIB if (type == MUNGE_ZIP_BZLIB) { if (BZ2_bzBuffToBuffCompress ((char *) xdst, &xdstlen, (char *) xsrc, xsrclen, 9, 0, 0) != BZ_OK) return (-1); } #endif /* HAVE_PKG_BZLIB */ #if HAVE_PKG_ZLIB /* * XXX: The use of the "xdstlen_ul" temporary variable is to avoid the * gcc3.3 compiler warning: "dereferencing type-punned pointer * will break strict-aliasing rules". A mere cast doesn't suffice. */ if (type == MUNGE_ZIP_ZLIB) { unsigned long xdstlen_ul = xdstlen; if (compress (xdst, &xdstlen_ul, xsrc, (unsigned long) xsrclen) != Z_OK) return (-1); xdstlen = xdstlen_ul; } #endif /* HAVE_PKG_ZLIB */ *pdstlen = xdstlen + sizeof (zip_meta_t); pmeta = dst; pmeta->magic = htonl (ZIP_MAGIC); pmeta->length = htonl (xsrclen); return (0); } int zip_decompress_block (munge_zip_t type, void *dst, int *pdstlen, const void *src, int srclen) { unsigned char *xdst; unsigned int xdstlen; unsigned char *xsrc; unsigned int xsrclen; int n; assert (dst != NULL); assert (pdstlen != NULL); assert (src != NULL); if (!zip_is_valid_type (type)) { return (-1); } n = zip_decompress_length (type, src, srclen); if (n < 0) { return (-1); } if (*pdstlen < n) { return (-1); } if (srclen <= 0) { return (-1); } xdst = dst; xdstlen = *pdstlen; xsrc = (unsigned char *) src + sizeof (zip_meta_t); xsrclen = srclen - sizeof (zip_meta_t); #if HAVE_PKG_BZLIB if (type == MUNGE_ZIP_BZLIB) { if (BZ2_bzBuffToBuffDecompress ((char *) xdst, &xdstlen, (char *) xsrc, xsrclen, 0, 0) != BZ_OK) return (-1); } #endif /* HAVE_PKG_BZLIB */ #if HAVE_PKG_ZLIB /* * XXX: The use of the "xdstlen_ul" temporary variable is to avoid the * gcc3.3 compiler warning: "dereferencing type-punned pointer * will break strict-aliasing rules". A mere cast doesn't suffice. */ if (type == MUNGE_ZIP_ZLIB) { unsigned long xdstlen_ul = xdstlen; if (uncompress (xdst, &xdstlen_ul, xsrc, (unsigned long) xsrclen) != Z_OK) return (-1); xdstlen = xdstlen_ul; } #endif /* HAVE_PKG_ZLIB */ *pdstlen = xdstlen; return (0); } int zip_compress_length (munge_zip_t type, const void *src, int len) { /* For zlib "deflate" compression, allocate an output buffer at least 0.1% * larger than the uncompressed input, plus an additional 12 bytes. * For bzlib compression, allocate an output buffer at least 1% larger than * the uncompressed input, plus an additional 600 bytes. * Also reserve space for encoding the size of the uncompressed data. * The "+1" is for the double-to-int conversion to perform a ceiling function. * * XXX: Note the [src] parm is not currently used here. */ #if HAVE_PKG_BZLIB if (type == MUNGE_ZIP_BZLIB) return ((int) ((len * 1.01) + 600 + 1 + sizeof (zip_meta_t))); #endif /* HAVE_PKG_BZLIB */ #if HAVE_PKG_ZLIB if (type == MUNGE_ZIP_ZLIB) return ((int) ((len * 1.001) + 12 + 1 + sizeof (zip_meta_t))); #endif /* HAVE_PKG_ZLIB */ return (-1); } int zip_decompress_length (munge_zip_t type, const void *src, int len) { /* XXX: Note the [type] parm is not currently used here. */ zip_meta_t *pmeta; assert (src != NULL); if (len < sizeof (zip_meta_t)) { return (-1); } pmeta = (void *) src; if (ntohl (pmeta->magic) != ZIP_MAGIC) { return (-1); } return ((int) ntohl (pmeta->length)); } munge_zip_t zip_select_default_type (munge_zip_t type) { /* Selects an available compression type (assuming compression is requested * by the specified [type]) with a preference towards zlib since it's fast * with low overhead. */ munge_zip_t z; munge_zip_t z_def; z = MUNGE_ZIP_DEFAULT; z_def = MUNGE_ZIP_NONE; #if HAVE_PKG_BZLIB z_def = MUNGE_ZIP_BZLIB; if (type == MUNGE_ZIP_BZLIB) { z = MUNGE_ZIP_BZLIB; } #endif /* HAVE_PKG_BZLIB */ #if HAVE_PKG_ZLIB z_def = MUNGE_ZIP_ZLIB; if (type == MUNGE_ZIP_ZLIB) { z = MUNGE_ZIP_ZLIB; } #endif /* HAVE_PKG_ZLIB */ if (type == MUNGE_ZIP_NONE) { z = MUNGE_ZIP_NONE; } else if (z == MUNGE_ZIP_DEFAULT) { z = z_def; } return (z); } munge-munge-0.5.15/src/munged/zip.h000066400000000000000000000073051425467526100170700ustar00rootroot00000000000000/***************************************************************************** * Written by Chris Dunlap . * Copyright (C) 2007-2022 Lawrence Livermore National Security, LLC. * Copyright (C) 2002-2007 The Regents of the University of California. * UCRL-CODE-155910. * * This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE). * For details, see . * * MUNGE 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. Additionally for the MUNGE library (libmunge), you * can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation, * either version 3 of the License, or (at your option) any later version. * * MUNGE 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 * and GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * and GNU Lesser General Public License along with MUNGE. If not, see * . *****************************************************************************/ #ifndef ZIP_H #define ZIP_H #if HAVE_CONFIG_H # include #endif /* HAVE_CONFIG_H */ #include #include "common.h" /* HAVE_PKG_BZLIB, HAVE_PKG_ZLIB */ /***************************************************************************** * Prototypes *****************************************************************************/ int zip_is_valid_type (munge_zip_t type); /* * Returns non-zero if the given [type] is a supported valid MUNGE compression * type according to the current configuration. The NONE and DEFAULT types * are not considered valid types by this routine. */ int zip_compress_block (munge_zip_t type, void *dst, int *pdstlen, const void *src, int srclen); /* * Compresses the [src] buffer of length [srclen] in a single pass using the * compression method [type]. The resulting compressed output is stored * in the [dst] buffer. * Upon entry, [*pdstlen] must be set to the size of the [dst] buffer. * Upon exit, [*pdstlen] is set to the size of the compressed data. * Returns 0 on success, or -1 or error. */ int zip_decompress_block (munge_zip_t type, void *dst, int *pdstlen, const void *src, int srclen); /* * Decompresses the [src] buffer of length [srclen] in a single pass using the * compression method [type]. The resulting decompressed (original) output * is stored in the [dst] buffer. * Upon entry, [*pdstlen] must be set to the size of the [dst] buffer. * Upon exit, [*pdstlen] is set to the size of the decompressed data. * Returns 0 on success, or -1 or error. */ int zip_compress_length (munge_zip_t type, const void *src, int len); /* * Returns a worst-case estimate for the buffer length needed to compress data * in the [src] buffer of length [len] using the compression method [type], * or -1 on error. */ int zip_decompress_length (munge_zip_t type, const void *src, int len); /* * Returns the decompressed (original) length of the compressed data * in the [src] buffer of length [len], or -1 on error. */ munge_zip_t zip_select_default_type (munge_zip_t type); /* * Returns [type] if that compression type is supported by the current * configuration; otherwise, returns an acceptible default type. */ #endif /* !ZIP_H */ munge-munge-0.5.15/src/mungekey/000077500000000000000000000000001425467526100164555ustar00rootroot00000000000000munge-munge-0.5.15/src/mungekey/Makefile.am000066400000000000000000000035211425467526100205120ustar00rootroot00000000000000# MUNGE src/mungekey/Makefile.am # # This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE). # For details, see . include $(top_srcdir)/Make-inc.mk TEMPLATE_FILES = \ mungekey.8.in \ # End of TEMPLATE_FILES SUBSTITUTE_FILES = \ mungekey.8 \ # End of SUBSTITUTE_FILES EXTRA_DIST = \ $(TEMPLATE_FILES) \ # End of EXTRA_DIST CLEANFILES = \ $(SUBSTITUTE_FILES) \ # End of CLEANFILES $(SUBSTITUTE_FILES): Makefile $(AM_V_GEN)$(substitute) < '$(srcdir)/$@.in' > '$(builddir)/$@' mungekey.8: mungekey.8.in sbin_PROGRAMS = \ mungekey \ # End of sbin_PROGRAMS mungekey_CFLAGS = \ $(AM_CFLAGS) \ $(CRYPTO_CFLAGS) \ # End of mungekey_CFLAGS mungekey_CPPFLAGS = \ -DSYSCONFDIR='"$(sysconfdir)"' \ -I$(top_srcdir)/src/common \ -I$(top_srcdir)/src/libcommon \ -I$(top_srcdir)/src/libmissing \ -I$(top_srcdir)/src/libmunge \ # End of mungekey_CPPFLAGS mungekey_LDADD = \ $(top_builddir)/src/libcommon/libcommon.la \ $(top_builddir)/src/libmissing/libmissing.la \ $(top_builddir)/src/libmunge/libmunge.la \ $(CRYPTO_LIBS) \ # End of mungekey_LDADD mungekey_SOURCES = \ mungekey.c \ conf.c \ conf.h \ key.c \ key.h \ $(top_srcdir)/src/common/crypto.c \ $(top_srcdir)/src/common/crypto.h \ $(top_srcdir)/src/common/entropy.c \ $(top_srcdir)/src/common/entropy.h \ $(top_srcdir)/src/common/hkdf.c \ $(top_srcdir)/src/common/hkdf.h \ $(top_srcdir)/src/common/mac.c \ $(top_srcdir)/src/common/mac.h \ $(top_srcdir)/src/common/md.c \ $(top_srcdir)/src/common/md.h \ $(top_srcdir)/src/common/rotate.c \ $(top_srcdir)/src/common/rotate.h \ $(top_srcdir)/src/common/xsignal.c \ $(top_srcdir)/src/common/xsignal.h \ # End of mungekey_SOURCES # For dependency on SYSCONFDIR via the #define for MUNGE_KEYFILE_PATH. # $(srcdir)/mungekey-conf.$(OBJEXT): Makefile man_MANS = \ mungekey.8 \ # End of man_MANS munge-munge-0.5.15/src/mungekey/conf.c000066400000000000000000000335701425467526100175560ustar00rootroot00000000000000/***************************************************************************** * Written by Chris Dunlap . * Copyright (C) 2007-2022 Lawrence Livermore National Security, LLC. * Copyright (C) 2002-2007 The Regents of the University of California. * UCRL-CODE-155910. * * This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE). * For details, see . * * MUNGE 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. Additionally for the MUNGE library (libmunge), you * can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation, * either version 3 of the License, or (at your option) any later version. * * MUNGE 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 * and GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * and GNU Lesser General Public License along with MUNGE. If not, see * . *****************************************************************************/ #if HAVE_CONFIG_H # include #endif /* HAVE_CONFIG_H */ #include #include #include #include #include #include #include #include #include "conf.h" #include "license.h" #include "log.h" #include "missing.h" #include "munge_defs.h" #include "version.h" /***************************************************************************** * Command-Line Options *****************************************************************************/ /* GETOPT_DEBUG_SHORT_OPTS is defined when configured with --enable-debug * in order to test the case of a command-line option being unimplemented. */ #ifdef NDEBUG #define GETOPT_DEBUG_SHORT_OPTS "" #else /* !NDEBUG */ #define GETOPT_DEBUG_SHORT_OPTS "8" #endif /* !NDEBUG */ const char * const short_opts = ":b:cfhk:LvV" GETOPT_DEBUG_SHORT_OPTS ; #include struct option long_opts[] = { { "bits", required_argument, NULL, 'b' }, { "create", no_argument, NULL, 'c' }, { "force", no_argument, NULL, 'f' }, { "help", no_argument, NULL, 'h' }, { "keyfile", required_argument, NULL, 'k' }, { "license", no_argument, NULL, 'L' }, { "verbose", no_argument, NULL, 'v' }, { "version", no_argument, NULL, 'V' }, { NULL, 0, NULL, 0 } }; /***************************************************************************** * Private Prototypes *****************************************************************************/ static void _conf_parse_bits_opt (int *dstp, const char *src, int sopt, const char *lopt); static void _conf_parse_keyfile_opt (char **dstp, const char *src, int sopt, const char *lopt); static void _conf_display_help (const char *prog); static const char * _conf_get_opt_string (int short_opt, const char *long_opt, const char *argv_str); static int _conf_set_int (int *dstp, const char *src, long min, long max); static int _conf_set_str (char **dstp, const char *src); static void _conf_validate (conf_t *confp); /***************************************************************************** * Public Functions *****************************************************************************/ /* Create and return a new initialized conf_t. */ conf_t * create_conf (void) { conf_t *confp; confp = calloc (sizeof (struct conf), 1); if (confp == NULL) { log_errno (EMUNGE_NO_MEMORY, LOG_ERR, "Failed to allocate conf struct"); } confp->key_path = strdup (MUNGE_KEYFILE_PATH); if (confp->key_path == NULL) { log_errno (EMUNGE_NO_MEMORY, LOG_ERR, "Failed to dup key_path string"); } confp->key_num_bytes = MUNGE_KEY_LEN_DFL_BYTES; _conf_validate (confp); return confp; } /* Destroy the conf_t [confp]. */ void destroy_conf (conf_t *confp) { assert (confp != NULL); if (confp == NULL) { return; } if (confp->key_path != NULL) { free (confp->key_path); confp->key_path = NULL; } free (confp); } /* Parse the command-line, storing the config in [confp]. */ void parse_cmdline (conf_t *confp, int argc, char **argv) { char *p; char *prog; int long_ind; const char *long_opt; int c; assert (confp != NULL); assert (argv != NULL); opterr = 0; /* suppress default getopt err msgs */ p = strrchr (argv[0], '/'); prog = (p != NULL) ? p + 1 : argv[0]; for (;;) { long_ind = -1; c = getopt_long (argc, argv, short_opts, long_opts, &long_ind); long_opt = (long_ind >= 0) ? long_opts[long_ind].name : NULL; if (c == -1) { /* reached end of option list */ break; } switch (c) { case 'b': _conf_parse_bits_opt (&confp->key_num_bytes, optarg, c, long_opt); break; case 'c': confp->do_create = 1; break; case 'f': confp->do_force = 1; break; case 'h': _conf_display_help (prog); exit (EXIT_SUCCESS); break; case 'k': _conf_parse_keyfile_opt (&confp->key_path, optarg, c, long_opt); break; case 'L': display_license (); exit (EXIT_SUCCESS); break; case 'v': confp->do_verbose = 1; break; case 'V': display_version (); exit (EXIT_SUCCESS); break; case '?': /* long_opt not set */ log_err (EMUNGE_SNAFU, LOG_ERR, "Option \"%s\" is invalid", _conf_get_opt_string (optopt, NULL, (optind > 1) ? argv[optind - 1] : NULL)); break; case ':': /* long_opt not set */ log_err (EMUNGE_SNAFU, LOG_ERR, "Option \"%s\" is missing a required argument", _conf_get_opt_string (optopt, NULL, (optind > 1) ? argv[optind - 1] : NULL)); break; default: /* long_opt and optopt not set */ log_err (EMUNGE_SNAFU, LOG_ERR, "Option \"%s\" is not implemented", _conf_get_opt_string (c, NULL, (optind > 1) ? argv[optind - 1] : NULL)); break; } } if (optind < argc) { log_err (EMUNGE_SNAFU, LOG_ERR, "Option \"%s\" is unrecognized", (optind > 0) ? argv[optind] : "???"); } /* Default to creating a key if no operation is specified. */ if (!confp->do_create) { confp->do_create = 1; } _conf_validate (confp); } /***************************************************************************** * Private Functions *****************************************************************************/ /* Parse the --bits command-line option arising from short-option [sopt] * or long-option [lopt]. * The [dstp] arg is passed by reference for storing the result of the * required argument specified in the [src] string. */ static void _conf_parse_bits_opt (int *dstp, const char *src, int sopt, const char *lopt) { int min = MUNGE_KEY_LEN_MIN_BYTES * 8; int max = MUNGE_KEY_LEN_MAX_BYTES * 8; int n; int rv; assert (dstp != NULL); assert (src != NULL); n = 0; /* suppress uninitialized warning */ rv = _conf_set_int (&n, src, min, max); if (rv < 0) { log_err (EMUNGE_SNAFU, LOG_ERR, "Option \"%s\" has invalid value \"%s\" (range is %d-%d)", _conf_get_opt_string (sopt, lopt, NULL), src, min, max); } /* Round-up to the next byte. */ n = (n + 7) / 8; *dstp = n; } /* Parse the --keyfile command-line option arising from short-option [sopt] * or long-option [lopt]. * The [dstp] arg is passed by reference for storing the result of the * required argument specified in the [src] string. */ static void _conf_parse_keyfile_opt (char **dstp, const char *src, int sopt, const char *lopt) { int rv; assert (dstp != NULL); assert (src != NULL); rv = _conf_set_str (dstp, src); if (rv < 0) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Option \"%s\" failed to copy argument string", _conf_get_opt_string (sopt, lopt, NULL)); } } /* Display a help message describing the command-line options for [prog]. */ static void _conf_display_help (const char *prog) { const int w = -25; /* pad for width of option string */ assert (prog != NULL); printf ("Usage: %s [OPTIONS]\n", prog); printf ("\n"); printf (" %*s %s\n", w, "-c, --create", "Create keyfile"); printf ("\n"); printf (" %*s %s\n", w, "-b, --bits=INT", "Specify number of bits in key being created"); printf (" %*s %s\n", w, "-f, --force", "Force keyfile to be overwritten if it exists"); printf (" %*s %s [%s]\n", w, "-k, --keyfile=PATH", "Specify keyfile pathname", MUNGE_KEYFILE_PATH); printf (" %*s %s\n", w, "-v, --verbose", "Be verbose"); printf ("\n"); printf (" %*s %s\n", w, "-h, --help", "Display this help message"); printf (" %*s %s\n", w, "-L, --license", "Display license information"); printf (" %*s %s\n", w, "-V, --version", "Display version information"); printf ("\n"); } /* Convert the specified command-line option into a null-terminated string * that will have a leading single-hyphen for a short-option or a leading * double-hyphen for a long-option. * The [short_opt] character is the integer value returned by getopt_long(). * The [long_opt] string is the one specified in the longopts option struct * and lacks the leading double-hyphen. The [argv_str] string is from the * argv[] array. * Return a ptr to a static buffer or string containing the text of the * command-line option. */ static const char * _conf_get_opt_string (int short_opt, const char *long_opt, const char *argv_str) { static char buf[1024]; if (long_opt != NULL) { (void) snprintf (buf, sizeof (buf), "--%s", long_opt); return buf; } else if ((argv_str != NULL) && (strncmp (argv_str, "--", 2) == 0)) { return argv_str; } else if (isprint (short_opt)) { (void) snprintf (buf, sizeof (buf), "-%c", short_opt); return buf; } log_err (EMUNGE_SNAFU, LOG_ERR, "Failed to process command-line"); return NULL; /* not reached */ } /* Set the int ptr [dstp] to the integer value specified by the string [src]. * This value must be within the [min] and [max] bounds. * Return 0 on success with [dstp] set to the new int, or -1 on error * with [dstp] unchanged and errno set. */ static int _conf_set_int (int *dstp, const char *src, long min, long max) { long l; char *endp; if ((dstp == NULL) || (src == NULL)) { errno = EINVAL; return -1; } /* strtol() can legitimately return 0, LONG_MIN, or LONG_MAX on both * success and failure. Consequently, set errno before the call to * determine if an error actually occurred. */ errno = 0; l = strtol (src, &endp, 10); if ((src == endp) || (*endp != '\0')) { errno = EINVAL; return -1; } if ((errno == ERANGE) && ((l == LONG_MIN) || (l == LONG_MAX))) { return -1; } if ((l < INT_MIN) || (l > INT_MAX)) { errno = ERANGE; return -1; } if ((l < min) || (l > max)) { errno = ERANGE; return -1; } if (errno != 0) { return -1; } *dstp = (int) l; return 0; } /* Set the string ptr [dstp] to a newly-allocated string copied from [src]. * If [dstp] refers to an existing string, the old string will be freed * before [dstp] is updated. * Return 0 on success with [dstp] set to the new string, or -1 on error * with [dstp] unchanged and errno set. */ static int _conf_set_str (char **dstp, const char *src) { char *p; if ((dstp == NULL) || (src == NULL)) { errno = EINVAL; return -1; } p = strdup (src); if (p == NULL) { return -1; } if (*dstp != NULL) { free (*dstp); } *dstp = p; return 0; } /* Validate [confp] to check that everything is properly initialized * and within the appropriate limits. */ void _conf_validate (conf_t *confp) { if (confp == NULL) { log_err (EMUNGE_SNAFU, LOG_ERR, "Failed to validate conf: struct undefined"); } if (confp->key_path == NULL) { log_err (EMUNGE_SNAFU, LOG_ERR, "Failed to validate conf: key_path undefined"); } if (confp->key_num_bytes > MUNGE_KEY_LEN_MAX_BYTES) { log_err (EMUNGE_SNAFU, LOG_ERR, "Failed to validate conf: key_num_bytes above maximum"); } if (confp->key_num_bytes < MUNGE_KEY_LEN_MIN_BYTES) { log_err (EMUNGE_SNAFU, LOG_ERR, "Failed to validate conf: key_num_bytes below minimum"); } } munge-munge-0.5.15/src/mungekey/conf.h000066400000000000000000000046611425467526100175620ustar00rootroot00000000000000/***************************************************************************** * Written by Chris Dunlap . * Copyright (C) 2007-2022 Lawrence Livermore National Security, LLC. * Copyright (C) 2002-2007 The Regents of the University of California. * UCRL-CODE-155910. * * This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE). * For details, see . * * MUNGE 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. Additionally for the MUNGE library (libmunge), you * can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation, * either version 3 of the License, or (at your option) any later version. * * MUNGE 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 * and GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * and GNU Lesser General Public License along with MUNGE. If not, see * . *****************************************************************************/ #ifndef MUNGEKEY_CONF_H #define MUNGEKEY_CONF_H /***************************************************************************** * Data Types *****************************************************************************/ typedef struct conf { unsigned do_create:1; /* flag to create new key */ unsigned do_force:1; /* flag to force overwriting key */ unsigned do_verbose:1; /* flag to be verbose */ char *key_path; /* pathname of keyfile */ int key_num_bytes; /* number of bytes for key creation */ } conf_t; /***************************************************************************** * Prototypes *****************************************************************************/ conf_t * create_conf (void); void destroy_conf (conf_t *confp); void parse_cmdline (conf_t *confp, int argc, char **argv); #endif /* !MUNGEKEY_CONF_H */ munge-munge-0.5.15/src/mungekey/key.c000066400000000000000000000156641425467526100174250ustar00rootroot00000000000000/***************************************************************************** * Written by Chris Dunlap . * Copyright (C) 2007-2022 Lawrence Livermore National Security, LLC. * Copyright (C) 2002-2007 The Regents of the University of California. * UCRL-CODE-155910. * * This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE). * For details, see . * * MUNGE 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. Additionally for the MUNGE library (libmunge), you * can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation, * either version 3 of the License, or (at your option) any later version. * * MUNGE 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 * and GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * and GNU Lesser General Public License along with MUNGE. If not, see * . *****************************************************************************/ #if HAVE_CONFIG_H # include #endif /* HAVE_CONFIG_H */ #include #include #include #include #include #include #include "common.h" #include "conf.h" #include "entropy.h" #include "fd.h" #include "hkdf.h" #include "log.h" #include "munge_defs.h" #include "str.h" /***************************************************************************** * Prototypes *****************************************************************************/ static int _create_key_secret (unsigned char *buf, size_t buflen); /***************************************************************************** * Public Functions *****************************************************************************/ /* Create a key for the config in [confp]. */ void create_key (conf_t *confp) { unsigned char buf[MUNGE_KEY_LEN_MAX_BYTES]; int fd; int n; int rv; assert (confp != NULL); assert (confp->key_num_bytes <= MUNGE_KEY_LEN_MAX_BYTES); assert (confp->key_num_bytes >= MUNGE_KEY_LEN_MIN_BYTES); if (confp->key_num_bytes > sizeof (buf)) { log_err (EMUNGE_SNAFU, LOG_ERR, "Failed to create \"%s\": %d-byte key exceeds %zu-byte buffer", confp->key_path, confp->key_num_bytes, sizeof (buf)); } if (confp->do_force) { do { rv = unlink (confp->key_path); } while ((rv == -1) && (errno == EINTR)); if ((rv == -1) && (errno != ENOENT)) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to remove \"%s\"", confp->key_path); } } fd = open (confp->key_path, O_WRONLY | O_CREAT | O_EXCL, 0600); if (fd == -1) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to create \"%s\"", confp->key_path); } rv = _create_key_secret (buf, confp->key_num_bytes); if (rv == -1) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to create \"%s\"", confp->key_path); } n = fd_write_n (fd, buf, confp->key_num_bytes); if (n != confp->key_num_bytes) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to write %d bytes to \"%s\"", confp->key_num_bytes, confp->key_path); } rv = close (fd); if (rv == -1) { log_errno (EMUNGE_SNAFU, LOG_ERR, "Failed to close \"%s\"", confp->key_path); } (void) memburn (buf, 0, sizeof (buf)); if (confp->do_verbose) { log_msg (LOG_INFO, "Created \"%s\" with %d-bit key", confp->key_path, confp->key_num_bytes * 8); } } /***************************************************************************** * Private Functions *****************************************************************************/ /* Create the key secret, writing it to the buffer [buf] of length [buflen]. * Return 0 on success, or -1 on error. */ static int _create_key_secret (unsigned char *buf, size_t buflen) { unsigned char key[ENTROPY_NUM_BYTES_GUARANTEED]; unsigned int salt; const munge_mac_t md = MUNGE_DEFAULT_MAC; const char *md_str; const char *info_prefix = "MUNGEKEY"; int num_bits; char info[1024]; hkdf_ctx_t *hkdfp = NULL; int rv; assert (buf != NULL); assert (buflen > 0); /* Read entropy from the kernel's CSPRNG for the input keying material. */ rv = entropy_read (key, sizeof (key), NULL); if (rv == -1) { goto err; } /* Read entropy independent of the kernel's CSPRNG for use as a salt. */ rv = entropy_read_uint (&salt); if (rv == -1) { goto err; } /* Create a distinguisher that embeds the use, algorithm, and key length. * For example, "MUNGEKEY:sha256:1024:". */ md_str = munge_enum_int_to_str (MUNGE_ENUM_MAC, md); if (md_str == NULL) { log_msg (LOG_ERR, "Failed to lookup text string for md=%d", md); rv = -1; goto err; } num_bits = buflen * 8; rv = snprintf (info, sizeof (info), "%s:%s:%d:", info_prefix, md_str, num_bits); if ((rv < 0) || (rv >= sizeof (info))) { log_msg (LOG_ERR, "Failed to create key distinguisher info: " "exceeded %zu-byte buffer", sizeof (info)); rv = -1; goto err; } /* Mix it all together in the key derivation function. */ hkdfp = hkdf_ctx_create (); if (hkdfp == NULL) { log_msg (LOG_ERR, "Failed to allocate memory for HKDF context"); rv = -1; goto err; } rv = hkdf_ctx_set_md (hkdfp, md); if (rv == -1) { log_msg (LOG_ERR, "Failed to set HKDF message digest to md=%d", md); goto err; } rv = hkdf_ctx_set_key (hkdfp, key, sizeof (key)); if (rv == -1) { log_msg (LOG_ERR, "Failed to set HKDF input keying material"); goto err; } rv = hkdf_ctx_set_salt (hkdfp, &salt, sizeof (salt)); if (rv == -1) { log_msg (LOG_ERR, "Failed to set HKDF salt"); goto err; } rv = hkdf_ctx_set_info (hkdfp, info, strlen (info)); if (rv == -1) { log_msg (LOG_ERR, "Failed to set HKDF info"); goto err; } rv = hkdf (hkdfp, buf, &buflen); if (rv == -1) { log_msg (LOG_ERR, "Failed to compute HKDF key derivation"); goto err; } err: (void) memburn (key, 0, sizeof (key)); (void) memburn (&salt, 0, sizeof (salt)); hkdf_ctx_destroy (hkdfp); return rv; } munge-munge-0.5.15/src/mungekey/key.h000066400000000000000000000033611425467526100174210ustar00rootroot00000000000000/***************************************************************************** * Written by Chris Dunlap . * Copyright (C) 2007-2022 Lawrence Livermore National Security, LLC. * Copyright (C) 2002-2007 The Regents of the University of California. * UCRL-CODE-155910. * * This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE). * For details, see . * * MUNGE 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. Additionally for the MUNGE library (libmunge), you * can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation, * either version 3 of the License, or (at your option) any later version. * * MUNGE 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 * and GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * and GNU Lesser General Public License along with MUNGE. If not, see * . *****************************************************************************/ #ifndef MUNGEKEY_KEY_H #define MUNGEKEY_KEY_H /***************************************************************************** * Prototypes *****************************************************************************/ void create_key (conf_t *confp); #endif /* !MUNGEKEY_KEY_H */ munge-munge-0.5.15/src/mungekey/mungekey.8.in000066400000000000000000000074501425467526100210050ustar00rootroot00000000000000.\"**************************************************************************** .\" Written by Chris Dunlap . .\" Copyright (C) 2007-2022 Lawrence Livermore National Security, LLC. .\" Copyright (C) 2002-2007 The Regents of the University of California. .\" UCRL-CODE-155910. .\" .\" This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE). .\" For details, see . .\" .\" MUNGE 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. Additionally for the MUNGE library (libmunge), you .\" can redistribute it and/or modify it under the terms of the GNU Lesser .\" General Public License as published by the Free Software Foundation, .\" either version 3 of the License, or (at your option) any later version. .\" .\" MUNGE 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 .\" and GNU Lesser General Public License for more details. .\" .\" You should have received a copy of the GNU General Public License .\" and GNU Lesser General Public License along with MUNGE. If not, see .\" . .\"**************************************************************************** .TH MUNGEKEY 8 "@DATE@" "@PACKAGE@-@VERSION@" "MUNGE Uid 'N' Gid Emporium" .SH NAME mungekey \- MUNGE key management utility .SH SYNOPSIS .B mungekey [\fB\-c\fR] [\fB\-b\fR \fIbits\fR] [\fB\-f\fR] [\fB\-k\fR \fIkeyfile\fR] [\fB\-v\fR] .br .SH DESCRIPTION The \fBmungekey\fR executable is the key management utility for MUNGE. It should be run by the same user that starts the \fBmunged\fR daemon. .PP If no options are specified, \fBmungekey\fR will attempt to create a new key using the default settings; this will fail if the keyfile already exists. .PP All \fBmunged\fR daemons within a security realm must use the same key. In other words, all hosts within an administrative group (or cluster) using MUNGE for authentication must use the same key; this keyfile can be created on one host and then securely copied to all other hosts. .SH OPTIONS .TP .BI "\-b, \-\-bits " integer Specify the number of bits in the key being created [256-8192]. .TP .BI "\-c, \-\-create " Create a new keyfile. .TP .BI "\-f, \-\-force " Force the keyfile to be overwritten if it already exists. .TP .BI "\-h, \-\-help" Display a summary of the command-line options. .TP .BI "\-k, \-\-keyfile " path Specify the keyfile pathname. .TP .BI "\-L, \-\-license" Display license information. .TP .BI "\-v, \-\-verbose" Be verbose. .TP .BI "\-V, \-\-version" Display version information. .SH FILES .I @sysconfdir@/munge/munge.key .RS Contains the shared cryptographic key for hosts within the security realm. .RE .SH AUTHOR Chris Dunlap .SH COPYRIGHT Copyright (C) 2007-2022 Lawrence Livermore National Security, LLC. .br Copyright (C) 2002-2007 The Regents of the University of California. .PP MUNGE 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. .PP Additionally for the MUNGE library (libmunge), you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. .SH "SEE ALSO" .BR munge (1), .BR remunge (1), .BR unmunge (1), .BR munge (3), .BR munge_ctx (3), .BR munge_enum (3), .BR munge (7), .BR munged (8). .PP \fBhttps://dun.github.io/munge/\fR munge-munge-0.5.15/src/mungekey/mungekey.c000066400000000000000000000056111425467526100204500ustar00rootroot00000000000000/***************************************************************************** * Written by Chris Dunlap . * Copyright (C) 2007-2022 Lawrence Livermore National Security, LLC. * Copyright (C) 2002-2007 The Regents of the University of California. * UCRL-CODE-155910. * * This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE). * For details, see . * * MUNGE 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. Additionally for the MUNGE library (libmunge), you * can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation, * either version 3 of the License, or (at your option) any later version. * * MUNGE 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 * and GNU Lesser General Public License for more details. * * You should have received a copy of the GNU General Public License * and GNU Lesser General Public License along with MUNGE. If not, see * . *****************************************************************************/ #if HAVE_CONFIG_H # include "config.h" #endif /* HAVE_CONFIG_H */ #include #include #include #include #include "conf.h" #include "crypto.h" #include "key.h" #include "log.h" #include "md.h" #include "xsignal.h" /***************************************************************************** * Prototypes *****************************************************************************/ static void init_logging (const char *prog); /***************************************************************************** * Functions *****************************************************************************/ int main (int argc, char *argv[]) { conf_t *confp; xsignal_ignore (SIGHUP); xsignal_ignore (SIGPIPE); init_logging (argv[0]); confp = create_conf (); parse_cmdline (confp, argc, argv); crypto_init (); md_init_subsystem (); if (confp->do_create) { create_key (confp); } crypto_fini (); destroy_conf (confp); exit (EXIT_SUCCESS); } /* Configure logging to stderr. */ static void init_logging (const char *prog) { int priority = LOG_INFO; int options = LOG_OPT_PRIORITY; int rv; assert (prog != NULL); #ifndef NDEBUG priority = LOG_DEBUG; #endif /* !NDEBUG */ rv = log_open_file (stderr, prog, priority, options); if (rv == -1) { log_err (EMUNGE_SNAFU, LOG_ERR, "Failed to setup logging to stderr"); } } munge-munge-0.5.15/t/000077500000000000000000000000001425467526100143055ustar00rootroot00000000000000munge-munge-0.5.15/t/0000-sharness.t000077500000000000000000000376211425467526100167110ustar00rootroot00000000000000#!/bin/sh # # Copyright (c) 2011-2013 Mathias Lafeldt # Copyright (c) 2005-2013 Git project # Copyright (c) 2005-2013 Junio C Hamano # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see http://www.gnu.org/licenses/ . test_description='Test Sharness itself' . "$(dirname "$0")/sharness.sh" ret="$?" test_expect_success 'sourcing sharness succeeds' ' test "$ret" = 0 ' test_expect_success 'success is reported like this' ' : ' test_expect_failure 'pretend we have a known breakage' ' false ' test_terminal () { perl "$SHARNESS_TEST_SRCDIR"/test-terminal.perl "$@" } # If test_terminal works, then set a PERL_AND_TTY prereq for future tests: # (PERL and TTY prereqs may later be split if needed separately) test_terminal sh -c "test -t 1 && test -t 2" && test_set_prereq PERL_AND_TTY run_sub_test_lib_test () { name="$1" descr="$2" # stdin is the body of the test code prefix="$3" # optionally run sub-test under command opt="$4" # optionally call the script with extra option(s) mkdir "$name" && ( cd "$name" && cat >".$name.t" <<-EOF && #!$SHELL_PATH test_description='$descr (run in sub sharness) This is run in a sub sharness so that we do not get incorrect passing metrics ' # Point to the test/sharness.sh, which isn't in ../ as usual . "\$SHARNESS_TEST_SRCDIR"/sharness.sh EOF cat >>".$name.t" && chmod +x ".$name.t" && export SHARNESS_TEST_SRCDIR && $prefix ./".$name.t" $opt --chain-lint >out 2>err ) } check_sub_test_lib_test () { name="$1" # stdin is the expected output from the test ( cd "$name" && ! test -s err && sed -e 's/^> //' -e 's/Z$//' >expect && test_cmp expect out ) } test_expect_success 'pretend we have a fully passing test suite' " run_sub_test_lib_test full-pass '3 passing tests' <<-\\EOF && for i in 1 2 3 do test_expect_success \"passing test #\$i\" 'true' done test_done EOF check_sub_test_lib_test full-pass <<-\\EOF > ok 1 - passing test #1 > ok 2 - passing test #2 > ok 3 - passing test #3 > # passed all 3 test(s) > 1..3 EOF " test_expect_success 'pretend we have a partially passing test suite' " test_must_fail run_sub_test_lib_test \ partial-pass '2/3 tests passing' <<-\\EOF && test_expect_success 'passing test #1' 'true' test_expect_success 'failing test #2' 'false' test_expect_success 'passing test #3' 'true' test_done EOF check_sub_test_lib_test partial-pass <<-\\EOF > ok 1 - passing test #1 > not ok 2 - failing test #2 # false > ok 3 - passing test #3 > # failed 1 among 3 test(s) > 1..3 EOF " test_expect_success 'pretend we have a known breakage' " run_sub_test_lib_test failing-todo 'A failing TODO test' <<-\\EOF && test_expect_success 'passing test' 'true' test_expect_failure 'pretend we have a known breakage' 'false' test_done EOF check_sub_test_lib_test failing-todo <<-\\EOF > ok 1 - passing test > not ok 2 - pretend we have a known breakage # TODO known breakage > # still have 1 known breakage(s) > # passed all remaining 1 test(s) > 1..2 EOF " test_expect_success 'pretend we have fixed a known breakage' " run_sub_test_lib_test passing-todo 'A passing TODO test' <<-\\EOF && test_expect_failure 'pretend we have fixed a known breakage' 'true' test_done EOF check_sub_test_lib_test passing-todo <<-\\EOF > ok 1 - pretend we have fixed a known breakage # TODO known breakage vanished > # 1 known breakage(s) vanished; please update test(s) > 1..1 EOF " test_expect_success 'pretend we have fixed one of two known breakages (run in sub sharness)' " run_sub_test_lib_test partially-passing-todos \ '2 TODO tests, one passing' <<-\\EOF && test_expect_failure 'pretend we have a known breakage' 'false' test_expect_success 'pretend we have a passing test' 'true' test_expect_failure 'pretend we have fixed another known breakage' 'true' test_done EOF check_sub_test_lib_test partially-passing-todos <<-\\EOF > not ok 1 - pretend we have a known breakage # TODO known breakage > ok 2 - pretend we have a passing test > ok 3 - pretend we have fixed another known breakage # TODO known breakage vanished > # 1 known breakage(s) vanished; please update test(s) > # still have 1 known breakage(s) > # passed all remaining 1 test(s) > 1..3 EOF " test_expect_success 'pretend we have fixed one of two known breakages using --tee' " run_sub_test_lib_test partially-passing-todos-tee \ '2 TODO tests, one passing' '' --tee <<-\\EOF && test_expect_failure 'pretend we have a known breakage' 'false' test_expect_success 'pretend we have a passing test' 'true' test_expect_failure 'pretend we have fixed another known breakage' 'true' test_done EOF check_sub_test_lib_test partially-passing-todos-tee <<-\\EOF && > not ok 1 - pretend we have a known breakage # TODO known breakage > ok 2 - pretend we have a passing test > ok 3 - pretend we have fixed another known breakage # TODO known breakage vanished > # 1 known breakage(s) vanished; please update test(s) > # still have 1 known breakage(s) > # passed all remaining 1 test(s) > 1..3 EOF echo 0 >expect && test_cmp expect ../test-results/.partially-passing-todos-tee.exit && test_cmp partially-passing-todos-tee/out ../test-results/.partially-passing-todos-tee.out " test_expect_success 'pretend we have a pass, fail, and known breakage' " test_must_fail run_sub_test_lib_test \ mixed-results1 'mixed results #1' <<-\\EOF && test_expect_success 'passing test' 'true' test_expect_success 'failing test' 'false' test_expect_failure 'pretend we have a known breakage' 'false' test_done EOF check_sub_test_lib_test mixed-results1 <<-\\EOF > ok 1 - passing test > not ok 2 - failing test > # false > not ok 3 - pretend we have a known breakage # TODO known breakage > # still have 1 known breakage(s) > # failed 1 among remaining 2 test(s) > 1..3 EOF " test_expect_success 'pretend we have a mix of all possible results' " test_must_fail run_sub_test_lib_test \ mixed-results2 'mixed results #2' <<-\\EOF && test_expect_success 'passing test' 'true' test_expect_success 'passing test' 'true' test_expect_success 'passing test' 'true' test_expect_success 'passing test' 'true' test_expect_success 'failing test' 'false' test_expect_success 'failing test' 'false' test_expect_success 'failing test' 'false' test_expect_failure 'pretend we have a known breakage' 'false' test_expect_failure 'pretend we have a known breakage' 'false' test_expect_failure 'pretend we have fixed a known breakage' 'true' test_done EOF check_sub_test_lib_test mixed-results2 <<-\\EOF > ok 1 - passing test > ok 2 - passing test > ok 3 - passing test > ok 4 - passing test > not ok 5 - failing test > # false > not ok 6 - failing test > # false > not ok 7 - failing test > # false > not ok 8 - pretend we have a known breakage # TODO known breakage > not ok 9 - pretend we have a known breakage # TODO known breakage > ok 10 - pretend we have fixed a known breakage # TODO known breakage vanished > # 1 known breakage(s) vanished; please update test(s) > # still have 2 known breakage(s) > # failed 3 among remaining 7 test(s) > 1..10 EOF " test_expect_success 'pretend we have a pass, fail, and known breakage using --verbose-log' " test_must_fail run_sub_test_lib_test \ mixed-results3 'mixed results #3' '' --verbose-log <<-\\EOF && test_expect_success 'passing test' 'true' test_expect_success 'failing test' 'false' test_expect_failure 'pretend we have a known breakage' 'false' test_done EOF check_sub_test_lib_test mixed-results3 <<-\\EOF && > ok 1 - passing test > not ok 2 - failing test > # false > not ok 3 - pretend we have a known breakage # TODO known breakage > # still have 1 known breakage(s) > # failed 1 among remaining 2 test(s) > 1..3 EOF echo 1 >expect && test_cmp expect ../test-results/.mixed-results3.exit && sed -e 's/^> //' >expect <<-\\EOF && > expecting success: true > > ok 1 - passing test > expecting success: false > not ok 2 - failing test > # false > > checking known breakage: false > > not ok 3 - pretend we have a known breakage # TODO known breakage > # still have 1 known breakage(s) > # failed 1 among remaining 2 test(s) > 1..3 EOF # Output is not completely deterministic sort expect >expect.sorted && sort ../test-results/.mixed-results3.out >actual.sorted && test_cmp expect.sorted actual.sorted " test_expect_success 'pretend we have some unstable tests' " run_sub_test_lib_test \ results3 'results #3' <<-\\EOF && test_expect_success 'passing test' 'true' test_expect_success 'passing test' 'true' test_expect_unstable 'unstable test passing' 'true' test_expect_success 'passing test' 'true' test_expect_unstable 'unstable test failing' 'false' test_done EOF check_sub_test_lib_test results3 <<-\\EOF > ok 1 - passing test > ok 2 - passing test > ok 3 - unstable test passing > ok 4 - passing test > not ok 5 - unstable test failing # TODO known breakage > # still have 1 known breakage(s) > # passed all remaining 4 test(s) > 1..5 EOF " test_set_prereq HAVEIT haveit=no test_expect_success HAVEIT 'test runs if prerequisite is satisfied' ' test_have_prereq HAVEIT && haveit=yes ' donthaveit=yes test_expect_success DONTHAVEIT 'unmet prerequisite causes test to be skipped' ' donthaveit=no ' if test $haveit$donthaveit != yesyes then say "bug in test framework: prerequisite tags do not work reliably" exit 1 fi test_set_prereq HAVETHIS haveit=no test_expect_success HAVETHIS,HAVEIT 'test runs if prerequisites are satisfied' ' test_have_prereq HAVEIT && test_have_prereq HAVETHIS && haveit=yes ' donthaveit=yes test_expect_success HAVEIT,DONTHAVEIT 'unmet prerequisites causes test to be skipped' ' donthaveit=no ' donthaveiteither=yes test_expect_success DONTHAVEIT,HAVEIT 'unmet prerequisites causes test to be skipped' ' donthaveiteither=no ' if test $haveit$donthaveit$donthaveiteither != yesyesyes then say "bug in test framework: multiple prerequisite tags do not work reliably" exit 1 fi clean=no test_expect_success 'tests clean up after themselves' ' test_when_finished clean=yes ' if test $clean != yes then say "bug in test framework: basic cleanup command does not work reliably" exit 1 fi test_expect_success 'tests clean up even on failures' " test_must_fail run_sub_test_lib_test \ failing-cleanup 'Failing tests with cleanup commands' <<-\\EOF && test_expect_success 'tests clean up even after a failure' ' touch clean-after-failure && test_when_finished rm clean-after-failure && (exit 1) ' test_expect_success 'failure to clean up causes the test to fail' ' test_when_finished \"(exit 2)\" ' test_done EOF check_sub_test_lib_test failing-cleanup <<-\\EOF > not ok 1 - tests clean up even after a failure > # Z > # touch clean-after-failure && > # test_when_finished rm clean-after-failure && > # (exit 1) > # Z > not ok 2 - failure to clean up causes the test to fail > # Z > # test_when_finished \"(exit 2)\" > # Z > # failed 2 among 2 test(s) > 1..2 EOF " test_expect_success 'cleanup functions run at the end of the test' " run_sub_test_lib_test cleanup-function 'Empty test with cleanup function' <<-\\EOF && cleanup 'echo cleanup-function-called >&5' test_done EOF check_sub_test_lib_test cleanup-function <<-\\EOF 1..0 cleanup-function-called EOF " test_expect_success 'We detect broken && chains' " test_must_fail run_sub_test_lib_test \ broken-chain 'Broken && chain' <<-\\EOF test_expect_success 'Cannot fail' ' true true ' test_done EOF " test_expect_success 'tests can be run from an alternate directory' ' # Act as if we have an installation of sharness in current dir: ln -sf $SHARNESS_TEST_SRCDIR/sharness.sh . && export working_path="$(pwd)" && cat >test.t <<-EOF && test_description="test run of script from alternate dir" . \$(dirname \$0)/sharness.sh test_expect_success "success" " true " test_expect_success "trash dir is subdir of working path" " test \"\$(cd .. && pwd)\" = \"\$working_path/test-rundir\" " test_done EOF ( # unset SHARNESS variables before sub-test unset SHARNESS_TEST_DIRECTORY SHARNESS_TEST_SRCDIR && # unset HARNESS_ACTIVE so we get a test-results dir unset HARNESS_ACTIVE && chmod +x test.t && mkdir test-rundir && cd test-rundir && ../test.t >output 2>err && cat >expected <<-EOF && ok 1 - success ok 2 - trash dir is subdir of working path # passed all 2 test(s) 1..2 EOF test_cmp expected output && test -d test-results ) ' test_expect_success 'SHARNESS_ORIG_TERM propagated to sub-sharness' " ( export TERM=foo && unset SHARNESS_ORIG_TERM && run_sub_test_lib_test orig-term 'check original term' <<-\\EOF test_expect_success 'SHARNESS_ORIG_TERM is foo' ' test \"x\$SHARNESS_ORIG_TERM\" = \"xfoo\" ' test_done EOF ) " [ -z "$color" ] || test_set_prereq COLOR test_expect_success COLOR,PERL_AND_TTY 'sub-sharness still has color' " run_sub_test_lib_test \ test-color \ 'sub-sharness color check' \ test_terminal <<-\\EOF test_expect_success 'color is enabled' '[ -n \"\$color\" ]' test_done EOF " test_expect_success 'EXPENSIVE prereq not activated by default' " unset TEST_LONG && run_sub_test_lib_test no-long 'long test' <<-\\EOF && test_expect_success 'passing test' 'true' test_expect_success EXPENSIVE 'passing supposedly long test' 'true' test_done EOF check_sub_test_lib_test no-long <<-\\EOF > ok 1 - passing test > ok 2 # skip passing supposedly long test (missing EXPENSIVE) > # passed all 2 test(s) > 1..2 EOF " test_expect_success 'EXPENSIVE prereq is activated by --long' " run_sub_test_lib_test long 'long test' '' '--long' <<-\\EOF && test_expect_success 'passing test' 'true' test_expect_success EXPENSIVE 'passing supposedly long test' 'true' test_done EOF check_sub_test_lib_test long <<-\\EOF > ok 1 - passing test > ok 2 - passing supposedly long test > # passed all 2 test(s) > 1..2 EOF " test_expect_success 'loading sharness extensions works' ' # Act as if we have a new installation of sharness # under `extensions` directory. Then create # a sharness.d/ directory with a test extension function: mkdir extensions && ( cd extensions && mkdir sharness.d && cat >sharness.d/test.sh <<-EOF && this_is_a_test() { return 0 } EOF ln -sf $SHARNESS_TEST_SRCDIR/sharness.sh . && cat >test-extension.t <<-\EOF && test_description="test sharness extensions" . ./sharness.sh test_expect_success "extension function is present" " this_is_a_test " test_done EOF unset SHARNESS_TEST_DIRECTORY SHARNESS_TEST_SRCDIR && chmod +x ./test-extension.t && ./test-extension.t >out 2>err && cat >expected <<-\EOF && ok 1 - extension function is present # passed all 1 test(s) 1..1 EOF test_cmp expected out ) ' test_expect_success 'empty sharness.d directory does not cause failure' ' # Act as if we have a new installation of sharness # under `extensions` directory. Then create # an empty sharness.d/ directory mkdir nil-extensions && ( cd nil-extensions && mkdir sharness.d && ln -sf $SHARNESS_TEST_SRCDIR/sharness.sh . && cat >test.t <<-\EOF && test_description="sharness works" . ./sharness.sh test_expect_success "test success" " true " test_done EOF unset SHARNESS_TEST_DIRECTORY SHARNESS_TEST_SRCDIR && chmod +x ./test.t && ./test.t >out 2>err && cat >expected <<-\EOF && ok 1 - test success # passed all 1 test(s) 1..1 EOF test_cmp expected out ) ' test_expect_success INTERACTIVE 'Interactive tests work' ' echo -n "Please type yes and hit enter " && read -r var && test "$var" = "yes" ' test_done # vi: set ft=sh : munge-munge-0.5.15/t/0001-env-vars.t000077500000000000000000000006541425467526100166210ustar00rootroot00000000000000#!/bin/sh test_description='Check custom sharness environment variables' . "$(dirname "$0")/sharness.sh" test_expect_success 'MUNGE_BUILD_DIR directory exists' ' test_debug "echo MUNGE_BUILD_DIR=${MUNGE_BUILD_DIR}" && test -d "${MUNGE_BUILD_DIR}" ' test_expect_success 'MUNGE_SOURCE_DIR directory exists' ' test_debug "echo MUNGE_SOURCE_DIR=${MUNGE_SOURCE_DIR}" && test -d "${MUNGE_SOURCE_DIR}" ' test_done munge-munge-0.5.15/t/0002-smiple.t000077500000000000000000000027231425467526100163510ustar00rootroot00000000000000#!/bin/sh test_description="Because nothing is so simple that it can't still go wrong" . "$(dirname "$0")/sharness.sh" # When testing an expr string regex match for an absolute path, check if the # "/" regex should be escaped (i.e., "\/"). # FreeBSD requires the "/" regex in expr to be escaped. # See "m4/x_ac_with_munge_socket.m4". ## test_expect_success 'expr string match of absolute path with "/" regex' ' test_might_fail test "$(expr "/path" : "/")" -eq 1 ' test_expect_success 'expr string match of absolute path with "\/" regex' ' test "$(expr "/path" : "\/")" -eq 1 ' # Check for a given long option using an expr string regex match. # Some expr implementations require the option string to be preceded by the # "--" parameter to force an end to option-scanning. But some older # implementations don't recognize that syntax. Since no expr keyword starts # with 'X', prepending an 'X' to both strings should be a portable solution. # FreeBSD requires that a leading argument beginning with a minus sign be # considered an option to the program. ## test_expect_success 'expr string match of long opt' ' test_might_fail test "$(expr "--exec=foo" : "--exec=")" -eq 7 ' test_expect_success 'expr string match of long opt w/ preceding "--" parm' ' test_might_fail test "$(expr -- "--exec=foo" : "--exec=")" -eq 7 ' test_expect_success 'expr string match of long opt w/ prepended "X" char' ' test "$(expr X"--exec=foo" : "X--exec=")" -eq 8 ' test_done munge-munge-0.5.15/t/0010-basic.t000077500000000000000000000054531425467526100161430ustar00rootroot00000000000000#!/bin/sh test_description='Check basic functionality of MUNGE daemon and clients' . "$(dirname "$0")/sharness.sh" # Set up the environment. # test_expect_success 'setup' ' munged_setup ' # Create a key for the daemon. # test_expect_success 'create key' ' munged_create_key ' # Verify the key has been created. # test_expect_success 'check keyfile creation' ' test -s "${MUNGE_KEYFILE}" ' # Start the daemon process. # test_expect_success 'start munged' ' munged_start_daemon ' # Verify the pidfile has been created. # test_expect_success 'check pidfile creation' ' test -s "${MUNGE_PIDFILE}" ' # Verify the pid in the pidfile matches a running munged process. # test_expect_success 'check process is running' ' PID=$(cat "${MUNGE_PIDFILE}") && ps -p "${PID}" -ww | grep munged ' # Verify the socket has been created. # test_expect_success 'check socket creation' ' test -S "${MUNGE_SOCKET}" ' # Verify the logfile has been created. # test_expect_success 'check logfile creation' ' test -s "${MUNGE_LOGFILE}" ' # Encode a credential. # test_expect_success 'encode credential' ' "${MUNGE}" --socket="${MUNGE_SOCKET}" cred.$$ ' # Verify the credential string contains the expected prefix and suffix. # test_expect_success 'examine credential' ' test "$(expr X"$(cat cred.$$)" : "XMUNGE:.*:$")" -gt 0 ' # Decode a credential. # test_expect_success 'decode credential' ' "${UNMUNGE}" --socket="${MUNGE_SOCKET}" /dev/null ' # Decode the same credential a second time to check if a replay is detected. # test_expect_success 'replay credential' ' test_must_fail "${UNMUNGE}" --socket="${MUNGE_SOCKET}" /dev/null ' # Check if a message has been logged for the replayed credential. # test_expect_success 'check logfile for replay' ' grep "Replayed credential" "${MUNGE_LOGFILE}" ' # Stop the daemon process. # test_expect_success 'stop munged' ' munged_stop_daemon ' # Verify the socket has been removed. # test_expect_success 'check socket removal' ' test "x${MUNGE_SOCKET}" != x && test ! -S "${MUNGE_SOCKET}" ' # Verify the daemon process is no longer running. # test_expect_success 'check process has exited' ' test "x${PID}" != x && ! ps -p "${PID}" >/dev/null ' # Verify the pidfile has been removed. # test_expect_success 'check pidfile removal' ' test "x${MUNGE_PIDFILE}" != x && test ! -f "${MUNGE_PIDFILE}" ' # Verify the seedfile has been created. # test_expect_success 'check seedfile creation' ' test -s "${MUNGE_SEEDFILE}" ' # Check if the final log message for stopping the daemon has been written out. ## test_expect_success 'check logfile for stop' ' grep "Stopping" "${MUNGE_LOGFILE}" ' # Perform any housekeeping to clean up afterwards. # test_expect_success 'cleanup' ' munged_cleanup ' test_done munge-munge-0.5.15/t/0011-munged-cmdline.t000077500000000000000000000050371425467526100177510ustar00rootroot00000000000000#!/bin/sh test_description='Check munged command-line options' . "$(dirname "$0")/sharness.sh" # Set up the test environment. ## test_expect_success 'setup' ' munged_setup && munged_create_key ' test_expect_success 'munged invalid option' ' test_must_fail "${MUNGED}" --invalid-option ' for OPT_HELP in '-h' '--help'; do test_expect_success "munged ${OPT_HELP}" ' "${MUNGED}" "${OPT_HELP}" | grep -q "^Usage:" ' done for OPT_LICENSE in '-L' '--license'; do test_expect_success "munged ${OPT_LICENSE}" ' "${MUNGED}" "${OPT_LICENSE}" | grep -q "GNU General Public License" ' done for OPT_VERSION in '-V' '--version'; do test_expect_success "munged ${OPT_VERSION}" ' "${MUNGED}" "${OPT_VERSION}" | grep -q "^munge-[0-9.]*" ' done for OPT_STOP in '-s' '--stop'; do test_expect_success "munged ${OPT_STOP}" ' munged_start_daemon && "${MUNGED}" "${OPT_STOP}" --socket="${MUNGE_SOCKET}" ' done # Check if the stop option properly fails to stop a daemon on a non-existent # socket. ## test_expect_success 'munged --stop for missing socket' ' test_must_fail "${MUNGED}" --stop --socket=missing.socket.$$ ' for OPT_VERBOSE in '-v' '--verbose'; do test_expect_success "munged ${OPT_VERBOSE}" ' munged_start_daemon && "${MUNGED}" "${OPT_VERBOSE}" --stop --socket="${MUNGE_SOCKET}" 2>&1 | egrep -q "(Terminated|Killed) daemon" ' done # Check for a regression of a seedfile being specified by a relative pathname # failing to be created at exit. ## test_expect_success 'munged seedfile creation with relative pathname' ' local SEEDFILE="seed.$$" && munged_start_daemon --seed-file="${SEEDFILE}" && munged_stop_daemon && test -s "${SEEDFILE}" ' # Check for a regression of a socket being specified by a relative pathname # failing to be removed at exit. # Set the CWD to the MUNGE_SOCKETDIR (which should be in TMPDIR) in order to # prevent the socket pathname from exceeding the maximum length of 108 bytes # for a Unix domain socket. Without this, "make distcheck" failed. ## test_expect_success 'munged socket cleanup with relative pathname' ' local SOCKET="socket.$$" && cd "${MUNGE_SOCKETDIR}" && munged_start_daemon --socket="${SOCKET}" && munged_stop_daemon --socket="${SOCKET}" && test ! -S "${SOCKET}" ' test_expect_failure 'finish writing tests' ' false ' # Clean up after a munged process that may not have terminated. ## test_expect_success 'cleanup' ' munged_cleanup ' test_done munge-munge-0.5.15/t/0012-munge-cmdline.t000077500000000000000000000530051425467526100176040ustar00rootroot00000000000000#!/bin/sh test_description='Check munge command-line options' . "$(dirname "$0")/sharness.sh" test_expect_success 'munge invalid option' ' test_must_fail "${MUNGE}" --invalid-option ' for OPT_HELP in '-h' '--help'; do test_expect_success "munge ${OPT_HELP}" ' "${MUNGE}" "${OPT_HELP}" | grep -q "^Usage:" ' done for OPT_LICENSE in '-L' '--license'; do test_expect_success "munge ${OPT_LICENSE}" ' "${MUNGE}" "${OPT_LICENSE}" | grep -q "GNU General Public License" ' done for OPT_VERSION in '-V' '--version'; do test_expect_success "munge ${OPT_VERSION}" ' "${MUNGE}" "${OPT_VERSION}" | grep -q "^munge-[0-9.]*" ' done test_expect_success 'start munged' ' munged_setup && munged_create_key && munged_start_daemon ' for OPT_SOCKET in '-S' '--socket'; do test_expect_success "munge ${OPT_SOCKET}" ' "${MUNGE}" "${OPT_SOCKET}" "${MUNGE_SOCKET}" in.$$ && "${MUNGE}" --socket="${MUNGE_SOCKET}" in.$$ && "${MUNGE}" --socket="${MUNGE_SOCKET}" "${OPT_INPUT}" in.$$ | "${UNMUNGE}" --socket="${MUNGE_SOCKET}" --no-output --output=out.$$ && test_cmp in.$$ out.$$ ' done test_expect_success 'munge --input from stdin via "-"' ' echo -n xyzzy-$$ >in.$$ && "${MUNGE}" --socket="${MUNGE_SOCKET}" --input=- in.$$ && "${MUNGE}" --socket="${MUNGE_SOCKET}" "${OPT_OUTPUT}" cred.$$ in.$$ && "${MUNGE}" --socket="${MUNGE_SOCKET}" --output=- in.$$ && "${MUNGE}" --socket="${MUNGE_SOCKET}" --output=/dev/null out.$$ && test ! -s out.$$ ' for OPT_LIST_CIPHERS in '-C' '--list-ciphers'; do test_expect_success "munge ${OPT_LIST_CIPHERS}" ' "${MUNGE}" "${OPT_LIST_CIPHERS}" | grep -q "^Cipher types:$" ' done for OPT_CIPHER in '-c' '--cipher'; do test_expect_success "munge ${OPT_CIPHER} for default by name" ' "${MUNGE}" --socket="${MUNGE_SOCKET}" --no-input \ "${OPT_CIPHER}" default | "${UNMUNGE}" --socket="${MUNGE_SOCKET}" --no-output ' done test_expect_success 'munge --cipher for default by number' ' "${MUNGE}" --socket="${MUNGE_SOCKET}" --no-input --cipher=1 | "${UNMUNGE}" --socket="${MUNGE_SOCKET}" --no-output ' test_expect_success 'munge --cipher for none by name' ' "${MUNGE}" --socket="${MUNGE_SOCKET}" --no-input --cipher=none | "${UNMUNGE}" --socket="${MUNGE_SOCKET}" | awk "/^CIPHER:/ { print \$2 }" >meta.$$ && test "$(cat meta.$$)" = none ' test_expect_success 'munge --cipher for none by number' ' "${MUNGE}" --socket="${MUNGE_SOCKET}" --no-input --cipher=0 | "${UNMUNGE}" --socket="${MUNGE_SOCKET}" | awk "/^CIPHER:/ { print \$2 }" >meta.$$ && test "$(cat meta.$$)" = none ' test_expect_success 'munge --cipher for invalid name' ' test_must_fail "${MUNGE}" --socket="${MUNGE_SOCKET}" --no-input \ --cipher=invalid ' test_expect_success 'munge --cipher for invalid positive number' ' test_must_fail "${MUNGE}" --socket="${MUNGE_SOCKET}" --no-input --cipher=88 ' test_expect_success 'munge --cipher for invalid negative number' ' test_must_fail "${MUNGE}" --socket="${MUNGE_SOCKET}" --no-input --cipher=-1 ' test_expect_success 'munge --cipher for each cipher by name' ' local META NAME NUM EXTRA && >fail.$$ && "${MUNGE}" --list-ciphers | awk "/([0-9]+)/ { gsub(/[()]/, \"\"); print \$2, \$1 }" | while read NUM NAME EXTRA; do "${MUNGE}" --socket="${MUNGE_SOCKET}" --no-input --cipher="${NAME}" | "${UNMUNGE}" --socket="${MUNGE_SOCKET}" | awk "/^CIPHER:/ { print \$2 }" >meta.$$ && META=$(cat meta.$$) && if test "${NAME}" = "${META}" || test "${NAME}" = default; then test_debug "echo \"Decoded cipher [${NUM}/${NAME}] as [${META}]\"" else echo "Error: munge --cipher=${NAME} failed" echo "cipher ${NUM} ${NAME} ${META}" >>fail.$$; fi done && test ! -s fail.$$ ' test_expect_success 'munge --cipher for each cipher by number' ' local META NAME NUM EXTRA && >fail.$$ && "${MUNGE}" --list-ciphers | awk "/([0-9]+)/ { gsub(/[()]/, \"\"); print \$2, \$1 }" | while read NUM NAME EXTRA; do "${MUNGE}" --socket="${MUNGE_SOCKET}" --no-input --cipher="${NUM}" | "${UNMUNGE}" --socket="${MUNGE_SOCKET}" | awk "/^CIPHER:/ { print \$2 }" >meta.$$ && META=$(cat meta.$$) && if test "${NAME}" = "${META}" || test "${NAME}" = default; then test_debug "echo \"Decoded cipher [${NUM}/${NAME}] as [${META}]\"" else echo "Error: munge --cipher=${NUM} failed" echo "cipher ${NUM} ${NAME} ${META}" >>fail.$$; fi done && test ! -s fail.$$ ' for OPT_LIST_MACS in '-M' '--list-macs'; do test_expect_success "munge ${OPT_LIST_MACS}" ' "${MUNGE}" "${OPT_LIST_MACS}" | grep -q "^MAC types:$" ' done for OPT_MAC in '-m' '--mac'; do test_expect_success "munge ${OPT_MAC} for default by name" ' "${MUNGE}" --socket="${MUNGE_SOCKET}" --no-input "${OPT_MAC}" default | "${UNMUNGE}" --socket="${MUNGE_SOCKET}" --no-output ' done test_expect_success 'munge --mac for default by number' ' "${MUNGE}" --socket="${MUNGE_SOCKET}" --no-input --mac=1 | "${UNMUNGE}" --socket="${MUNGE_SOCKET}" --no-output ' test_expect_success 'munge --mac for none by name' ' test_must_fail "${MUNGE}" --socket="${MUNGE_SOCKET}" --no-input --mac=none ' test_expect_success 'munge --mac for none by number' ' test_must_fail "${MUNGE}" --socket="${MUNGE_SOCKET}" --no-input --mac=0 ' test_expect_success 'munge --mac for invalid name' ' test_must_fail "${MUNGE}" --socket="${MUNGE_SOCKET}" --no-input \ --mac=invalid ' test_expect_success 'munge --mac for invalid positive number' ' test_must_fail "${MUNGE}" --socket="${MUNGE_SOCKET}" --no-input --mac=88 ' test_expect_success 'munge --mac for invalid negative number' ' test_must_fail "${MUNGE}" --socket="${MUNGE_SOCKET}" --no-input --mac=-1 ' test_expect_success 'munge --mac for each mac by name' ' local META NAME NUM EXTRA && >fail.$$ && "${MUNGE}" --list-macs | awk "/([0-9]+)/ { gsub(/[()]/, \"\"); print \$2, \$1 }" | while read NUM NAME EXTRA; do "${MUNGE}" --socket="${MUNGE_SOCKET}" --no-input --mac="${NAME}" | "${UNMUNGE}" --socket="${MUNGE_SOCKET}" | awk "/^MAC:/ { print \$2 }" >meta.$$ && META=$(cat meta.$$) && if test "${NAME}" = "${META}" || test "${NAME}" = default; then test_debug "echo \"Decoded mac [${NUM}/${NAME}] as [${META}]\"" else echo "Error: munge --mac=${NAME} failed" echo "mac ${NUM} ${NAME} ${META}" >>fail.$$; fi done && test ! -s fail.$$ ' test_expect_success 'munge --mac for each mac by number' ' local META NAME NUM EXTRA && >fail.$$ && "${MUNGE}" --list-macs | awk "/([0-9]+)/ { gsub(/[()]/, \"\"); print \$2, \$1 }" | while read NUM NAME EXTRA; do "${MUNGE}" --socket="${MUNGE_SOCKET}" --no-input --mac="${NUM}" | "${UNMUNGE}" --socket="${MUNGE_SOCKET}" | awk "/^MAC:/ { print \$2 }" >meta.$$ && META=$(cat meta.$$) && if test "${NAME}" = "${META}" || test "${NAME}" = default; then test_debug "echo \"Decoded mac [${NUM}/${NAME}] as [${META}]\"" else echo "Error: munge --mac=${NUM} failed" echo "mac ${NUM} ${NAME} ${META}" >>fail.$$; fi done && test ! -s fail.$$ ' for OPT_LIST_ZIPS in '-Z' '--list-zips'; do test_expect_success "munge ${OPT_LIST_ZIPS}" ' "${MUNGE}" "${OPT_LIST_ZIPS}" | grep -q "^Compression types:$" ' done # Compression will be disabled if the compressed credential is not smaller than # an uncompressed credential. Consequently, encode a highly-compressible # payload when testing --zip to force compression. ## for OPT_ZIP in '-z' '--zip'; do test_expect_success "munge ${OPT_ZIP} for default by name" ' "${MUNGE}" --socket="${MUNGE_SOCKET}" --no-input \ "${OPT_ZIP}" default --string="$(printf %0128d 0)" | "${UNMUNGE}" --socket="${MUNGE_SOCKET}" --no-output ' done test_expect_success 'munge --zip for default by number' ' "${MUNGE}" --socket="${MUNGE_SOCKET}" --no-input --zip=1 \ --string="$(printf %0128d 0)" | "${UNMUNGE}" --socket="${MUNGE_SOCKET}" --no-output ' test_expect_success 'munge --zip for none by name' ' "${MUNGE}" --socket="${MUNGE_SOCKET}" --no-input --zip=none \ --string="$(printf %0128d 0)" | "${UNMUNGE}" --socket="${MUNGE_SOCKET}" | awk "/^ZIP:/ { print \$2 }" >meta.$$ && test "$(cat meta.$$)" = none ' test_expect_success 'munge --zip for none by number' ' "${MUNGE}" --socket="${MUNGE_SOCKET}" --no-input --zip=0 \ --string="$(printf %0128d 0)" | "${UNMUNGE}" --socket="${MUNGE_SOCKET}" | awk "/^ZIP:/ { print \$2 }" >meta.$$ && test "$(cat meta.$$)" = none ' test_expect_success 'munge --zip for invalid name' ' test_must_fail "${MUNGE}" --socket="${MUNGE_SOCKET}" --no-input \ --zip=invalid ' test_expect_success 'munge --zip for invalid positive number' ' test_must_fail "${MUNGE}" --socket="${MUNGE_SOCKET}" --no-input --zip=88 ' test_expect_success 'munge --zip for invalid negative number' ' test_must_fail "${MUNGE}" --socket="${MUNGE_SOCKET}" --no-input --zip=-1 ' test_expect_success 'munge --zip for each zip by name' ' local META NAME NUM EXTRA && >fail.$$ && "${MUNGE}" --list-zips | awk "/([0-9]+)/ { gsub(/[()]/, \"\"); print \$2, \$1 }" | while read NUM NAME EXTRA; do "${MUNGE}" --socket="${MUNGE_SOCKET}" --no-input --zip="${NAME}" \ --string="$(printf %0128d 0)" | "${UNMUNGE}" --socket="${MUNGE_SOCKET}" | awk "/^ZIP:/ { print \$2 }" >meta.$$ && META=$(cat meta.$$) && if test "${NAME}" = "${META}" || test "${NAME}" = default; then test_debug "echo \"Decoded zip [${NUM}/${NAME}] as [${META}]\"" else echo "Error: munge --zip=${NAME} failed" echo "zip ${NUM} ${NAME} ${META}" >>fail.$$; fi done && test ! -s fail.$$ ' test_expect_success 'munge --zip for each zip by number' ' local META NAME NUM EXTRA && >fail.$$ && "${MUNGE}" --list-zips | awk "/([0-9]+)/ { gsub(/[()]/, \"\"); print \$2, \$1 }" | while read NUM NAME EXTRA; do "${MUNGE}" --socket="${MUNGE_SOCKET}" --no-input --zip="${NUM}" \ --string="$(printf %0128d 0)" | "${UNMUNGE}" --socket="${MUNGE_SOCKET}" | awk "/^ZIP:/ { print \$2 }" >meta.$$ && META=$(cat meta.$$) && if test "${NAME}" = "${META}" || test "${NAME}" = default; then test_debug "echo \"Decoded zip [${NUM}/${NAME}] as [${META}]\"" else echo "Error: munge --zip=${NUM} failed" echo "zip ${NUM} ${NAME} ${META}" >>fail.$$; fi done && test ! -s fail.$$ ' for OPT_RESTRICT_UID in '-u' '--restrict-uid'; do test_expect_success "munge ${OPT_RESTRICT_UID} by name" ' local ID=$(id -u -n) META && "${MUNGE}" --socket="${MUNGE_SOCKET}" --no-input \ "${OPT_RESTRICT_UID}" "${ID}" | "${UNMUNGE}" --socket="${MUNGE_SOCKET}" | awk "/^UID_RESTRICTION:/ { print \$2 }" >meta.$$ && META=$(cat meta.$$) && test "${ID}" = "${META}" && test_debug "echo \"UID Restriction user [${ID}] matches [${META}]\"" ' done test_expect_success 'munge --restrict-uid by number' ' local ID=$(id -u) META && "${MUNGE}" --socket="${MUNGE_SOCKET}" --no-input --restrict-uid="${ID}" | "${UNMUNGE}" --socket="${MUNGE_SOCKET}" | awk "/^UID_RESTRICTION:/ { gsub(/[()]/, \"\"); print \$3 }" >meta.$$ && META=$(cat meta.$$) && test "${ID}" = "${META}" && test_debug "echo \"UID Restriction user [${ID}] matches [${META}]\"" ' test_expect_success 'munge --restrict-uid for invalid name' ' test_must_fail "${MUNGE}" --socket="${MUNGE_SOCKET}" --no-input \ --restrict-uid=invalid$$ ' test_expect_success 'munge --restrict-uid for invalid number' ' test_must_fail "${MUNGE}" --socket="${MUNGE_SOCKET}" --no-input \ --restrict-uid=-1 ' for OPT_UID in '-U' '--uid'; do test_expect_success "munge ${OPT_UID} for effective user by name" ' local ID=$(id -u -n) META && "${MUNGE}" --socket="${MUNGE_SOCKET}" --no-input "${OPT_UID}" "${ID}" | "${UNMUNGE}" --socket="${MUNGE_SOCKET}" | awk "/^UID:/ { print \$2 }" >meta.$$ && META=$(cat meta.$$) && test "${ID}" = "${META}" && test_debug "echo \"Effective user [${ID}] matches [${META}]\"" ' done test_expect_success 'munge --uid for effective user by number' ' local ID=$(id -u) META && "${MUNGE}" --socket="${MUNGE_SOCKET}" --no-input --uid="${ID}" | "${UNMUNGE}" --socket="${MUNGE_SOCKET}" | awk "/^UID:/ { gsub(/[()]/, \"\"); print \$3 }" >meta.$$ && META=$(cat meta.$$) && test "${ID}" = "${META}" && test_debug "echo \"Effective uid [${ID}] matches [${META}]\"" ' test_expect_success SUDO 'munge --uid for root user by name via sudo' ' local ID=root META && sudo LD_LIBRARY_PATH="${LD_LIBRARY_PATH}" "${MUNGE}" \ --socket="${MUNGE_SOCKET}" --no-input --uid="${ID}" | "${UNMUNGE}" --socket="${MUNGE_SOCKET}" | awk "/^UID:/ { print \$2 }" >meta.$$ && META=$(cat meta.$$) && test "${ID}" = "${META}" && test_debug "echo \"sudo user [${ID}] matches [${META}]\"" ' test_expect_success SUDO 'munge --uid for root user by number via sudo' ' local ID=0 META && sudo LD_LIBRARY_PATH="${LD_LIBRARY_PATH}" "${MUNGE}" \ --socket="${MUNGE_SOCKET}" --no-input --uid="${ID}" | "${UNMUNGE}" --socket="${MUNGE_SOCKET}" | awk "/^UID:/ { gsub(/[()]/, \"\"); print \$3 }" >meta.$$ && META=$(cat meta.$$) && test "${ID}" = "${META}" && test_debug "echo \"sudo uid [${ID}] matches [${META}]\"" ' test_expect_success 'munge --uid for invalid name' ' test_must_fail "${MUNGE}" --socket="${MUNGE_SOCKET}" --no-input \ --uid=invalid$$ ' test_expect_success 'munge --uid for invalid number' ' test_must_fail "${MUNGE}" --socket="${MUNGE_SOCKET}" --no-input --uid=-1 ' for OPT_RESTRICT_GID in '-g' '--restrict-gid'; do test_expect_success "munge ${OPT_RESTRICT_GID} by name" ' local ID=$(id -g -n) META && "${MUNGE}" --socket="${MUNGE_SOCKET}" --no-input \ "${OPT_RESTRICT_GID}" "${ID}" | "${UNMUNGE}" --socket="${MUNGE_SOCKET}" | awk "/^GID_RESTRICTION:/ { print \$2 }" >meta.$$ && META=$(cat meta.$$) && test "${ID}" = "${META}" && test_debug "echo \"GID Restriction GROUP [${ID}] matches [${META}]\"" ' done test_expect_success 'munge --restrict-gid by number' ' local ID=$(id -g) META && "${MUNGE}" --socket="${MUNGE_SOCKET}" --no-input --restrict-gid="${ID}" | "${UNMUNGE}" --socket="${MUNGE_SOCKET}" | awk "/^GID_RESTRICTION:/ { gsub(/[()]/, \"\"); print \$3 }" >meta.$$ && META=$(cat meta.$$) && test "${ID}" = "${META}" && test_debug "echo \"GID Restriction GROUP [${ID}] matches [${META}]\"" ' test_expect_success 'munge --restrict-gid for invalid name' ' test_must_fail "${MUNGE}" --socket="${MUNGE_SOCKET}" --no-input \ --restrict-gid=invalid$$ ' test_expect_success 'munge --restrict-gid for invalid number' ' test_must_fail "${MUNGE}" --socket="${MUNGE_SOCKET}" --no-input \ --restrict-gid=-1 ' for OPT_GID in '-G' '--gid'; do test_expect_success "munge ${OPT_GID} for effective group by name" ' local ID=$(id -g -n) META && "${MUNGE}" --socket="${MUNGE_SOCKET}" --no-input "${OPT_GID}" "${ID}" | "${UNMUNGE}" --socket="${MUNGE_SOCKET}" | awk "/^GID:/ { print \$2 }" >meta.$$ && META=$(cat meta.$$) && test "${ID}" = "${META}" && test_debug "echo \"Effective group [${ID}] matches [${META}]\"" ' done test_expect_success 'munge --gid for effective group by number' ' local ID=$(id -g) META && "${MUNGE}" --socket="${MUNGE_SOCKET}" --no-input --gid="${ID}" | "${UNMUNGE}" --socket="${MUNGE_SOCKET}" | awk "/^GID:/ { gsub(/[()]/, \"\"); print \$3 }" >meta.$$ && META=$(cat meta.$$) && test "${ID}" = "${META}" && test_debug "echo \"Effective gid [${ID}] matches [${META}]\"" ' # Since FreeBSD uses the wheel group instead of the root group, # query root's group via id. ## test_expect_success SUDO 'munge --gid for root group by name via sudo' ' local ID=$(id -g -n root) META && sudo LD_LIBRARY_PATH="${LD_LIBRARY_PATH}" "${MUNGE}" \ --socket="${MUNGE_SOCKET}" --no-input --gid="${ID}" | "${UNMUNGE}" --socket="${MUNGE_SOCKET}" | awk "/^GID:/ { print \$2 }" >meta.$$ && META=$(cat meta.$$) && test "${ID}" = "${META}" && test_debug "echo \"sudo group [${ID}] matches [${META}]\"" ' test_expect_success SUDO 'munge --gid for root group by number via sudo' ' local ID=0 META && sudo LD_LIBRARY_PATH="${LD_LIBRARY_PATH}" "${MUNGE}" \ --socket="${MUNGE_SOCKET}" --no-input --gid="${ID}" | "${UNMUNGE}" --socket="${MUNGE_SOCKET}" | awk "/^GID:/ { gsub(/[()]/, \"\"); print \$3 }" >meta.$$ && META=$(cat meta.$$) && test "${ID}" = "${META}" && test_debug "echo \"sudo gid [${ID}] matches [${META}]\"" ' test_expect_success 'munge --gid for invalid name' ' test_must_fail "${MUNGE}" --socket="${MUNGE_SOCKET}" --no-input \ --gid=invalid$$ ' test_expect_success 'munge --gid for invalid number' ' test_must_fail "${MUNGE}" --socket="${MUNGE_SOCKET}" --no-input --gid=-1 ' for OPT_TTL in '-t' '--ttl'; do test_expect_success "munge ${OPT_TTL} for default value" ' "${MUNGE}" --socket="${MUNGE_SOCKET}" --no-input "${OPT_TTL}" 0 | "${UNMUNGE}" --socket="${MUNGE_SOCKET}" --no-output ' done test_expect_success 'munge --ttl for maximum value' ' "${MUNGE}" --socket="${MUNGE_SOCKET}" --no-input --ttl=-1 | "${UNMUNGE}" --socket="${MUNGE_SOCKET}" --no-output ' test_expect_success 'munge --ttl for non-default value' ' local TTL=88 META && "${MUNGE}" --socket="${MUNGE_SOCKET}" --no-input --ttl="${TTL}" | "${UNMUNGE}" --socket="${MUNGE_SOCKET}" | awk "/^TTL:/ { print \$2 }" >meta.$$ && META=$(cat meta.$$) && test "${TTL}" = "${META}" && test_debug "echo \"TTL [${TTL}] matches [${META}]\"" ' test_expect_success 'munge --ttl for invalid string value' ' test_must_fail "${MUNGE}" --socket="${MUNGE_SOCKET}" --no-input \ --ttl=invalid ' test_expect_success 'munge --ttl for invalid positive number' ' test_must_fail "${MUNGE}" --socket="${MUNGE_SOCKET}" --no-input \ --ttl=4294967296 ' test_expect_success 'munge --ttl for invalid negative number' ' test_must_fail "${MUNGE}" --socket="${MUNGE_SOCKET}" --no-input --ttl=-2 ' test_expect_success 'stop munged' ' munged_stop_daemon ' test_expect_success 'cleanup' ' munged_cleanup ' test_done munge-munge-0.5.15/t/0013-unmunge-cmdline.t000077500000000000000000000173731425467526100201600ustar00rootroot00000000000000#!/bin/sh test_description='Check unmunge command-line options' . "$(dirname "$0")/sharness.sh" test_expect_success 'unmunge invalid option' ' test_must_fail "${UNMUNGE}" --invalid-option ' for OPT_HELP in '-h' '--help'; do test_expect_success "unmunge ${OPT_HELP}" ' "${UNMUNGE}" "${OPT_HELP}" | grep -q "^Usage:" ' done for OPT_LICENSE in '-L' '--license'; do test_expect_success "unmunge ${OPT_LICENSE}" ' "${UNMUNGE}" "${OPT_LICENSE}" | grep -q "GNU General Public License" ' done for OPT_VERSION in '-V' '--version'; do test_expect_success "unmunge ${OPT_VERSION}" ' "${UNMUNGE}" "${OPT_VERSION}" | grep -q "^munge-[0-9.]*" ' done test_expect_success 'start munged' ' munged_setup && munged_create_key && munged_start_daemon ' for OPT_SOCKET in '-S' '--socket'; do test_expect_success "unmunge ${OPT_SOCKET}" ' "${MUNGE}" --socket="${MUNGE_SOCKET}" --no-input | "${UNMUNGE}" "${OPT_SOCKET}" "${MUNGE_SOCKET}" >/dev/null ' done test_expect_success 'unmunge --socket for missing socket' ' "${MUNGE}" --socket="${MUNGE_SOCKET}" --no-input | test_must_fail "${UNMUNGE}" --socket=missing.socket.$$ ' test_expect_success 'unmunge --socket for invalid socket (file)' ' touch invalid.socket.file.$$ && "${MUNGE}" --socket="${MUNGE_SOCKET}" --no-input | test_must_fail "${UNMUNGE}" --socket=invalid.socket.file.$$ ' test_expect_success 'unmunge --socket for invalid socket (directory)' ' mkdir invalid.socket.dir.$$ && "${MUNGE}" --socket="${MUNGE_SOCKET}" --no-input | test_must_fail "${UNMUNGE}" --socket=invalid.socket.dir.$$ ' test_expect_success 'unmunge reading from /dev/null' ' test_must_fail "${UNMUNGE}" --socket="${MUNGE_SOCKET}" /dev/null ' done test_expect_success 'unmunge --input from stdin via "-"' ' "${MUNGE}" --socket="${MUNGE_SOCKET}" --no-input | "${UNMUNGE}" --socket="${MUNGE_SOCKET}" --input=- >/dev/null ' test_expect_success 'unmunge --input from /dev/null' ' test_must_fail "${UNMUNGE}" --socket="${MUNGE_SOCKET}" --input=/dev/null ' test_expect_success 'unmunge --input from missing file' ' test_must_fail "${UNMUNGE}" --socket="${MUNGE_SOCKET}" \ --input=missing.file.$$ ' for OPT_NO_OUTPUT in '-n' '--no-output'; do test_expect_success "unmunge ${OPT_NO_OUTPUT}" ' local PAYLOAD=xyzzy-$$ && "${MUNGE}" --socket="${MUNGE_SOCKET}" --string="${PAYLOAD}" | "${UNMUNGE}" --socket="${MUNGE_SOCKET}" "${OPT_NO_OUTPUT}" >out.$$ && test ! -s out.$$ ' done for OPT_METADATA in '-m' '--metadata'; do test_expect_success "unmunge ${OPT_METADATA}" ' local PAYLOAD=xyzzy-$$ && "${MUNGE}" --socket="${MUNGE_SOCKET}" --string="${PAYLOAD}" | "${UNMUNGE}" --socket="${MUNGE_SOCKET}" "${OPT_METADATA}" meta.$$ \ >out.$$ && grep -q "^STATUS:" meta.$$ && grep -q -v "^${PAYLOAD}" meta.$$ && test "$(cat out.$$)" = "${PAYLOAD}" ' done test_expect_success 'unmunge --metadata to stdout via "-" along with payload' ' local PAYLOAD=xyzzy-$$ && "${MUNGE}" --socket="${MUNGE_SOCKET}" --string="${PAYLOAD}" | "${UNMUNGE}" --socket="${MUNGE_SOCKET}" --metadata=- >meta.out.$$ && grep -q "^STATUS:" meta.out.$$ && grep -q "^${PAYLOAD}" meta.out.$$ ' test_expect_success 'unmunge --metadata to /dev/null with payload on stdout' ' local PAYLOAD=xyzzy-$$ && "${MUNGE}" --socket="${MUNGE_SOCKET}" --string="${PAYLOAD}" | "${UNMUNGE}" --socket="${MUNGE_SOCKET}" --metadata=/dev/null >out.$$ && grep -q -v "^STATUS:" out.$$ && test "$(cat out.$$)" = "${PAYLOAD}" ' for OPT_OUTPUT in '-o' '--output'; do test_expect_success "unmunge ${OPT_OUTPUT}" ' local PAYLOAD=xyzzy-$$ && "${MUNGE}" --socket="${MUNGE_SOCKET}" --string="${PAYLOAD}" | "${UNMUNGE}" --socket="${MUNGE_SOCKET}" "${OPT_OUTPUT}" out.$$ \ >meta.$$ && grep -q "^STATUS:" meta.$$ && grep -q -v "^${PAYLOAD}" meta.$$ && test "$(cat out.$$)" = "${PAYLOAD}" ' done test_expect_success 'unmunge --output to stdout via "-" along with metadata' ' local PAYLOAD=xyzzy-$$ && "${MUNGE}" --socket="${MUNGE_SOCKET}" --string="${PAYLOAD}" | "${UNMUNGE}" --socket="${MUNGE_SOCKET}" --output=- >meta.out.$$ && grep -q "^STATUS:" meta.out.$$ && grep -q "^${PAYLOAD}" meta.out.$$ ' test_expect_success 'unmunge --output to /dev/null with metadata on stdout' ' local PAYLOAD=xyzzy-$$ && "${MUNGE}" --socket="${MUNGE_SOCKET}" --string="${PAYLOAD}" | "${UNMUNGE}" --socket="${MUNGE_SOCKET}" --output=/dev/null >meta.$$ && grep -q "^STATUS:" meta.$$ && grep -q -v "${PAYLOAD}" meta.$$ ' for OPT_LIST_KEYS in '-K' '--list-keys'; do test_expect_success "unmunge ${OPT_LIST_KEYS}" ' "${UNMUNGE}" "${OPT_LIST_KEYS}" | grep -q "^Metadata keys:$" ' done for OPT_KEYS in '-k' '--keys'; do test_expect_success "unmunge ${OPT_KEYS}" ' local KEY=LENGTH && "${MUNGE}" --socket="${MUNGE_SOCKET}" --no-input | "${UNMUNGE}" --socket="${MUNGE_SOCKET}" "${OPT_KEYS}" ${KEY} | awk "/${KEY}:/ { gsub(/:/, \"\"); print \$1 }" >meta.$$ && test "$(cat meta.$$)" = "${KEY}" ' done test_expect_success 'unmunge --keys for ignoring invalid key' ' "${MUNGE}" --socket="${MUNGE_SOCKET}" --no-input | "${UNMUNGE}" --socket="${MUNGE_SOCKET}" --keys=invalid ' test_expect_success 'unmunge --keys for single uppercase key' ' "${MUNGE}" --socket="${MUNGE_SOCKET}" --no-input | "${UNMUNGE}" --socket="${MUNGE_SOCKET}" --keys=STATUS | awk "/STATUS:/ { gsub(/:/, \"\"); print \$1 }" >meta.$$ && test STATUS = "$(cat meta.$$)" ' test_expect_success 'unmunge --keys for single lowercase key' ' "${MUNGE}" --socket="${MUNGE_SOCKET}" --no-input | "${UNMUNGE}" --socket="${MUNGE_SOCKET}" --keys=status | awk "/STATUS:/ { gsub(/:/, \"\"); print \$1 }" >meta.$$ && test STATUS = "$(cat meta.$$)" ' for FS in ' ' ',' ';' '.'; do test_expect_success "unmunge --keys for multiple keys split by \"${FS}\"" ' "${MUNGE}" --socket="${MUNGE_SOCKET}" --no-input | "${UNMUNGE}" --socket="${MUNGE_SOCKET}" \ --keys="STATUS${FS}UID${FS}GID" | awk "/^(STATUS|UID|GID):/ { i++ } END { print i }" >cnt.$$ && test "$(cat cnt.$$)" -eq 3 ' done test_expect_success 'unmunge --keys for each key' ' >fail.$$ && "${UNMUNGE}" --list-keys | awk "/^ [A-Z_]+\$/ { print \$1 }" | while read KEY EXTRA; do "${MUNGE}" --socket="${MUNGE_SOCKET}" --no-input \ --restrict-uid="$(id -u)" --restrict-gid="$(id -g)" | "${UNMUNGE}" --socket="${MUNGE_SOCKET}" --keys="${KEY}" | awk "/${KEY}:/ { gsub(/:/, \"\"); print \$1 }" >meta.$$ if test "$(cat meta.$$)" = "${KEY}"; then test_debug "echo \"Tested unmunge --keys=${KEY}\"" else echo "Error: unmunge --keys=${KEY} failed" echo "${KEY}" >>fail.$$ fi done && test ! -s fail.$$ ' for OPT_NUMERIC in '-N' '--numeric'; do test_expect_success "unmunge ${OPT_NUMERIC}" ' "${MUNGE}" --socket="${MUNGE_SOCKET}" --no-input \ --restrict-uid="$(id -u)" --restrict-gid="$(id -g)" | "${UNMUNGE}" --socket="${MUNGE_SOCKET}" "${OPT_NUMERIC}" \ --metadata=meta.$$ && ! grep -q -v "^[A-Z_]*: *[0-9.]*$" meta.$$ ' done test_expect_success 'stop munged' ' munged_stop_daemon ' test_expect_success 'cleanup' ' munged_cleanup ' test_done munge-munge-0.5.15/t/0015-mungekey-cmdline.t000077500000000000000000000333101425467526100203150ustar00rootroot00000000000000#!/bin/sh test_description='Check mungekey command-line options' . "$(dirname "$0")/sharness.sh" # Check if an invalid short-option displays the expected option text in the # error message. ## test_expect_success 'mungekey invalid short option' ' test_must_fail "${MUNGEKEY}" -9 2>err.$$ && grep -q "Option \"-9\" is invalid" err.$$ ' # Check if an invalid long-option displays the expected option text in the # error message. ## test_expect_success 'mungekey invalid long option' ' test_must_fail "${MUNGEKEY}" --invalid-option 2>err.$$ && grep -q "Option \"--invalid-option\" is invalid" err.$$ ' # Check if a non-printable option is handled. This tests the case where the # text of an invalid option cannot be properly displayed. ## test_expect_success 'mungekey invalid non-printable short option' ' test_must_fail "${MUNGEKEY}" - 2>err.$$ && grep -q "Failed to process command-line" err.$$ ' # Check if an unimplemented option is handled. # The unimplemented short-option is specified in GETOPT_DEBUG_SHORT_OPTS # when configured with --enable-debug. ## test_expect_success DEBUG 'mungekey unimplemented option' ' test_must_fail "${MUNGEKEY}" -8 2>err.$$ && grep -q "Option \"-8\" is not implemented" err.$$ ' # Check if a non-option option (i.e., one without a single or double leading # hyphen) is handled. This tests the case of leftover args in argv[] after # getopt_long() is finished. ## test_expect_success 'mungekey unrecognized option' ' test_must_fail "${MUNGEKEY}" unrecognized-option 2>err.$$ && grep -q "Option \"unrecognized-option\" is unrecognized" err.$$ ' # Check if a single lone hyphen is handled. ## test_expect_success 'mungekey lone hyphen option' ' test_must_fail "${MUNGEKEY}" - 2>err.$$ && grep -q "Option \"-\" is unrecognized" err.$$ ' # Check for a successful exit after writing usage info to stdout. ## for OPT_HELP in '-h' '--help'; do test_expect_success "mungekey ${OPT_HELP}" ' "${MUNGEKEY}" "${OPT_HELP}" >out.$$ && grep -q "^Usage:" out.$$ ' done # Check for a successful exit after writing license info to stdout. ## for OPT_LICENSE in '-L' '--license'; do test_expect_success "mungekey ${OPT_LICENSE}" ' "${MUNGEKEY}" "${OPT_LICENSE}" >out.$$ && grep -q "GNU General Public License" out.$$ ' done # Check for a successful exit after writing version info to stdout. ## for OPT_VERSION in '-V' '--version'; do test_expect_success "mungekey ${OPT_VERSION}" ' "${MUNGEKEY}" "${OPT_VERSION}" >out.$$ && grep -q "^munge-[0-9.]*" out.$$ ' done # Check if the keyfile is created and properly permissioned. ## for OPT_CREATE in '-c' '--create'; do test_expect_success "mungekey ${OPT_CREATE}" ' local KEYFILE=key.$$ && rm -f "${KEYFILE}" && test ! -f "${KEYFILE}" && "${MUNGEKEY}" "${OPT_CREATE}" --keyfile="${KEYFILE}" && test -f "${KEYFILE}" && test "$(find ${KEYFILE} -perm 0600)" = "${KEYFILE}" ' done # Check if the keyfile is the appropriate size based on the number of bits # specified. ## for OPT_BITS in '-b' '--bits'; do test_expect_success "mungekey ${OPT_BITS}" ' local KEYFILE=key.$$ NUM_BITS=1000 FILE_SIZE && rm -f "${KEYFILE}" && test ! -f "${KEYFILE}" && "${MUNGEKEY}" --create --keyfile="${KEYFILE}" \ "${OPT_BITS}" "${NUM_BITS}" && test -f "${KEYFILE}" && FILE_SIZE=$(wc -c < "${KEYFILE}") && test "${FILE_SIZE}" -eq "$(( ${NUM_BITS} / 8 ))" ' done # Check if the number of bits is rounded-up to the next byte if it is not # evenly divisible by 8. NUM_BITS is set to 1 bit above the requested # NUM_BYTES. ## test_expect_success 'mungekey --bits rounding-up to next byte' ' local KEYFILE=key.$$ NUM_BYTES=128 NUM_BITS NUM_BYTES_ROUNDED FILE_SIZE && NUM_BITS=$(( (${NUM_BYTES} * 8) + 1 )) && rm -f "${KEYFILE}" && test ! -f "${KEYFILE}" && "${MUNGEKEY}" --create --keyfile="${KEYFILE}" --bits="${NUM_BITS}" && test -f "${KEYFILE}" && NUM_BYTES_ROUNDED=$(( (${NUM_BITS} + 7) / 8 )) && test "${NUM_BYTES_ROUNDED}" = "$(( ${NUM_BYTES} + 1 ))" && FILE_SIZE=$(wc -c < "${KEYFILE}") && test "${FILE_SIZE}" -eq "${NUM_BYTES_ROUNDED}" ' # Check if the default def is used when the number of bits is unspecified. ## test_expect_success 'mungekey --bits unspecified and using default' ' local KEYFILE=key.$$ DEFS NUM_BYTES NUM_BITS FILE_SIZE && DEFS="${MUNGE_SOURCE_DIR}/src/libcommon/munge_defs.h" && test -f "${DEFS}" && NUM_BYTES=$(awk "/MUNGE_KEY_LEN_DFL_BYTES/ { print \$3 }" "${DEFS}") && NUM_BITS=$(( ${NUM_BYTES} * 8 )) && rm -f "${KEYFILE}" && test ! -f "${KEYFILE}" && "${MUNGEKEY}" --create --keyfile="${KEYFILE}" && test -f "${KEYFILE}" && FILE_SIZE=$(wc -c < "${KEYFILE}") && test "${FILE_SIZE}" -eq "${NUM_BYTES}" ' # Check the boundary case for the minimum number of bits. ## test_expect_success 'mungekey --bits with minimum value' ' local KEYFILE=key.$$ DEFS NUM_BYTES NUM_BITS FILE_SIZE && DEFS="${MUNGE_SOURCE_DIR}/src/libcommon/munge_defs.h" && test -f "${DEFS}" && NUM_BYTES=$(awk "/MUNGE_KEY_LEN_MIN_BYTES/ { print \$3 }" "${DEFS}") && NUM_BITS=$(( ${NUM_BYTES} * 8 )) && rm -f "${KEYFILE}" && test ! -f "${KEYFILE}" && "${MUNGEKEY}" --create --keyfile="${KEYFILE}" --bits="${NUM_BITS}" && test -f "${KEYFILE}" && FILE_SIZE=$(wc -c < "${KEYFILE}") && test "${FILE_SIZE}" -eq "${NUM_BYTES}" ' # Check the boundary case for the maximum number of bits. ## test_expect_success 'mungekey --bits with maximum value' ' local KEYFILE=key.$$ DEFS NUM_BYTES NUM_BITS FILE_SIZE && DEFS="${MUNGE_SOURCE_DIR}/src/libcommon/munge_defs.h" && test -f "${DEFS}" && NUM_BYTES=$(awk "/MUNGE_KEY_LEN_MAX_BYTES/ { print \$3 }" "${DEFS}") && NUM_BITS=$(( ${NUM_BYTES} * 8 )) && rm -f "${KEYFILE}" && test ! -f "${KEYFILE}" && "${MUNGEKEY}" --create --keyfile="${KEYFILE}" --bits="${NUM_BITS}" && test -f "${KEYFILE}" && FILE_SIZE=$(wc -c < "${KEYFILE}") && test "${FILE_SIZE}" -eq "${NUM_BYTES}" ' # Check the boundary case below the minimum number of bits. ## test_expect_success 'mungekey --bits below minimum value' ' local DEFS NUM_BYTES NUM_BITS && DEFS="${MUNGE_SOURCE_DIR}/src/libcommon/munge_defs.h" && test -f "${DEFS}" && NUM_BYTES=$(awk "/MUNGE_KEY_LEN_MIN_BYTES/ { print \$3 }" "${DEFS}") && NUM_BITS=$(( (${NUM_BYTES} * 8) - 1 )) && test_must_fail "${MUNGEKEY}" --create --keyfile=key.$$ \ --bits="${NUM_BITS}" 2>err.$$ && grep -q "Option \"--bits\" has invalid value \"${NUM_BITS}\"" err.$$ ' # Check the boundary case above the maximum number of bits. ## test_expect_success 'mungekey --bits above maximum value' ' local DEFS NUM_BYTES NUM_BITS && DEFS="${MUNGE_SOURCE_DIR}/src/libcommon/munge_defs.h" && test -f "${DEFS}" && NUM_BYTES=$(awk "/MUNGE_KEY_LEN_MAX_BYTES/ { print \$3 }" "${DEFS}") && NUM_BITS=$(( (${NUM_BYTES} * 8) + 1 )) && test_must_fail "${MUNGEKEY}" --create --keyfile=key.$$ \ --bits="${NUM_BITS}" 2>err.$$ && grep -q "Option \"--bits\" has invalid value \"${NUM_BITS}\"" err.$$ ' # Check if the minimum number of bits is displayed in the error message. ## test_expect_success 'mungekey --bits error message with minimum value' ' local DEFS NUM_BYTES NUM_BITS && DEFS="${MUNGE_SOURCE_DIR}/src/libcommon/munge_defs.h" && test -f "${DEFS}" && NUM_BYTES=$(awk "/MUNGE_KEY_LEN_MIN_BYTES/ { print \$3 }" "${DEFS}") && NUM_BITS=$(( ${NUM_BYTES} * 8 )) && test_must_fail "${MUNGEKEY}" --create --keyfile=key.$$ --bits=1 2>err.$$ && grep -q -- "${NUM_BITS}-" err.$$ ' # Check if the maximum number of bits is displayed in the error message. ## test_expect_success 'mungekey --bits error message with maximum value' ' local DEFS NUM_BYTES NUM_BITS && DEFS="${MUNGE_SOURCE_DIR}/src/libcommon/munge_defs.h" && test -f "${DEFS}" && NUM_BYTES=$(awk "/MUNGE_KEY_LEN_MAX_BYTES/ { print \$3 }" "${DEFS}") && NUM_BITS=$(( ${NUM_BYTES} * 8 )) && test_must_fail "${MUNGEKEY}" --create --keyfile=key.$$ --bits=1 2>err.$$ && grep -q -- "-${NUM_BITS}" err.$$ ' # Check the case for zero number of bits. ## test_expect_success 'mungekey --bits with zero value' ' test_must_fail "${MUNGEKEY}" --create --keyfile=key.$$ --bits=0 2>err.$$ && grep -q "Option \"--bits\" has invalid value" err.$$ ' # Check the case for a negative number of bits. ## test_expect_success 'mungekey --bits with negative value' ' test_must_fail "${MUNGEKEY}" --create --keyfile=key.$$ --bits=-1 \ 2>err.$$ && grep -q "Option \"--bits\" has invalid value" err.$$ ' # Check if -b requires an argument and displays the expected short-option text # in the error message. ## test_expect_success 'mungekey -b without required value' ' test_must_fail "${MUNGEKEY}" --create --keyfile=key.$$ -b 2>err.$$ && grep -q "Option \"-b\" is missing a required argument" err.$$ ' # Check if --bits requires an argument and displays the expected long-option # text in the error message. ## test_expect_success 'mungekey --bits without required value' ' test_must_fail "${MUNGEKEY}" --create --keyfile=key.$$ --bits 2>err.$$ && grep -q "Option \"--bits\" is missing a required argument" err.$$ ' # Check if --force removes an existing keyfile. ## for OPT_FORCE in '-f' '--force'; do test_expect_success "mungekey ${OPT_FORCE}" ' local KEYFILE=key.$$ && rm -f "${KEYFILE}" && touch "${KEYFILE}" && test ! -s "${KEYFILE}" && "${MUNGEKEY}" --create --keyfile="${KEYFILE}" "${OPT_FORCE}" && test -s "${KEYFILE}" ' done # Check if the lack of --force preserves an existing and writable keyfile. ## test_expect_success 'mungekey without --force and with existing keyfile' ' local KEYFILE=key.$$ && rm -f "${KEYFILE}" && echo -n xyzzy-$$ > "${KEYFILE}" && chmod 0600 "${KEYFILE}" && test_must_fail "${MUNGEKEY}" --create --keyfile="${KEYFILE}" 2>err.$$ && grep -q "File exists" err.$$ && test "$(cat ${KEYFILE})" = xyzzy-$$ ' # Check if an alternate keyfile can be specified. # This is tested by practically every testcase in order to prevent writing a # key somewhere it shouldn't. ## for OPT_KEYFILE in '-k' '--keyfile'; do test_expect_success "mungekey ${OPT_KEYFILE}" ' local KEYFILE=key.$$ && rm -f "${KEYFILE}" && test ! -f "${KEYFILE}" && "${MUNGEKEY}" --create "${OPT_KEYFILE}" "${KEYFILE}" && test -f "${KEYFILE}" ' done # Check if -k requires an argument and displays the expected short-option text # in the error message. ## test_expect_success 'mungekey -k without required value' ' test_must_fail "${MUNGEKEY}" --create -k 2>err.$$ && grep -q "Option \"-k\" is missing a required argument" err.$$ ' # Check if --keyfile requires an argument and displays the expected long-option # text in the error message. ## test_expect_success 'mungekey --keyfile without required value' ' test_must_fail "${MUNGEKEY}" --create --keyfile 2>err.$$ && grep -q "Option \"--keyfile\" is missing a required argument" err.$$ ' # Check if an informational message is written to stderr when creating a key # with --verbose. ## for OPT_VERBOSE in '-v' '--verbose'; do test_expect_success "mungekey ${OPT_VERBOSE}" ' local KEYFILE=key.$$ && rm -f "${KEYFILE}" && test ! -f "${KEYFILE}" && "${MUNGEKEY}" --create --keyfile="${KEYFILE}" "${OPT_VERBOSE}" \ 2>err.$$ && test -f "${KEYFILE}" && grep -q "Created \"${KEYFILE}\"" err.$$ ' done # Check if the informational message written to stderr when creating a key # contains the number of bits used. ## test_expect_success 'mungekey --verbose number of bits' ' local KEYFILE=key.$$ NUM_BITS=1000 NUM_BITS_USED && rm -f "${KEYFILE}" && test ! -f "${KEYFILE}" && "${MUNGEKEY}" --create --keyfile="${KEYFILE}" --bits="${NUM_BITS}" \ --verbose 2>err.$$ && test -f "${KEYFILE}" && NUM_BITS_USED=$(sed -n -e "s/.* \([0-9][0-9]*\)-bit.*/\\1/p" err.$$) && test "${NUM_BITS_USED}" -eq "${NUM_BITS}" ' # Check that nothing is written to stdout or stderr when successfully creating # a key without --verbose (unless configured with --enable-debug). ## test_expect_success !DEBUG 'mungekey without --verbose' ' local KEYFILE=key.$$ && rm -f "${KEYFILE}" && test ! -f "${KEYFILE}" && "${MUNGEKEY}" --create --keyfile="${KEYFILE}" >out.$$ 2>err.$$ && test -f "${KEYFILE}" && test ! -s out.$$ && test ! -s err.$$ ' # With getopt_long(), long_ind is only set when a long-option is successfully # parsed. It must be re-initialized before each call to getopt_long(). # If not, it may erroneously refer to a previous option. # Check if long_ind is being re-initialized by specifying the --keyfile # long-option (and required argument) followed by the -b short-option # (with an invalid value to trigger the error case). If long_ind is not # being re-initialized, the error message will erroneously refer to the last # successfully-parsed long-option (i.e., --keyfile). ## test_expect_success 'mungekey long_ind re-initialized for getopt_long()' ' test_must_fail "${MUNGEKEY}" --create --keyfile=key.$$ -b 1 2>err.$$ && grep -q "Option \"-b\" has invalid value" err.$$ ' # Check if mungekey defaults to creating a key if no operation is specified. # The --keyfile option does not specify an operation, and it must be # specified here to prevent writing a key somewhere it shouldn't. ## test_expect_success 'mungekey defaults to create key' ' local KEYFILE=key.$$ && rm -f "${KEYFILE}" && test ! -f "${KEYFILE}" && "${MUNGEKEY}" --keyfile="${KEYFILE}" && test -f "${KEYFILE}" ' test_done munge-munge-0.5.15/t/0021-munged-valgrind.t000077500000000000000000000020331425467526100201360ustar00rootroot00000000000000#!/bin/sh test_description='Check munged for resource leaks' . "$(dirname "$0")/sharness.sh" if test_have_prereq EXPENSIVE; then :; else skip_all='skipping valgrind tests; long test not specified' test_done fi if test_have_prereq VALGRIND; then :; else skip_all='skipping valgrind tests; valgrind not installed' test_done fi test_expect_success 'start munged under valgrind' ' munged_setup && munged_create_key && munged_start_daemon t-exec="${VALGRIND_CMD}" ' test_expect_success 'encode credential' ' "${MUNGE}" --socket="${MUNGE_SOCKET}" cred.$$ ' test_expect_success 'decode credential' ' "${UNMUNGE}" --socket="${MUNGE_SOCKET}" /dev/null ' test_expect_success 'replay credential' ' test_must_fail "${UNMUNGE}" --socket="${MUNGE_SOCKET}" /dev/null ' test_expect_success 'stop munged' ' munged_stop_daemon ' test_expect_success 'check valgrind log for errors in munged' ' valgrind_check_log ' test_expect_success 'cleanup' ' munged_cleanup ' test_done munge-munge-0.5.15/t/0022-munge-valgrind.t000077500000000000000000000014511425467526100177760ustar00rootroot00000000000000#!/bin/sh test_description='Check munge for resource leaks' . "$(dirname "$0")/sharness.sh" if test_have_prereq EXPENSIVE; then :; else skip_all='skipping valgrind tests; long test not specified' test_done fi if test_have_prereq VALGRIND; then :; else skip_all='skipping valgrind tests; valgrind not installed' test_done fi test_expect_success 'start munged' ' munged_setup && munged_create_key && munged_start_daemon ' test_expect_success 'encode credential under valgrind' ' ${VALGRIND_CMD} "${MUNGE}" --socket="${MUNGE_SOCKET}" /dev/null ' test_expect_success 'stop munged' ' munged_stop_daemon ' test_expect_success 'check valgrind log for errors in munge' ' valgrind_check_log ' test_expect_success 'cleanup' ' munged_cleanup ' test_done munge-munge-0.5.15/t/0023-unmunge-valgrind.t000077500000000000000000000016301425467526100203410ustar00rootroot00000000000000#!/bin/sh test_description='Check unmunge for resource leaks' . "$(dirname "$0")/sharness.sh" if test_have_prereq EXPENSIVE; then :; else skip_all='skipping valgrind tests; long test not specified' test_done fi if test_have_prereq VALGRIND; then :; else skip_all='skipping valgrind tests; valgrind not installed' test_done fi test_expect_success 'start munged' ' munged_setup && munged_create_key && munged_start_daemon ' test_expect_success 'encode credential' ' "${MUNGE}" --socket="${MUNGE_SOCKET}" cred.$$ ' test_expect_success 'decode credential under valgrind' ' ${VALGRIND_CMD} "${UNMUNGE}" --socket="${MUNGE_SOCKET}" /dev/null ' test_expect_success 'stop munged' ' munged_stop_daemon ' test_expect_success 'check valgrind log for errors in unmunge' ' valgrind_check_log ' test_expect_success 'cleanup' ' munged_cleanup ' test_done munge-munge-0.5.15/t/0025-mungekey-valgrind.t000077500000000000000000000010721425467526100205110ustar00rootroot00000000000000#!/bin/sh test_description='Check mungekey for resource leaks' . "$(dirname "$0")/sharness.sh" if test_have_prereq EXPENSIVE; then :; else skip_all='skipping valgrind tests; long test not specified' test_done fi if test_have_prereq VALGRIND; then :; else skip_all='skipping valgrind tests; valgrind not installed' test_done fi test_expect_success 'create key under valgrind' ' munged_setup && munged_create_key t-exec="${VALGRIND_CMD}" ' test_expect_success 'check valgrind log for errors in mungekey' ' valgrind_check_log ' test_done munge-munge-0.5.15/t/0099-credential-decode.cred000066400000000000000000000002201425467526100210700ustar00rootroot00000000000000MUNGE:AwQFAADgFEPFKVLPoDVOF91tahXT1MkHMW6sXk7nrL+bQM+Ou4cQ8Jfc2fIGEqL8rftt7ZMvMQNZ/ik9Mf74oxSqwW/EKZvlowrUC8WPjS3udqHuSlM2r0rJg5Per6Zp+3lyKAo=: munge-munge-0.5.15/t/0099-credential-decode.key000066400000000000000000000000401425467526100207430ustar00rootroot000000000000000123456789ABCDEF0123456789ABCDEFmunge-munge-0.5.15/t/0099-credential-decode.out000066400000000000000000000003371425467526100207730ustar00rootroot00000000000000STATUS: 15 ENCODE_HOST: 127.0.1.1 ENCODE_TIME: 1634268043 TTL: 300 CIPHER: 4 MAC: 5 ZIP: 0 UID: 7607 GID: 7607 LENGTH: 5 xyzzy munge-munge-0.5.15/t/0099-credential-decode.t000077500000000000000000000024221425467526100204270ustar00rootroot00000000000000#!/bin/sh test_description='Check credential decode to verify crypto portability' . "$(dirname "$0")/sharness.sh" # Set up the environment. # test_expect_success 'setup' ' munged_setup ' # Start the daemon process with the known key. # Force the daemon to run since the key may have the wrong permissions. # test_expect_success 'start munged with known key' ' munged_start_daemon --force \ --key-file="${SHARNESS_TEST_SRCDIR}/0099-credential-decode.key" ' # Decode a known credential. # Expect an expired credential (STATUS=15). # test_expect_success 'decode known credential' ' test_expect_code 15 "${UNMUNGE}" --socket="${MUNGE_SOCKET}" \ --input="${SHARNESS_TEST_SRCDIR}/0099-credential-decode.cred" \ --numeric >out.$$ ' # Verify the decoded credential matches the expected output. # Remove the decode time since that is not stored in the known output. # test_expect_success 'verify expected output' ' grep -v DECODE_TIME: out.post.$$ && test_cmp "${SHARNESS_TEST_SRCDIR}/0099-credential-decode.out" out.post.$$ ' # Stop the daemon process. # test_expect_success 'stop munged' ' munged_stop_daemon ' # Perform any housekeeping to clean up afterwards. # test_expect_success 'cleanup' ' munged_cleanup ' test_done munge-munge-0.5.15/t/0100-munged-lock.t000077500000000000000000000146601425467526100172670ustar00rootroot00000000000000#!/bin/sh test_description='Check munged socket lock' . "$(dirname "$0")/sharness.sh" # Set up the environment for testing. # The location of the lockfile is derived from the name of the socket. ## test_expect_success 'setup' ' munged_setup && munged_create_key && MUNGE_LOCKFILE="${MUNGE_SOCKET}.lock" ' # The umask is cleared here to be able to later check if the lockfile has had # its permissions set properly. ## test_expect_success 'start munged with open umask' ' local MASK && MASK=$(umask) && umask 0 && munged_start_daemon && umask "${MASK}" ' # Check if the pidfile has been created, and if it contains the pid of an # active munged process. ## test_expect_success 'check pidfile after munged success' ' ps -p "$(cat "${MUNGE_PIDFILE}")" -ww | grep munged ' # Check if the lockfile has been created. ## test_expect_success 'check lockfile existence' ' test -e "${MUNGE_LOCKFILE}" ' # Check if the lockfile is a regular file. ## test_expect_success 'check lockfile type' ' test -f "${MUNGE_LOCKFILE}" ' # Check if the lockfile has the expected permissions for a write-lock. ## test_expect_success 'check lockfile permissions' ' test "$(find ${MUNGE_LOCKFILE} -perm 0200)" = "${MUNGE_LOCKFILE}" ' # Try starting a new munged process using a socket that is already in use. # The lockfile should prevent this. ## test_expect_success 'start munged with in-use socket' ' test_must_fail munged_start_daemon t-keep-process && egrep "Error:.* Failed to lock \"${MUNGE_LOCKFILE}\"" "${MUNGE_LOGFILE}" ' # Check if the pidfile still contains the pid of an active munged process. # This tests whether the pidfile was corrupted by the preceding attempt # to start a new munged process using a socket that was already in use. ## test_expect_success 'check pidfile after munged failure' ' ps -p "$(cat "${MUNGE_PIDFILE}")" -ww | grep munged ' # Stop munged using the --stop option which derives the daemon's pid from # the lockfile. # Check that it responded to SIGTERM indicating it cleaned up before exiting. # A successful cleanup is necessary for the subsequent check for lockfile # removal. ## test_expect_success 'stop munged using lockfile-derived pid' ' munged_stop_daemon 2>&1 | grep "Terminated daemon" ' # Check if the lockfile was removed when munged shut down. ## test_expect_success 'check lockfile removal' ' test "x${MUNGE_LOCKFILE}" != x && test ! -f "${MUNGE_LOCKFILE}" ' # Check if munged will honor a supposed lockfile with read permissions. ## test_expect_success 'start munged with 0600 bogus lockfile' ' rm -f "${MUNGE_LOCKFILE}" && touch "${MUNGE_LOCKFILE}" && chmod 0600 "${MUNGE_LOCKFILE}" && test_must_fail munged_start_daemon && egrep "Error:.* \"${MUNGE_LOCKFILE}\" .* permissions for write by user" \ "${MUNGE_LOGFILE}" ' # Check if munged will honor a supposed lockfile with write permissions for # group and other. ## test_expect_success 'start munged with 0222 bogus lockfile' ' rm -f "${MUNGE_LOCKFILE}" && touch "${MUNGE_LOCKFILE}" && chmod 0222 "${MUNGE_LOCKFILE}" && test_must_fail munged_start_daemon && egrep "Error:.* \"${MUNGE_LOCKFILE}\" .* permissions for write by user" \ "${MUNGE_LOGFILE}" ' # Create a bogus non-empty "lockfile" here to be able to later check if munged # has truncated it. ## test_expect_success 'start munged with inactive non-zero-length lockfile' ' rm -f "${MUNGE_LOCKFILE}" && echo "$$" > "${MUNGE_LOCKFILE}" && chmod 0200 "${MUNGE_LOCKFILE}" && test -s "${MUNGE_LOCKFILE}" && munged_start_daemon ' # Check if the lockfile gets truncated. ## test_expect_success 'check for lockfile truncation after successful start' ' test -f "${MUNGE_LOCKFILE}" && test ! -s "${MUNGE_LOCKFILE}" ' # Kill munged to prevent cleanup in preparation for a later test to check if # munged can recover from a dead socket and lockfile. ## test_expect_success 'stop munged using sigkill to prevent cleanup' ' local PID && PID=$(cat "${MUNGE_PIDFILE}") && ps -p "${PID}" -ww | grep munged && while kill -s KILL "${PID}" 2>/dev/null; do :; done && ! ps -p "${PID}" >/dev/null ' # Check for the leftover socket since munged was prevented from cleaning up. ## test_expect_success 'check for leftover socket from unclean shutdown' ' test -S "${MUNGE_SOCKET}" ' # Check for the leftover lockfile since munged was prevented from cleaning up. ## test_expect_success 'check for leftover lockfile from unclean shutdown' ' test -f "${MUNGE_LOCKFILE}" ' # Check for the leftover pidfile since munged was prevented from cleaning up. ## test_expect_success 'check for leftover pidfile from unclean shutdown' ' test -f "${MUNGE_PIDFILE}" ' # Check if munged can recover from an unclean shutdown. While the socket and # lockfile still exist, the advisory lock will have been automatically # dropped when the previous munged died. # On Debian 3.1 (Linux 2.4.27-3-386), the advisory lock seems to stay held for # a few seconds after the process has terminated. Therefore, make a few # attempts to give the old lock a chance to clear before admitting defeat. ## test_expect_success 'start munged with leftover socket from unclean shutdown' ' retry 5 "munged_start_daemon" ' # Stop the munged that was started for the preceding test. # Check that it responded to SIGTERM indicating it cleaned up before exiting. # A successful cleanup is necessary for the subsequent check for lockfile # removal. ## test_expect_success 'stop munged' ' munged_stop_daemon 2>&1 | grep "Terminated daemon" ' # Check if the lockfile was removed when munged shut down. ## test_expect_success 'check lockfile removal again' ' test "x${MUNGE_LOCKFILE}" != x && test ! -f "${MUNGE_LOCKFILE}" ' # Check if root can stop a munged process started by a non-privileged user. # This tests the case where the lockfile owner (a non-privileged user) is # checked against the euid of the process performing the --stop option # (root). If root is unable to stop it, attempt cleanup as the # non-privileged user and return a failure status. ## test_expect_success SUDO 'stop unprivileged munged as root' ' munged_start_daemon && if munged_stop_daemon \ t-exec="sudo LD_LIBRARY_PATH=${LD_LIBRARY_PATH}"; then :; else munged_stop_daemon; false; fi ' # Clean up after a munged process that may not have terminated. ## test_expect_success 'cleanup' ' munged_cleanup ' test_done munge-munge-0.5.15/t/0101-munged-security-socket.t000077500000000000000000000166271425467526100215020ustar00rootroot00000000000000#!/bin/sh test_description='Check munged security of socket' . "$(dirname "$0")/sharness.sh" # Set up the environment for checking the socket. # MUNGE_SOCKETDIR is redefined to add a sub-directory for testing changes to # directory ownership and permissions. It is kept in TMPDIR since NFS can # cause problems for the lockfile (the location of which is derived from the # socket name), ## test_expect_success 'setup' ' MUNGE_SOCKETDIR="${TMPDIR:-"/tmp"}/munge-$$/socketdir-$$" && munged_setup && munged_create_key ' # Check the permissions on the socket dir. ## test_expect_success 'socket dir perms' ' test "$(find "${MUNGE_SOCKETDIR}" -type d -perm 1777)" = \ "${MUNGE_SOCKETDIR}" && munged_start_daemon && munged_stop_daemon ' # Check the file type and permissions on the socket. # MUNGE_SOCKET must be examined while munged is running since the socket is # removed when the daemon terminates. # Testing TYPE and PERM after munged terminates allows the daemon to be stopped # even if the tests fail. ## test_expect_success 'socket type and perms' ' local TYPE PERM && munged_start_daemon && TYPE=$(find "${MUNGE_SOCKET}" -type s) && PERM=$(find "${MUNGE_SOCKET}" -perm 0777) && munged_stop_daemon && test "${TYPE}" = "${MUNGE_SOCKET}" && test "${PERM}" = "${MUNGE_SOCKET}" ' # Check a socket dir that is owned by the EUID. ## test_expect_success 'socket dir owned by euid' ' local DIR_UID MY_EUID && DIR_UID=$(ls -d -l -n "${MUNGE_SOCKETDIR}" | awk "{ print \$3 }") && MY_EUID=$(id -u) && test "${DIR_UID}" = "${MY_EUID}" && munged_start_daemon && munged_stop_daemon ' # Create an alternate socket dir that can be chwon'd. # This dir is placed in a subdir of TMPDIR since chowning something as root can # fail if NFS is configured for squashed access. ## test_expect_success SUDO 'alt socket dir setup' ' ALT_SOCKETDIR="${TMPDIR:-"/tmp"}/munge-$$/alt-socketdir-$$" && mkdir -m 1777 -p "${ALT_SOCKETDIR}" && ALT_SOCKET="${ALT_SOCKETDIR}/munged.sock.$$" && test_set_prereq ALT ' # Check a socket dir that is owned by root. ## test_expect_success ALT,SUDO 'socket dir owned by root' ' sudo chown root "${ALT_SOCKETDIR}" && munged_start_daemon --socket="${ALT_SOCKET}" && munged_stop_daemon --socket="${ALT_SOCKET}" ' # Check for an error when the socket dir is not owned by the EUID or root. ## test_expect_success ALT,SUDO 'socket dir owned by other failure' ' test "$(id -u)" != "1" && sudo chown 1 "${ALT_SOCKETDIR}" && test_must_fail munged_start_daemon --socket="${ALT_SOCKET}" && egrep "Error:.* Socket.* invalid ownership of \"${ALT_SOCKETDIR}\"" \ "${MUNGE_LOGFILE}" ' # Check if the error can be overridden when the socket dir is not owned by the # EUID or root. ## test_expect_success ALT,SUDO 'socket dir owned by other override' ' test "$(id -u)" != "1" && sudo chown 1 "${ALT_SOCKETDIR}" && munged_start_daemon --socket="${ALT_SOCKET}" --force && munged_stop_daemon --socket="${ALT_SOCKET}" && egrep "Warning:.* Socket.* invalid ownership of \"${ALT_SOCKETDIR}\"" \ "${MUNGE_LOGFILE}" ' # Cleanup the alternate socket dir. ## test_expect_success ALT 'alt socket dir cleanup' ' rmdir "${ALT_SOCKETDIR}" && unset ALT_SOCKETDIR && unset ALT_SOCKET ' # Check if the socket dir can be writable by group (without the sticky bit set) # when a trusted group is specified that matches the directory's group. ## test_expect_success 'socket dir writable by trusted group' ' local GID && GID=$(ls -d -l -n "${MUNGE_SOCKETDIR}" | awk "{ print \$4 }") && chmod 0771 "${MUNGE_SOCKETDIR}" && munged_start_daemon --trusted-group="${GID}" && munged_stop_daemon && chmod 1777 "${MUNGE_SOCKETDIR}" ' # Check for an error when the socket dir is writable (without the sticky bit # set) by a group that does not match the specified trusted group. ## test_expect_success 'socket dir writable by untrusted group failure' ' local GID && GID=$(ls -d -l -n "${MUNGE_SOCKETDIR}" | awk "{ print \$4 }") && GID=$(( ${GID} + 1 )) && chmod 0771 "${MUNGE_SOCKETDIR}" && test_must_fail munged_start_daemon --trusted-group="${GID}" && chmod 1777 "${MUNGE_SOCKETDIR}" ' # Check for an error when the socket dir is writable by group without the # sticky bit set. ## test_expect_success 'socket dir writable by group failure' ' chmod 0771 "${MUNGE_SOCKETDIR}" && test_must_fail munged_start_daemon && chmod 1777 "${MUNGE_SOCKETDIR}" && egrep "Error:.* group-writable permissions without sticky bit set" \ "${MUNGE_LOGFILE}" ' # Check if the error can be overridden when the socket dir is writable by group # without the sticky bit set. ## test_expect_success 'socket dir writable by group override' ' chmod 0771 "${MUNGE_SOCKETDIR}" && munged_start_daemon --force && munged_stop_daemon && chmod 1777 "${MUNGE_SOCKETDIR}" && egrep "Warning:.* group-writable permissions without sticky bit set" \ "${MUNGE_LOGFILE}" ' # Check if the socket dir can be writable by group with the sticky bit set. ## test_expect_success 'socket dir writable by group with sticky bit' ' chmod 1771 "${MUNGE_SOCKETDIR}" && munged_start_daemon && munged_stop_daemon && chmod 1777 "${MUNGE_SOCKETDIR}" ' # Check for an error when the socket dir is writable by other without the # sticky bit set. ## test_expect_success 'socket dir writable by other failure' ' chmod 0717 "${MUNGE_SOCKETDIR}" && test_must_fail munged_start_daemon && chmod 1777 "${MUNGE_SOCKETDIR}" && egrep "Error:.* world-writable permissions without sticky bit set" \ "${MUNGE_LOGFILE}" ' # Check if the error can be overridden when the socket dir is writable by other # without the sticky bit set. ## test_expect_success 'socket dir writable by other override' ' chmod 0717 "${MUNGE_SOCKETDIR}" && munged_start_daemon --force && munged_stop_daemon && chmod 1777 "${MUNGE_SOCKETDIR}" && egrep "Warning:.* world-writable permissions without sticky bit set" \ "${MUNGE_LOGFILE}" ' # Check if the socket dir can be writable by other with the sticky bit set. ## test_expect_success 'socket dir writable by other with sticky bit' ' chmod 1717 "${MUNGE_SOCKETDIR}" && munged_start_daemon && munged_stop_daemon && chmod 1777 "${MUNGE_SOCKETDIR}" ' # Check for an error when the socket dir does not have execute permissions # for all. ## test_expect_success 'socket dir inaccessible by all failure' ' chmod 0700 "${MUNGE_SOCKETDIR}" && test_must_fail munged_start_daemon && chmod 1777 "${MUNGE_SOCKETDIR}" && egrep "Error:.* Socket is inaccessible.* \"${MUNGE_SOCKETDIR}\"" \ "${MUNGE_LOGFILE}" ' # # Check if the error can be overridden when the socket dir does not have # execute permissions for all. ## test_expect_success 'socket dir inaccessible by all override' ' chmod 0700 "${MUNGE_SOCKETDIR}" && munged_start_daemon --force && munged_stop_daemon && chmod 1777 "${MUNGE_SOCKETDIR}" && egrep "Warning:.* Socket is inaccessible.* \"${MUNGE_SOCKETDIR}\"" \ "${MUNGE_LOGFILE}" ' # Clean up detritus from testing. This may include an errant munged process # that has not terminated. ## test_expect_success 'cleanup' ' rmdir "${MUNGE_SOCKETDIR}" && if rmdir "$(dirname "${MUNGE_SOCKETDIR}")" 2>/dev/null; then :; fi && munged_cleanup ' test_done munge-munge-0.5.15/t/0102-munged-security-keyfile.t000077500000000000000000000277021425467526100216370ustar00rootroot00000000000000#!/bin/sh test_description='Check munged security of keyfile' . "$(dirname "$0")/sharness.sh" # Set up the environment for checking the keyfile. ## test_expect_success 'setup' ' munged_setup && munged_create_key ' # Check a keyfile that is a regular file. ## test_expect_success 'keyfile regular file' ' test -f "${MUNGE_KEYFILE}" && munged_start_daemon && munged_stop_daemon ' # Check for an error when the keyfile is missing. ## test_expect_success 'keyfile missing failure' ' local MUNGE_KEYFILE && MUNGE_KEYFILE="${MUNGE_KEYDIR}/munged.key.$$.missing" && test_must_fail munged_start_daemon && egrep "Error:.* Failed to find keyfile.*: No such file" "${MUNGE_LOGFILE}" ' # Check for an error when the keyfile is not a regular file. # Using a directory for the non-regular-file seems the most portable solution. ## test_expect_success 'keyfile non-regular-file failure' ' local MUNGE_KEYFILE && MUNGE_KEYFILE="${MUNGE_KEYDIR}/munged.key.$$.non-regular-file" && rm -r -f "${MUNGE_KEYFILE}" && mkdir "${MUNGE_KEYFILE}" && test_must_fail munged_start_daemon && egrep "Error:.* Keyfile.* must be a regular file" "${MUNGE_LOGFILE}" && rmdir "${MUNGE_KEYFILE}" ' # Check that the error cannot be overridden when the keyfile is not a regular # file. ## test_expect_success 'keyfile non-regular-file override failure' ' local MUNGE_KEYFILE && MUNGE_KEYFILE="${MUNGE_KEYDIR}/munged.key.$$.non-regular-file" && rm -r -f "${MUNGE_KEYFILE}" && mkdir "${MUNGE_KEYFILE}" && test_must_fail munged_start_daemon --force && egrep "Error:.* Keyfile.* must be a regular file" "${MUNGE_LOGFILE}" && rmdir "${MUNGE_KEYFILE}" ' # Check for an error when the keyfile is a symlink to a regular file. ## test_expect_success 'keyfile symlink to regular file failure' ' local MY_KEYFILE && MY_KEYFILE="${MUNGE_KEYFILE}.symlink" && ln -s -f "${MUNGE_KEYFILE}" "${MY_KEYFILE}" && test_must_fail munged_start_daemon --key-file="${MY_KEYFILE}" && egrep "Error:.* Keyfile.* a symbolic link" "${MUNGE_LOGFILE}" ' # Check if the error can be overridden when the keyfile is a symlink to a # regular file. ## test_expect_success 'keyfile symlink to regular file override' ' local MY_KEYFILE && MY_KEYFILE="${MUNGE_KEYFILE}.symlink" && ln -s -f "${MUNGE_KEYFILE}" "${MY_KEYFILE}" && munged_start_daemon --key-file="${MY_KEYFILE}" --force && munged_stop_daemon && egrep "Warning:.* Keyfile.* a symbolic link" "${MUNGE_LOGFILE}" ' # Check a keyfile owned by the EUID. ## test_expect_success 'keyfile owned by euid' ' local KEY_UID MY_EUID && KEY_UID=$(ls -l -n "${MUNGE_KEYFILE}" | awk "{ print \$3 }") && MY_EUID=$(id -u) && test "${KEY_UID}" = "${MY_EUID}" && munged_start_daemon && munged_stop_daemon ' # Check if the keyfile can be readable by a group that matches the specified # trusted group. ## test_expect_failure 'keyfile readable by trusted group' ' local GID && GID=$(ls -l -n "${MUNGE_KEYFILE}" | awk "{ print \$4 }") && chmod 0640 "${MUNGE_KEYFILE}" && munged_start_daemon --trusted-group="${GID}" && munged_stop_daemon ' # Check for an error when the keyfile is readable by a group that does not # match the specified trusted group. ## test_expect_success 'keyfile readable by untrusted group failure' ' local GID && GID=$(ls -l -n "${MUNGE_KEYFILE}" | awk "{ print \$4 }") && GID=$(( ${GID} + 1 )) && chmod 0640 "${MUNGE_KEYFILE}" && test_must_fail munged_start_daemon --trusted-group="${GID}" ' # Check if the keyfile can be writable by a group that matches the specified # trusted group. ## test_expect_failure 'keyfile writable by trusted group' ' local GID && GID=$(ls -l -n "${MUNGE_KEYFILE}" | awk "{ print \$4 }") && chmod 0620 "${MUNGE_KEYFILE}" && munged_start_daemon --trusted-group="${GID}" && munged_stop_daemon ' # Check for an error when the keyfile is writable by a group that does not # match the specified trusted group. ## test_expect_success 'keyfile writable by untrusted group failure' ' local GID && GID=$(ls -l -n "${MUNGE_KEYFILE}" | awk "{ print \$4 }") && GID=$(( ${GID} + 1 )) && chmod 0620 "${MUNGE_KEYFILE}" && test_must_fail munged_start_daemon --trusted-group="${GID}" ' # Check for an error when the keyfile is readable by group. ## test_expect_success 'keyfile readable by group failure' ' chmod 0640 "${MUNGE_KEYFILE}" && test_must_fail munged_start_daemon && egrep "Error:.* Keyfile.* readable.* by.* group" "${MUNGE_LOGFILE}" ' # Check if the error can be overridden when the keyfile is readable by group. ## test_expect_success 'keyfile readable by group override' ' chmod 0640 "${MUNGE_KEYFILE}" && munged_start_daemon --force && munged_stop_daemon && egrep "Warning:.* Keyfile.* readable.* by.* group" "${MUNGE_LOGFILE}" ' # Check for an error when the keyfile is writable by group. ## test_expect_success 'keyfile writable by group failure' ' chmod 0620 "${MUNGE_KEYFILE}" && test_must_fail munged_start_daemon && egrep "Error:.* Keyfile.* writable.* by.* group" "${MUNGE_LOGFILE}" ' # Check if the error can be overridden when the keyfile is writable by group. ## test_expect_success 'keyfile writable by group override' ' chmod 0620 "${MUNGE_KEYFILE}" && munged_start_daemon --force && munged_stop_daemon && egrep "Warning:.* Keyfile.* writable.* by.* group" "${MUNGE_LOGFILE}" ' # Check for an error when the keyfile is readable by other. ## test_expect_success 'keyfile readable by other failure' ' chmod 0604 "${MUNGE_KEYFILE}" && test_must_fail munged_start_daemon && egrep "Error:.* Keyfile.* readable.* by.* other" "${MUNGE_LOGFILE}" ' # Check if the error can be overridden when the keyfile is readable by other. ## test_expect_success 'keyfile readable by other override' ' chmod 0604 "${MUNGE_KEYFILE}" && munged_start_daemon --force && munged_stop_daemon && egrep "Warning:.* Keyfile.* readable.* by.* other" "${MUNGE_LOGFILE}" ' # Check for an error when the keyfile is writable by other. ## test_expect_success 'keyfile writable by other failure' ' chmod 0602 "${MUNGE_KEYFILE}" && test_must_fail munged_start_daemon && egrep "Error:.* Keyfile.* writable.* by.* other" "${MUNGE_LOGFILE}" ' # Check if the error can be overridden when the keyfile is writable by other. ## test_expect_success 'keyfile writable by other override' ' chmod 0602 "${MUNGE_KEYFILE}" && munged_start_daemon --force && munged_stop_daemon && egrep "Warning:.* Keyfile.* writable.* by.* other" "${MUNGE_LOGFILE}" ' # Check a keyfile with secure permissions. # Note that this restores keyfile secure permissions for the remaining checks. ## test_expect_success 'keyfile secure perms' ' chmod 0600 "${MUNGE_KEYFILE}" && munged_start_daemon && munged_stop_daemon ' # Check a keyfile dir that is owned by the EUID. ## test_expect_success 'keyfile dir owned by euid' ' local DIR_UID MY_EUID && DIR_UID=$(ls -d -l -n "${MUNGE_KEYDIR}" | awk "{ print \$3 }") && MY_EUID=$(id -u) && test "${DIR_UID}" = "${MY_EUID}" && munged_start_daemon && munged_stop_daemon ' # Create an alternate keyfile dir that can be chown'd. # This dir is placed in a subdir of TMPDIR since chowning something as root can # fail if NFS is configured for squashed access. ## test_expect_success SUDO 'alt keyfile dir setup' ' ALT_KEYDIR="${TMPDIR:-"/tmp"}/munge-$$/alt-etc-$$" && mkdir -m 0755 -p "${ALT_KEYDIR}" && ALT_KEYFILE="${ALT_KEYDIR}/munged.key.$$" && cp -p "${MUNGE_KEYFILE}" "${ALT_KEYFILE}" && test_set_prereq ALT ' # Check a keyfile dir that is owned by root. ## test_expect_success ALT,SUDO 'keyfile dir owned by root' ' sudo chown root "${ALT_KEYDIR}" && munged_start_daemon --key-file="${ALT_KEYFILE}" && munged_stop_daemon ' # Check for an error when the keyfile dir is not owned by the EUID or root. ## test_expect_success ALT,SUDO 'keyfile dir owned by other failure' ' test "$(id -u)" != "1" && sudo chown 1 "${ALT_KEYDIR}" && test_must_fail munged_start_daemon --key-file="${ALT_KEYFILE}" && egrep "Error:.* Keyfile.* invalid ownership of \"${ALT_KEYDIR}\"" \ "${MUNGE_LOGFILE}" ' # Check if the error can be overridden when the keyfile dir is not owned by # the EUID or root. ## test_expect_success ALT,SUDO 'keyfile dir owned by other override' ' test "$(id -u)" != "1" && sudo chown 1 "${ALT_KEYDIR}" && munged_start_daemon --key-file="${ALT_KEYFILE}" --force && munged_stop_daemon && egrep "Warning:.* Keyfile.* invalid ownership of \"${ALT_KEYDIR}\"" \ "${MUNGE_LOGFILE}" ' # Cleanup the alternate keyfile dir. ## test_expect_success ALT,SUDO 'alt keyfile dir cleanup' ' sudo rm -r -f "${ALT_KEYDIR}" && if rmdir "$(dirname "${ALT_KEYDIR}")" 2>/dev/null; then :; fi && unset ALT_KEYDIR && unset ALT_KEYFILE ' # Check if the keyfile dir can be writable (without the sticky bit) by a group # that matches the specified trusted group. ## test_expect_success 'keyfile dir writable by trusted group' ' local GID && GID=$(ls -d -l -n "${MUNGE_KEYDIR}" | awk "{ print \$4 }") && chmod 0770 "${MUNGE_KEYDIR}" && munged_start_daemon --trusted-group="${GID}" && munged_stop_daemon && chmod 0755 "${MUNGE_KEYDIR}" ' # Check for an error when the keyfile dir is writable (without the sticky bit) # by a group that does not match the specified trusted group. ## test_expect_success 'keyfile dir writable by untrusted group failure' ' local GID && GID=$(ls -d -l -n "${MUNGE_KEYDIR}" | awk "{ print \$4 }") && GID=$(( ${GID} + 1 )) && chmod 0770 "${MUNGE_KEYDIR}" && test_must_fail munged_start_daemon --trusted-group="${GID}" && chmod 0755 "${MUNGE_KEYDIR}" ' # Check for an error when the keyfile dir is writable by group without the # sticky bit set. ## test_expect_success 'keyfile dir writable by group failure' ' chmod 0770 "${MUNGE_KEYDIR}" && test_must_fail munged_start_daemon && chmod 0755 "${MUNGE_KEYDIR}" && egrep "Error:.* group-writable permissions without sticky bit set" \ "${MUNGE_LOGFILE}" ' # Check if the error can be overridden when the keyfile dir is writable by # group without the sticky bit set. ## test_expect_success 'keyfile dir writable by group override' ' chmod 0770 "${MUNGE_KEYDIR}" && munged_start_daemon --force && munged_stop_daemon && chmod 0755 "${MUNGE_KEYDIR}" && egrep "Warning:.* group-writable permissions without sticky bit set" \ "${MUNGE_LOGFILE}" ' # Check if the keyfile dir can be writable by group with the sticky bit set. ## test_expect_success 'keyfile dir writable by group with sticky bit' ' chmod 1770 "${MUNGE_KEYDIR}" && munged_start_daemon && munged_stop_daemon && chmod 0755 "${MUNGE_KEYDIR}" ' # Check for an error when the keyfile dir is writable by other without the # sticky bit set. ## test_expect_success 'keyfile dir writable by other failure' ' chmod 0707 "${MUNGE_KEYDIR}" && test_must_fail munged_start_daemon && chmod 0755 "${MUNGE_KEYDIR}" && egrep "Error:.* world-writable permissions without sticky bit set" \ "${MUNGE_LOGFILE}" ' # Check if the error can be overridden when the keyfile dir is writable by # other without the sticky bit set. ## test_expect_success 'keyfile dir writable by other override' ' chmod 0707 "${MUNGE_KEYDIR}" && munged_start_daemon --force && munged_stop_daemon && chmod 0755 "${MUNGE_KEYDIR}" && egrep "Warning:.* world-writable permissions without sticky bit set" \ "${MUNGE_LOGFILE}" ' # Check if the keyfile dir can be writable by other with the sticky bit set. ## test_expect_success 'keyfile dir writable by other with sticky bit' ' chmod 1707 "${MUNGE_KEYDIR}" && munged_start_daemon && munged_stop_daemon && chmod 0755 "${MUNGE_KEYDIR}" ' # Clean up after a munged process that may not have terminated. ## test_expect_success 'cleanup' ' munged_cleanup ' test_done munge-munge-0.5.15/t/0103-munged-security-logfile.t000077500000000000000000000312461425467526100216270ustar00rootroot00000000000000#!/bin/sh test_description='Check munged security of logfile' . "$(dirname "$0")/sharness.sh" # Set up the environment for checking the logfile. ## test_expect_success 'setup' ' munged_setup && munged_create_key ' # Check startup with an existing empty logfile. The same file (identified by # its inode number) should exist after the daemon terminates, but it should # no longer be empty. ## test_expect_success 'logfile regular file' ' local INODE0 INODE1 && rm -f "${MUNGE_LOGFILE}" && touch "${MUNGE_LOGFILE}" && INODE0=$(ls -i "${MUNGE_LOGFILE}" | awk "{ print \$1 }") && munged_start_daemon t-keep-logfile && munged_stop_daemon && INODE1=$(ls -i "${MUNGE_LOGFILE}" | awk "{ print \$1 }") && test "${INODE0}" -eq "${INODE1}" && test -s "${MUNGE_LOGFILE}" ' # Check for an error when the logfile is a symlink to a regular file. ## test_expect_success 'logfile symlink to regular file failure' ' local MY_LOGFILE && MY_LOGFILE="${MUNGE_LOGFILE}.symlink" && ln -s -f "${MUNGE_LOGFILE}" "${MY_LOGFILE}" && rm -f "${MUNGE_LOGFILE}" && touch "${MUNGE_LOGFILE}" && test_must_fail munged_start_daemon t-keep-logfile \ --log-file="${MY_LOGFILE}" 2>err.$$ && egrep "Error:.* Logfile.* should not be a symbolic link" err.$$ ' # Check if the error can be overridden when the logfile is a symlink to a # regular file. ## test_expect_success 'logfile symlink to regular file override' ' local MY_LOGFILE && MY_LOGFILE="${MUNGE_LOGFILE}.symlink" && ln -s -f "${MUNGE_LOGFILE}" "${MY_LOGFILE}" && rm -f "${MUNGE_LOGFILE}" && touch "${MUNGE_LOGFILE}" && munged_start_daemon t-keep-logfile --log-file="${MY_LOGFILE}" --force \ 2>err.$$ && munged_stop_daemon && egrep "Warning:.* Logfile.* should not be a symbolic link" err.$$ ' # Check startup without an existing logfile (by not specifying t-keep-logfile # so as to remove an existing logfile). A non-empty logfile should exist # after the daemon terminates. ## test_expect_success 'logfile missing' ' munged_start_daemon && munged_stop_daemon && test -s "${MUNGE_LOGFILE}" ' # Check for an error when the logfile is a symlink to a non-existent file # (by not specifying t-keep-logfile so as to remove an existing logfile). ## test_expect_success 'logfile symlink to missing file failure' ' local MY_LOGFILE && MY_LOGFILE="${MUNGE_LOGFILE}.symlink" && ln -s -f "${MUNGE_LOGFILE}" "${MY_LOGFILE}" && test_must_fail munged_start_daemon --log-file="${MY_LOGFILE}" 2>err.$$ && egrep "Error:.* Logfile.* should not be a symbolic link" err.$$ ' # Check if the error can be overridden when the logfile is a symlink to a # non-existent file (by not specifying t-keep-logfile so as to remove an # existing logfile). A non-empty logfile should exist after the daemon # terminates. ## test_expect_success 'logfile symlink to missing file override' ' local MY_LOGFILE && MY_LOGFILE="${MUNGE_LOGFILE}.symlink" && ln -s -f "${MUNGE_LOGFILE}" "${MY_LOGFILE}" && munged_start_daemon --log-file="${MY_LOGFILE}" --force 2>err.$$ && munged_stop_daemon && egrep "Warning:.* Logfile.* should not be a symbolic link" err.$$ && test -s "${MUNGE_LOGFILE}" ' # Check for an error when the logfile is not a regular file. # Using a directory for the non-regular-file seems the most portable solution. ## test_expect_success 'logfile non-regular-file failure' ' local MUNGE_LOGFILE && MUNGE_LOGFILE="${MUNGE_LOGDIR}/munged.log.$$.non-regular-file" && rm -f "${MUNGE_LOGFILE}" && mkdir "${MUNGE_LOGFILE}" && test_must_fail munged_start_daemon t-keep-logfile 2>err.$$ && egrep "Error:.* Logfile.* must be a regular file" err.$$ && rmdir "${MUNGE_LOGFILE}" ' # Check that the error cannot be overridden when the logfile is not a regular # file. ## test_expect_success 'logfile non-regular-file override failure' ' local MUNGE_LOGFILE && MUNGE_LOGFILE="${MUNGE_LOGDIR}/munged.log.$$.non-regular-file" && rm -f "${MUNGE_LOGFILE}" && mkdir "${MUNGE_LOGFILE}" && test_must_fail munged_start_daemon t-keep-logfile --force 2>err.$$ && egrep "Error:.* Logfile.* must be a regular file" err.$$ && rmdir "${MUNGE_LOGFILE}" ' # Check for an error when the logfile is not writable by user. # Skip this test if running as root since the root user will not get the # expected EACCESS failure. ## test_expect_success !ROOT 'logfile not writable by user failure' ' rm -f "${MUNGE_LOGFILE}" && touch "${MUNGE_LOGFILE}" && chmod 0400 "${MUNGE_LOGFILE}" && test_must_fail munged_start_daemon t-keep-logfile 2>err.$$ && egrep "Error:.* Failed to open logfile.* Permission denied" err.$$ ' # Check if the logfile can be writable by a group that matches the specified # trusted group. ## test_expect_failure 'logfile writable by trusted group ' ' local GID && rm -f "${MUNGE_LOGFILE}" && touch "${MUNGE_LOGFILE}" && chmod 0620 "${MUNGE_LOGFILE}" && GID=$(ls -l -n "${MUNGE_LOGFILE}" | awk "{ print \$4 }") && munged_start_daemon t-keep-logfile --trusted-group="${GID}" && munged_stop_daemon ' # Check for an error when the logfile is writable by a group that does not # match the specified trusted group. ## test_expect_success 'logfile writable by untrusted group failure' ' local GID && rm -f "${MUNGE_LOGFILE}" && touch "${MUNGE_LOGFILE}" && chmod 0620 "${MUNGE_LOGFILE}" && GID=$(ls -l -n "${MUNGE_LOGFILE}" | awk "{ print \$4 }") && GID=$(( ${GID} + 1 )) && test_must_fail munged_start_daemon t-keep-logfile --trusted-group="${GID}" ' # Check for an error when the logfile is writable by group. ## test_expect_success 'logfile writable by group failure' ' rm -f "${MUNGE_LOGFILE}" && touch "${MUNGE_LOGFILE}" && chmod 0620 "${MUNGE_LOGFILE}" && test_must_fail munged_start_daemon t-keep-logfile 2>err.$$ && egrep "Error:.* Logfile.* writable.* by.* group" err.$$ ' # Check if the error can be overridden when the logfile is writable by group. ## test_expect_success 'logfile writable by group override' ' rm -f "${MUNGE_LOGFILE}" && touch "${MUNGE_LOGFILE}" && chmod 0620 "${MUNGE_LOGFILE}" && munged_start_daemon t-keep-logfile --force 2>err.$$ && munged_stop_daemon && egrep "Warning:.* Logfile.* writable.* by.* group" err.$$ ' # Check for an error when the logfile is writable by other. ## test_expect_success 'logfile writable by other failure' ' rm -f "${MUNGE_LOGFILE}" && touch "${MUNGE_LOGFILE}" && chmod 0602 "${MUNGE_LOGFILE}" && test_must_fail munged_start_daemon t-keep-logfile 2>err.$$ && egrep "Error:.* Logfile.* writable.* by.* other" err.$$ ' # Check if the error can be overridden when the logfile is writable by other. ## test_expect_success 'logfile writable by other override' ' rm -f "${MUNGE_LOGFILE}" && touch "${MUNGE_LOGFILE}" && chmod 0602 "${MUNGE_LOGFILE}" && munged_start_daemon t-keep-logfile --force 2>err.$$ && munged_stop_daemon && egrep "Warning:.* Logfile.* writable.* by.* other" err.$$ ' # Check if the logfile can be readable by all. ## test_expect_success 'logfile readable by all' ' rm -f "${MUNGE_LOGFILE}" && touch "${MUNGE_LOGFILE}" && chmod 0644 "${MUNGE_LOGFILE}" && munged_start_daemon t-keep-logfile && munged_stop_daemon ' # Check a logfile dir that is owned by the EUID. ## test_expect_success 'logfile dir owned by euid' ' local DIR_UID MY_EUID && DIR_UID=$(ls -d -l -n "${MUNGE_LOGDIR}" | awk "{ print \$3 }") && MY_EUID=$(id -u) && test "${DIR_UID}" = "${MY_EUID}" && munged_start_daemon && munged_stop_daemon ' # Create an alternate logfile dir that can be chown'd. # This dir is placed in a subdir of TMPDIR since chowning something as root can # fail if NFS is configured for squashed access. ## test_expect_success SUDO 'alt logfile dir setup' ' ALT_LOGDIR="${TMPDIR:-"/tmp"}/munge-$$/alt-log-$$" && mkdir -m 0755 -p "${ALT_LOGDIR}" && ALT_LOGFILE="${ALT_LOGDIR}/munged.log.$$" && touch "${ALT_LOGFILE}" && test_set_prereq ALT ' # Check a logfile dir that is owned by root. ## test_expect_success ALT,SUDO 'logfile dir owned by root' ' sudo chown root "${ALT_LOGDIR}" && > "${ALT_LOGFILE}" && munged_start_daemon --log-file="${ALT_LOGFILE}" && munged_stop_daemon ' # Check for an error when the logfile dir is not owned by the EUID or root. ## test_expect_success ALT,SUDO 'logfile dir owned by other failure' ' test "$(id -u)" != "1" && sudo chown 1 "${ALT_LOGDIR}" && > "${ALT_LOGFILE}" && test_must_fail munged_start_daemon --log-file="${ALT_LOGFILE}" 2>err.$$ && egrep "Error:.* Logfile.* invalid ownership of \"${ALT_LOGDIR}\"" err.$$ ' # Check if the error can be overridden when the logfile dir is not owned by # the EUID or root. ## test_expect_success ALT,SUDO 'logfile dir owned by other override' ' test "$(id -u)" != "1" && sudo chown 1 "${ALT_LOGDIR}" && > "${ALT_LOGFILE}" && munged_start_daemon --log-file="${ALT_LOGFILE}" --force 2>err.$$ && munged_stop_daemon && egrep "Warning:.* Logfile.* invalid ownership of \"${ALT_LOGDIR}\"" err.$$ ' # Cleanup the alternate logfile dir. ## test_expect_success ALT,SUDO 'alt logfile dir cleanup' ' sudo rm -r -f "${ALT_LOGDIR}" && if rmdir "$(dirname "${ALT_LOGDIR}")" 2>/dev/null; then :; fi && unset ALT_LOGDIR && unset ALT_LOGFILE ' # Check if the logfile dir can be writable (without the sticky bit) by a group # that matches the specified trusted group. ## test_expect_success 'logfile dir writable by trusted group ' ' local GID && GID=$(ls -d -l -n "${MUNGE_LOGDIR}" | awk "{ print \$4 }") && chmod 0770 "${MUNGE_LOGDIR}" && munged_start_daemon --trusted-group="${GID}" && munged_stop_daemon && chmod 0755 "${MUNGE_LOGDIR}" ' # Check if the logfile dir can be writable (without the sticky bit) by a group # that does not match the specified trusted group. # Group-writable permissions are allowed on the logfile dir (see Issue #31). ## test_expect_success 'logfile dir writable by untrusted group failure' ' local GID && GID=$(ls -d -l -n "${MUNGE_LOGDIR}" | awk "{ print \$4 }") && GID=$(( ${GID} + 1 )) && chmod 0770 "${MUNGE_LOGDIR}" && munged_start_daemon --trusted-group="${GID}" && munged_stop_daemon && chmod 0755 "${MUNGE_LOGDIR}" ' # Check if the logfile dir can be writable by group without the sticky bit set. # Group-writable permissions are allowed on the logfile dir (see Issue #31). ## test_expect_success 'logfile dir writable by group' ' chmod 0770 "${MUNGE_LOGDIR}" && munged_start_daemon && munged_stop_daemon && chmod 0755 "${MUNGE_LOGDIR}" ' # Check if the logfile dir can be writable by group with the sticky bit set. ## test_expect_success 'logfile dir writable by group with sticky bit' ' chmod 1770 "${MUNGE_LOGDIR}" && munged_start_daemon && munged_stop_daemon && chmod 0755 "${MUNGE_LOGDIR}" ' # Check for an error when the logfile dir is writable by other without the # sticky bit set. ## test_expect_success 'logfile dir writable by other failure' ' chmod 0707 "${MUNGE_LOGDIR}" && test_must_fail munged_start_daemon 2>err.$$ && chmod 0755 "${MUNGE_LOGDIR}" && egrep "Error:.* world-writable permissions without sticky bit set" err.$$ ' # Check if the error can be overridden when the logfile dir is writable by # other without the sticky bit set. ## test_expect_success 'logfile dir writable by other override' ' chmod 0707 "${MUNGE_LOGDIR}" && munged_start_daemon --force 2>err.$$ && munged_stop_daemon && chmod 0755 "${MUNGE_LOGDIR}" && egrep "Warning:.* world-writable permissions without sticky bit set" err.$$ ' # Check if the logfile dir can be writable by other with the sticky bit set. ## test_expect_success 'logfile dir writable by other with sticky bit' ' chmod 1707 "${MUNGE_LOGDIR}" && munged_start_daemon && munged_stop_daemon && chmod 0755 "${MUNGE_LOGDIR}" ' # Check for a regression of a duplicate error message being written to stderr. # To generate an error, test for the logfile being writable by other since this # will not be affected by root privileges. # ## test_expect_success 'logfile failure writes single message to stderr' ' local ERR NUM && rm -f "${MUNGE_LOGFILE}" && touch "${MUNGE_LOGFILE}" && chmod 0602 "${MUNGE_LOGFILE}" && test_must_fail munged_start_daemon t-keep-logfile 2>err.$$ && cat err.$$ && ERR=$(sed -n -e "s/.*Error: //p" err.$$ | sort | uniq -c | sort -n -r) && NUM=$(echo "${ERR}" | awk "{ print \$1; exit }") && test "${NUM}" -eq 1 2>/dev/null ' # Clean up after a munged process that may not have terminated. ## test_expect_success 'cleanup' ' munged_cleanup ' test_done munge-munge-0.5.15/t/0104-munged-security-pidfile.t000077500000000000000000000024221425467526100216150ustar00rootroot00000000000000#!/bin/sh test_description='Check munged security of pidfile' . "$(dirname "$0")/sharness.sh" # Set up the environment for checking the pidfile. ## test_expect_success 'setup' ' munged_setup && munged_create_key ' ## # FIXME # munged.c:write_pidfile # Is an absolute path required? ## # pidfile with absolute path # pidfile with relative path failure # pidfile dir owned by root # pidfile dir owned by euid # pidfile dir owned by other failure # pidfile dir owned by other override # pidfile dir writable by trusted group # pidfile dir writable by untrusted group failure # pidfile dir writable by group failure # pidfile dir writable by group override # pidfile dir writable by group with sticky bit # pidfile dir writable by other failure # pidfile dir writable by other override # pidfile dir writable by other with sticky bit # pidfile removal of previous file # pidfile contains munged pid (grep pid from logfile) # pidfile failure to open # pidfile failure to write # pidfile 0644 perms (without trusted group) (test w/ 0 umask) # pidfile 0664 perms with trusted group (test w/ 0 umask) ## test_expect_failure 'finish writing tests' ' false ' # Clean up after a munged process that may not have terminated. ## test_expect_success 'cleanup' ' munged_cleanup ' test_done munge-munge-0.5.15/t/0105-munged-security-seedfile.t000077500000000000000000000032121425467526100217600ustar00rootroot00000000000000#!/bin/sh test_description='Check munged security of seedfile' . "$(dirname "$0")/sharness.sh" # Set up the environment for checking the seedfile. ## test_expect_success 'setup' ' munged_setup && munged_create_key ' ## # FIXME # random.c:_random_read_entropy_from_file,_random_read_seed # Is an absolute path required? ## # seedfile regular file # seedfile missing # seedfile ignored when symlink # seedfile ignored when open fails # seedfile ignored when not a file # seedfile ignored when not owned by euid # seedfile readable by trusted group # seedfile ignored when readable by untrusted group # seedfile writable by trusted group # seedfile ignored when writable by untrusted group # seedfile ignored when readable by group # seedfile ignored when writable by group # seedfile ignored when readable by other # seedfile ignored when writable by other # seedfile dir owned by root # seedfile dir owned by euid # seedfile dir owned by other failure # seedfile dir owned by other override # seedfile dir writable by trusted group # seedfile dir writable by untrusted group failure # seedfile dir writable by group failure # seedfile dir writable by group override # seedfile dir writable by group with sticky bit # seedfile dir writable by other failure # seedfile dir writable by other override # seedfile dir writable by other with sticky bit # seedfile 0600 perms (without trusted group) (test w/ 0 umask) # seedfile 0660 perms with trusted group (test w/ 0 umask) ## test_expect_failure 'finish writing tests' ' false ' # Clean up after a munged process that may not have terminated. ## test_expect_success 'cleanup' ' munged_cleanup ' test_done munge-munge-0.5.15/t/0110-munged-origin-addr.t000077500000000000000000000133301425467526100205300ustar00rootroot00000000000000#!/bin/sh test_description='Check munged --origin' . "$(dirname "$0")/sharness.sh" # Set up the test environment. ## test_expect_success 'setup' ' munged_setup && munged_create_key ' # Check if the command-line option is documented in the help text. ## test_expect_success 'munged --origin help' ' "${MUNGED}" --help >out.$$ && grep " --origin=" out.$$ ' # Check for an error when an invalid origin address is specified. ## test_expect_success 'munged --origin failure' ' test_must_fail munged_start_daemon --origin=invalid.$$ ' # Check if the error can be overridden when an invalid origin address is # specified. ## test_expect_success 'munged --origin override' ' munged_start_daemon --origin=invalid.$$ --force && munged_stop_daemon ' # Check if the origin address is set to the null address when address lookup # fails and the error is overridden. ## test_expect_success 'munged --origin null address' ' munged_start_daemon --origin=invalid.$$ --force && munged_stop_daemon && egrep "Set origin address to 0\.0\.0\.0\>" "${MUNGE_LOGFILE}" ' # Check if the origin address is set to the null address in the credential # metadata when address lookup fails and the error is overridden. ## test_expect_success 'munged --origin null address metadata' ' munged_start_daemon --origin=invalid.$$ --force && "${MUNGE}" --socket="${MUNGE_SOCKET}" --no-input --output=cred.$$ && "${UNMUNGE}" --socket="${MUNGE_SOCKET}" --input=cred.$$ \ --metadata=meta.$$ --keys=ENCODE_HOST --numeric && munged_stop_daemon && egrep "^ENCODE_HOST:.* 0\.0\.0\.0\>" meta.$$ ' # Check if a warning message is logged to stderr when the origin address is set # to the null address. ## test_expect_success 'munged --origin null address warning' ' munged_start_daemon --origin=invalid.$$ --force 2>err.$$ && munged_stop_daemon && grep "Warning:.* origin set to null address" err.$$ ' # Check if the origin address can be set by specifying an IP address. ## test_expect_success 'munged --origin local IP address' ' rm -f ifname0.$$ && munged_start_daemon --origin=127.0.0.1 && munged_stop_daemon && egrep "Set origin address to 127\.0\.0\.1\>" "${MUNGE_LOGFILE}" ' # Check if the origin address is set to the appropriate IP address in the # credential metadata when specifying an IP address that (probably) matches # an address assigned to a local network interface. ## test_expect_success 'munged --origin local IP address metadata' ' munged_start_daemon --origin=127.0.0.1 && "${MUNGE}" --socket="${MUNGE_SOCKET}" --no-input --output=cred.$$ && "${UNMUNGE}" --socket="${MUNGE_SOCKET}" --input=cred.$$ \ --metadata=meta.$$ --keys=ENCODE_HOST --numeric && munged_stop_daemon && egrep "^ENCODE_HOST:.* 127\.0\.0\.1\>" meta.$$ ' # Check the log from the previous test for the network interface name # corresponding to the loopback address. # Set the IFNAME prereq if "ifname0.$$" contains a non-empty string. ## test_expect_success GETIFADDRS 'munged --origin interface name lookup' ' local ifname && sed -n -e "s/.*Set origin address.*(\([^)]*\)).*/\1/p" "${MUNGE_LOGFILE}" \ >ifname0.$$ && ifname=$(cat ifname0.$$) && test_debug "echo \"Loopback network interface name is [${ifname}]\"" && if test "x${ifname}" != x; then test_set_prereq IFNAME; fi ' # Check if the origin address can be set by specifying the loopback network # interface name. ## test_expect_success IFNAME 'munged --origin interface name' ' munged_start_daemon --origin="$(cat ifname0.$$)" && munged_stop_daemon && egrep "Set origin address to 127\.0\.0\.1\>" "${MUNGE_LOGFILE}" && sed -n -e "s/.*Set origin address.*(\([^)]*\)).*/\1/p" "${MUNGE_LOGFILE}" \ >ifname1.$$ && test_cmp ifname0.$$ ifname1.$$ ' # Check if the origin address is set to the appropriate IP address in the # credential metadata when specifying the loopback network interface name. ## test_expect_success IFNAME 'munged --origin interface name metadata' ' munged_start_daemon --origin="$(cat ifname0.$$)" && "${MUNGE}" --socket="${MUNGE_SOCKET}" --no-input --output=cred.$$ && "${UNMUNGE}" --socket="${MUNGE_SOCKET}" --input=cred.$$ \ --metadata=meta.$$ --keys=ENCODE_HOST --numeric && munged_stop_daemon && egrep "^ENCODE_HOST:.* 127\.0\.0\.1\>" meta.$$ ' # Check if the origin address can be set to a valid IP address that (probably) # does not match an address assigned to a local network interface. # Note: 192.0.0.0/24 is reserved for IETF Protocol Assignments (rfc6890) so the # IP address used here is presumably not likely to be assigned to a local # network interface. # Note: The egrep pattern uses the match-end-of-line operator ($) to ensure an # interface name does not follow the IP address. ## test_expect_success 'munged --origin non-interface IP address' ' munged_start_daemon --origin=192.0.0.255 && munged_stop_daemon && egrep "Set origin address to 192\.0\.0\.255$" "${MUNGE_LOGFILE}" ' # Check if the origin address is set to the appropriate IP address in the # credential metadata when specifying an IP address that (probably) does not # match an address assigned to a local network interface. ## test_expect_success 'munged --origin non-interface IP address metadata' ' munged_start_daemon --origin=192.0.0.255 && "${MUNGE}" --socket="${MUNGE_SOCKET}" --no-input --output=cred.$$ && "${UNMUNGE}" --socket="${MUNGE_SOCKET}" --input=cred.$$ \ --metadata=meta.$$ --keys=ENCODE_HOST --numeric && munged_stop_daemon && egrep "^ENCODE_HOST:.* 192\.0\.0\.255\>" meta.$$ ' # Clean up after a munged process that may not have terminated. ## test_expect_success 'cleanup' ' munged_cleanup ' test_done munge-munge-0.5.15/t/Makefile.am000066400000000000000000000021271425467526100163430ustar00rootroot00000000000000# MUNGE t/Makefile.am # # This file is part of the MUNGE Uid 'N' Gid Emporium (MUNGE). # For details, see . include $(top_srcdir)/Make-inc.mk TEST_EXTENSIONS = .t T_LOG_DRIVER = \ env AM_TAP_AWK='$(AWK)' $(SHELL) $(top_srcdir)/build-aux/tap-driver.sh TESTS = \ 0001-env-vars.t \ 0002-smiple.t \ 0010-basic.t \ 0011-munged-cmdline.t \ 0012-munge-cmdline.t \ 0013-unmunge-cmdline.t \ 0015-mungekey-cmdline.t \ 0021-munged-valgrind.t \ 0022-munge-valgrind.t \ 0023-unmunge-valgrind.t \ 0025-mungekey-valgrind.t \ 0099-credential-decode.t \ 0100-munged-lock.t \ 0101-munged-security-socket.t \ 0102-munged-security-keyfile.t \ 0103-munged-security-logfile.t \ 0104-munged-security-pidfile.t \ 0105-munged-security-seedfile.t \ 0110-munged-origin-addr.t \ # End of TESTS EXTRA_DIST = \ $(TESTS) \ 0000-sharness.t \ 0099-credential-decode.cred \ 0099-credential-decode.key \ 0099-credential-decode.out \ sharness.d \ sharness.sh \ test-terminal.perl \ valgrind.supp \ # End of EXTRA_DIST clean-local: -rm -rf test-results -rm -rf trash-directory.* munge-munge-0.5.15/t/sharness.d/000077500000000000000000000000001425467526100163555ustar00rootroot00000000000000munge-munge-0.5.15/t/sharness.d/01-directories.sh000066400000000000000000000023721425467526100214470ustar00rootroot00000000000000## # Search from directory [$1] on up to root, looking for the directory that # contains [$2]. # Output the resulting directory if a match is found. ## search_dirs() { local START_DIR=$1 local FIND_FILE=$2 ( cd "${START_DIR}" && while test "$(pwd)" != "/"; do test -e "${FIND_FILE}" && pwd && break cd .. done ) } ## # Set the top-level build directory. ## set_build_dir() { if test -z "${MUNGE_BUILD_DIR}"; then if test "x${builddir}" != x; then MUNGE_BUILD_DIR=${builddir} else MUNGE_BUILD_DIR=$(search_dirs "." "config.status") fi if test -z "${MUNGE_BUILD_DIR}"; then echo "ERROR: MUNGE has not been configured." exit 1 fi export MUNGE_BUILD_DIR fi } ## # Set the top-level source directory. ## set_source_dir() { local DIR if test -z "${MUNGE_SOURCE_DIR}"; then DIR=$(dirname "${SHARNESS_TEST_FILE}") MUNGE_SOURCE_DIR=$(search_dirs "${DIR}" "configure.ac") if test -z "${MUNGE_SOURCE_DIR}"; then echo "ERROR: Failed to locate source directory." exit 1 fi export MUNGE_SOURCE_DIR fi } set_build_dir set_source_dir munge-munge-0.5.15/t/sharness.d/02-executables.sh000066400000000000000000000012211425467526100214300ustar00rootroot00000000000000# Requires MUNGE_BUILD_DIR. ## # Set paths to executables. ## MUNGE="${MUNGE_BUILD_DIR}/src/munge/munge" UNMUNGE="${MUNGE_BUILD_DIR}/src/munge/unmunge" REMUNGE="${MUNGE_BUILD_DIR}/src/munge/remunge" MUNGED="${MUNGE_BUILD_DIR}/src/munged/munged" MUNGEKEY="${MUNGE_BUILD_DIR}/src/mungekey/mungekey" ## # Require executables to be built before tests can proceed. ## check_executables() { local EXEC for EXEC in "${MUNGE}" "${UNMUNGE}" "${REMUNGE}" "${MUNGED}" "${MUNGEKEY}" do if test ! -x "${EXEC}"; then echo "ERROR: MUNGE has not been built: ${EXEC} not found." exit 1 fi done } check_executables munge-munge-0.5.15/t/sharness.d/03-munged.sh000066400000000000000000000132331425467526100204120ustar00rootroot00000000000000# Requires MUNGED and MUNGEKEY. ## # Set up directory tree and shell variables for starting munged. # MUNGE_ROOT, MUNGE_SOCKETDIR, MUNGE_KEYDIR, MUNGE_LOGDIR, MUNGE_PIDDIR, and # MUNGE_SEEDDIR can be overridden by setting them beforehand. # MUNGE_SOCKET is placed in TMPDIR by default since NFS can cause problems for # the lockfile. Debian 3.1 returns an incorrect PID for the process holding # the lock across an NFS mount. FreeBSD cannot create a lockfile across an # NFS mount. ## munged_setup() { umask 0022 && : "${MUNGE_ROOT:="$(pwd)"}" && mkdir -m 0755 -p "${MUNGE_ROOT}" && : "${MUNGE_SOCKETDIR:="${TMPDIR:-"/tmp"}"}" && MUNGE_SOCKET="${MUNGE_SOCKETDIR}/munged.sock.$$" && mkdir -m 1777 -p "${MUNGE_SOCKETDIR}" && test_debug "echo MUNGE_SOCKET=\"${MUNGE_SOCKET}\"" && : "${MUNGE_KEYDIR:="${MUNGE_ROOT}/etc-$$"}" && MUNGE_KEYFILE="${MUNGE_KEYDIR}/munged.key.$$" && mkdir -m 0755 -p "${MUNGE_KEYDIR}" && test_debug "echo MUNGE_KEYFILE=\"${MUNGE_KEYFILE}\"" && : "${MUNGE_LOGDIR:="${MUNGE_ROOT}/log-$$"}" && MUNGE_LOGFILE="${MUNGE_LOGDIR}/munged.log.$$" && mkdir -m 0755 -p "${MUNGE_LOGDIR}" && test_debug "echo MUNGE_LOGFILE=\"${MUNGE_LOGFILE}\"" && : "${MUNGE_PIDDIR:="${MUNGE_ROOT}/run-$$"}" && MUNGE_PIDFILE="${MUNGE_PIDDIR}/munged.pid.$$" && mkdir -m 0755 -p "${MUNGE_PIDDIR}" && test_debug "echo MUNGE_PIDFILE=\"${MUNGE_PIDFILE}\"" && : "${MUNGE_SEEDDIR:="${MUNGE_ROOT}/lib-$$"}" && MUNGE_SEEDFILE="${MUNGE_SEEDDIR}/munged.seed.$$" && mkdir -m 0755 -p "${MUNGE_SEEDDIR}" && test_debug "echo MUNGE_SEEDFILE=\"${MUNGE_SEEDFILE}\"" } ## # Create the smallest-allowable key if one does not already exist. # The following leading args are recognized: # t-exec=ARG - use ARG to exec mungekey. # Remaining args will be appended to the mungekey command-line. ## munged_create_key() { local EXEC= && while true; do case $1 in t-exec=*) EXEC=$(echo "$1" | sed 's/^[^=]*=//');; *) break;; esac shift done && if test ! -r "${MUNGE_KEYFILE}"; then test_debug "echo ${EXEC} \"${MUNGEKEY}\" \ --create \ --keyfile=\"${MUNGE_KEYFILE}\" \ --bits=256 \ $*" && ${EXEC} "${MUNGEKEY}" \ --create \ --keyfile="${MUNGE_KEYFILE}" \ --bits=256 \ "$@" fi } ## # Start munged, removing an existing logfile or killing an errant munged # process (from a previous run) if needed. # The following leading args are recognized: # t-exec=ARG - use ARG to exec munged. # t-keep-logfile - do not remove logfile before starting munged. # t-keep-process - do not kill previous munged process. # Remaining args will be appended to the munged command-line. ## munged_start_daemon() { local EXEC= KEEP_LOGFILE= KEEP_PROCESS= && while true; do case $1 in t-exec=*) EXEC=$(echo "$1" | sed 's/^[^=]*=//');; t-keep-logfile) KEEP_LOGFILE=1;; t-keep-process) KEEP_PROCESS=1;; *) break;; esac shift done && if test "${KEEP_LOGFILE}" != 1; then rm -f "${MUNGE_LOGFILE}" fi && if test "${KEEP_PROCESS}" != 1; then munged_kill_daemon fi && test_debug "echo ${EXEC} \"${MUNGED}\" \ --socket=\"${MUNGE_SOCKET}\" \ --key-file=\"${MUNGE_KEYFILE}\" \ --log-file=\"${MUNGE_LOGFILE}\" \ --pid-file=\"${MUNGE_PIDFILE}\" \ --seed-file=\"${MUNGE_SEEDFILE}\" \ --group-update-time=-1 \ $*" && ${EXEC} "${MUNGED}" \ --socket="${MUNGE_SOCKET}" \ --key-file="${MUNGE_KEYFILE}" \ --log-file="${MUNGE_LOGFILE}" \ --pid-file="${MUNGE_PIDFILE}" \ --seed-file="${MUNGE_SEEDFILE}" \ --group-update-time=-1 \ "$@" } ## # Stop munged. # The following leading args are recognized: # t-exec=ARG - use ARG to exec munged. # Remaining args will be appended to the munged command-line. ## munged_stop_daemon() { local EXEC= && while true; do case $1 in t-exec=*) EXEC=$(echo "$1" | sed 's/^[^=]*=//');; *) break;; esac shift done && test_debug "echo ${EXEC} \"${MUNGED}\" \ --socket=\"${MUNGE_SOCKET}\" \ --stop \ --verbose \ $*" && ${EXEC} "${MUNGED}" \ --socket="${MUNGE_SOCKET}" \ --stop \ --verbose \ "$@" } ## # Kill an errant munged process running in the background from a previous test. # This situation is most likely to occur if a munged test is expected to fail # and instead erroneously succeeds. # Only check for the pid named in ${MUNGE_PIDFILE} to avoid intefering with # munged processes belonging to other tests or system use. And check that # the named pid is a munged process and not one recycled by the system for # some other running process. # A SIGTERM is used here instead of "munged --stop" in case the latter has a # bug introduced that prevents cleanup from occurring. # A SIGKILL would prevent the munged process from cleaning up which could cause # other tests to inadvertently fail. ## munged_kill_daemon() { local PID PID=$(cat "${MUNGE_PIDFILE}" 2>/dev/null) if ps -p "${PID}" -ww 2>/dev/null | grep munged; then kill "${PID}" test_debug "echo \"Terminated errant munged pid ${PID}\"" fi } ## # Perform any housekeeping to clean up after munged. This should be called # at the end of any test script that starts a munged process. ## munged_cleanup() { munged_kill_daemon } munge-munge-0.5.15/t/sharness.d/05-retry.sh000066400000000000000000000007701425467526100203040ustar00rootroot00000000000000## # Retry the COMMAND up to COUNT times. # Return 0 on success, 1 on error, 2 on invalid COUNT. ## retry() { local COUNT="$1" local COMMAND="$2" local i=1 test "${COUNT}" -gt 0 2>/dev/null || return 2 while true; do test_debug 'echo "retry $i/${COUNT}: ${COMMAND}"' eval ${COMMAND} test "$?" -eq 0 && return 0 test "$i" -ge "${COUNT}" && return 1 i=$((i + 1)) sleep 1 done return 3 # not reached } munge-munge-0.5.15/t/sharness.d/10-debug.sh000066400000000000000000000003001425467526100202060ustar00rootroot00000000000000# Requires MUNGE_BUILD_DIR. ## # Is debug enabled? ## if egrep -q '^#define.*\.*1' \ "${MUNGE_BUILD_DIR}/config.h" >/dev/null 2>&1; then :; else test_set_prereq DEBUG fi munge-munge-0.5.15/t/sharness.d/10-getifaddrs.sh000066400000000000000000000003111425467526100212360ustar00rootroot00000000000000# Requires MUNGE_BUILD_DIR. ## # Got HAVE_GETIFADDRS? ## if egrep -q '^#define.*\.*1' \ "${MUNGE_BUILD_DIR}/config.h" >/dev/null 2>&1; then test_set_prereq GETIFADDRS fi munge-munge-0.5.15/t/sharness.d/10-root.sh000066400000000000000000000001511425467526100201070ustar00rootroot00000000000000## # Is the test being run by the root user? ## if test "$(id -u)" = 0; then test_set_prereq ROOT fi munge-munge-0.5.15/t/sharness.d/10-sudo.sh000066400000000000000000000005021425467526100200760ustar00rootroot00000000000000## # Is non-interactive sudo available? # Designate sudo-invoked commands as "expensive". Enable them with the # sharness "--long-tests" option. The EXPENSIVE prereq has not been set yet, # so check TEST_LONG instead. ## if test "x${TEST_LONG}" != x && sudo -n true >/dev/null 2>&1; then test_set_prereq SUDO fi munge-munge-0.5.15/t/sharness.d/10-valgrind.sh000066400000000000000000000030661425467526100207420ustar00rootroot00000000000000## # Is valgrind installed? ## if valgrind --version >/dev/null 2>&1; then test_set_prereq VALGRIND fi ## # Set the name of the valgrind log file. # Referenced by VALGRIND_CMD, valgrind_check_log(), and ".travis.yml". ## VALGRIND_LOGFILE="valgrind.log.$$" ## # Valgrind command (executed via libtool) and options for memcheck analysis. # This allows the program being analyzed to be run in the background. # Results of the valgrind analysis are checked via valgrind_check_log(). # Use of this variable should be followed by the program being analyzed # along with any of its command-line options. ## VALGRIND_CMD="libtool --mode=execute valgrind --tool=memcheck \ --errors-for-leak-kinds=all \ --gen-suppressions=all \ --keep-stacktraces=alloc-and-free \ --leak-check=full \ --leak-resolution=high \ --log-file=${VALGRIND_LOGFILE} \ --num-callers=40 \ --partial-loads-ok=no \ --read-var-info=yes \ --show-leak-kinds=all \ --suppressions=${SHARNESS_TEST_SRCDIR}/valgrind.supp \ --track-origins=yes \ --undef-value-errors=yes \ " ## # Check the valgrind log for errors. # Output the log file if errors are found or if debugging is enabled. ## valgrind_check_log() { local ERR && if test ! -s "${VALGRIND_LOGFILE}"; then echo "ERROR: Valgrind logfile [${VALGRIND_LOGFILE}] not found." ERR=1 elif grep -q 'ERROR SUMMARY: [^0]' "${VALGRIND_LOGFILE}"; then cat "${VALGRIND_LOGFILE}" ERR=1 else test_debug 'cat "${VALGRIND_LOGFILE}"' ERR=0 fi && return ${ERR} } munge-munge-0.5.15/t/sharness.sh000066400000000000000000000632241425467526100164760ustar00rootroot00000000000000# Sharness test framework. # # Copyright (c) 2011-2012 Mathias Lafeldt # Copyright (c) 2005-2012 Git project # Copyright (c) 2005-2012 Junio C Hamano # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see http://www.gnu.org/licenses/ . # Public: Current version of Sharness. SHARNESS_VERSION="1.1.0" export SHARNESS_VERSION # Public: The file extension for tests. By default, it is set to "t". : "${SHARNESS_TEST_EXTENSION:=t}" export SHARNESS_TEST_EXTENSION # Public: Root directory containing tests. Tests can override this variable, # e.g. for testing Sharness itself. if test -z "$SHARNESS_TEST_DIRECTORY" then SHARNESS_TEST_DIRECTORY=$(pwd) else # ensure that SHARNESS_TEST_DIRECTORY is an absolute path so that it # is valid even if the current working directory is changed SHARNESS_TEST_DIRECTORY=$(cd "$SHARNESS_TEST_DIRECTORY" && pwd) || exit 1 fi export SHARNESS_TEST_DIRECTORY # Reset TERM to original terminal if found, otherwise save original TERM [ "x" = "x$SHARNESS_ORIG_TERM" ] && SHARNESS_ORIG_TERM="$TERM" || TERM="$SHARNESS_ORIG_TERM" # Public: The unsanitized TERM under which sharness is originally run export SHARNESS_ORIG_TERM # Export SHELL_PATH : "${SHELL_PATH:=$SHELL}" export SHELL_PATH # if --tee was passed, write the output not only to the terminal, but # additionally to the file test-results/$BASENAME.out, too. case "$SHARNESS_TEST_TEE_STARTED, $* " in done,*) # do not redirect again ;; *' --tee '*|*' --verbose-log '*) mkdir -p "$SHARNESS_TEST_DIRECTORY/test-results" BASE="$SHARNESS_TEST_DIRECTORY/test-results/$(basename "$0" ".$SHARNESS_TEST_EXTENSION")" # Make this filename available to the sub-process in case it is using # --verbose-log. SHARNESS_TEST_TEE_OUTPUT_FILE="$BASE.out" export SHARNESS_TEST_TEE_OUTPUT_FILE # Truncate before calling "tee -a" to get rid of the results # from any previous runs. : >"$SHARNESS_TEST_TEE_OUTPUT_FILE" (SHARNESS_TEST_TEE_STARTED="done" ${SHELL_PATH} "$0" "$@" 2>&1; echo $? >"$BASE.exit") | tee -a "$SHARNESS_TEST_TEE_OUTPUT_FILE" test "$(cat "$BASE.exit")" = 0 exit ;; esac # For repeatability, reset the environment to a known state. # TERM is sanitized below, after saving color control sequences. LANG=C LC_ALL=C PAGER="cat" TZ=UTC EDITOR=: export LANG LC_ALL PAGER TZ EDITOR unset VISUAL CDPATH GREP_OPTIONS [ "x$TERM" != "xdumb" ] && ( [ -t 1 ] && tput bold >/dev/null 2>&1 && tput setaf 1 >/dev/null 2>&1 && tput sgr0 >/dev/null 2>&1 ) && color=t while test "$#" -ne 0; do case "$1" in -d|--d|--de|--deb|--debu|--debug) debug=t; shift ;; -i|--i|--im|--imm|--imme|--immed|--immedi|--immedia|--immediat|--immediate) immediate=t; shift ;; -l|--l|--lo|--lon|--long|--long-|--long-t|--long-te|--long-tes|--long-test|--long-tests) TEST_LONG=t; export TEST_LONG; shift ;; --in|--int|--inte|--inter|--intera|--interac|--interact|--interacti|--interactiv|--interactive|--interactive-|--interactive-t|--interactive-te|--interactive-tes|--interactive-test|--interactive-tests): TEST_INTERACTIVE=t; export TEST_INTERACTIVE; verbose=t; shift ;; -h|--h|--he|--hel|--help) help=t; shift ;; -v|--v|--ve|--ver|--verb|--verbo|--verbos|--verbose) verbose=t; shift ;; -q|--q|--qu|--qui|--quie|--quiet) # Ignore --quiet under a TAP::Harness. Saying how many tests # passed without the ok/not ok details is always an error. test -z "$HARNESS_ACTIVE" && quiet=t; shift ;; --chain-lint) chain_lint=t; shift ;; --no-chain-lint) chain_lint=; shift ;; --no-color) color=; shift ;; --tee) shift ;; # was handled already --root=*) root=$(expr "z$1" : 'z[^=]*=\(.*\)') shift ;; --verbose-log) verbose_log=t shift ;; *) echo "error: unknown test option '$1'" >&2; exit 1 ;; esac done if test -n "$color"; then # Save the color control sequences now rather than run tput # each time say_color() is called. This is done for two # reasons: # * TERM will be changed to dumb # * HOME will be changed to a temporary directory and tput # might need to read ~/.terminfo from the original HOME # directory to get the control sequences # Note: This approach assumes the control sequences don't end # in a newline for any terminal of interest (command # substitutions strip trailing newlines). Given that most # (all?) terminals in common use are related to ECMA-48, this # shouldn't be a problem. say_color_error=$(tput bold; tput setaf 1) # bold red say_color_skip=$(tput setaf 4) # blue say_color_warn=$(tput setaf 3) # brown/yellow say_color_pass=$(tput setaf 2) # green say_color_info=$(tput setaf 6) # cyan say_color_reset=$(tput sgr0) say_color_raw="" # no formatting for normal text say_color() { test -z "$1" && test -n "$quiet" && return case "$1" in error) say_color_color=$say_color_error ;; skip) say_color_color=$say_color_skip ;; warn) say_color_color=$say_color_warn ;; pass) say_color_color=$say_color_pass ;; info) say_color_color=$say_color_info ;; *) say_color_color=$say_color_raw ;; esac shift printf '%s%s%s\n' "$say_color_color" "$*" "$say_color_reset" } else say_color() { test -z "$1" && test -n "$quiet" && return shift printf '%s\n' "$*" } fi TERM=dumb export TERM error() { say_color error "error: $*" EXIT_OK=t exit 1 } say() { say_color info "$*" } test -n "${test_description:-}" || error "Test script did not set test_description." if test "$help" = "t"; then echo "$test_description" exit 0 fi exec 5>&1 exec 6<&0 if test "$verbose_log" = "t" then exec 3>>"$SHARNESS_TEST_TEE_OUTPUT_FILE" 4>&3 elif test "$verbose" = "t" then exec 4>&2 3>&1 else exec 4>/dev/null 3>/dev/null fi # Public: The current test number, starting at 0. SHARNESS_TEST_NB=0 export SHARNESS_TEST_NB test_failure=0 test_fixed=0 test_broken=0 test_success=0 die() { code=$? if test -n "$EXIT_OK"; then exit $code else echo >&5 "FATAL: Unexpected exit with code $code" exit 1 fi } EXIT_OK= trap 'die' EXIT # Public: Define that a test prerequisite is available. # # The prerequisite can later be checked explicitly using test_have_prereq or # implicitly by specifying the prerequisite name in calls to test_expect_success # or test_expect_failure. # # $1 - Name of prerequisite (a simple word, in all capital letters by convention) # # Examples # # # Set PYTHON prerequisite if interpreter is available. # command -v python >/dev/null && test_set_prereq PYTHON # # # Set prerequisite depending on some variable. # test -z "$NO_GETTEXT" && test_set_prereq GETTEXT # # Returns nothing. test_set_prereq() { satisfied_prereq="$satisfied_prereq$1 " } satisfied_prereq=" " # Public: Check if one or more test prerequisites are defined. # # The prerequisites must have previously been set with test_set_prereq. # The most common use of this is to skip all the tests if some essential # prerequisite is missing. # # $1 - Comma-separated list of test prerequisites. # # Examples # # # Skip all remaining tests if prerequisite is not set. # if ! test_have_prereq PERL; then # skip_all='skipping perl interface tests, perl not available' # test_done # fi # # Returns 0 if all prerequisites are defined or 1 otherwise. test_have_prereq() { # prerequisites can be concatenated with ',' save_IFS=$IFS IFS=, set -- $@ IFS=$save_IFS total_prereq=0 ok_prereq=0 missing_prereq= for prerequisite; do case "$prerequisite" in !*) negative_prereq=t prerequisite=${prerequisite#!} ;; *) negative_prereq= esac total_prereq=$((total_prereq + 1)) case "$satisfied_prereq" in *" $prerequisite "*) satisfied_this_prereq=t ;; *) satisfied_this_prereq= esac case "$satisfied_this_prereq,$negative_prereq" in t,|,t) ok_prereq=$((ok_prereq + 1)) ;; *) # Keep a list of missing prerequisites; restore # the negative marker if necessary. prerequisite=${negative_prereq:+!}$prerequisite if test -z "$missing_prereq"; then missing_prereq=$prerequisite else missing_prereq="$prerequisite,$missing_prereq" fi esac done test $total_prereq = $ok_prereq } # You are not expected to call test_ok_ and test_failure_ directly, use # the text_expect_* functions instead. test_ok_() { test_success=$((test_success + 1)) say_color "" "ok $SHARNESS_TEST_NB - $*" } test_failure_() { test_failure=$((test_failure + 1)) say_color error "not ok $SHARNESS_TEST_NB - $1" shift echo "$@" | sed -e 's/^/# /' test "$immediate" = "" || { EXIT_OK=t; exit 1; } } test_known_broken_ok_() { test_fixed=$((test_fixed + 1)) say_color error "ok $SHARNESS_TEST_NB - $* # TODO known breakage vanished" } test_known_broken_failure_() { test_broken=$((test_broken + 1)) say_color warn "not ok $SHARNESS_TEST_NB - $* # TODO known breakage" } # Public: Execute commands in debug mode. # # Takes a single argument and evaluates it only when the test script is started # with --debug. This is primarily meant for use during the development of test # scripts. # # $1 - Commands to be executed. # # Examples # # test_debug "cat some_log_file" # # Returns the exit code of the last command executed in debug mode or 0 # otherwise. test_debug() { test "$debug" = "" || eval "$1" } # Public: Stop execution and start a shell. # # This is useful for debugging tests and only makes sense together with "-v". # Be sure to remove all invocations of this command before submitting. test_pause() { if test "$verbose" = t; then "$SHELL_PATH" <&6 >&3 2>&4 else error >&5 "test_pause requires --verbose" fi } test_eval_() { # This is a separate function because some tests use # "return" to end a test_expect_success block early. case ",$test_prereq," in *,INTERACTIVE,*) eval "$*" ;; *) eval &3 2>&4 "$*" ;; esac } test_run_() { test_cleanup=: expecting_failure=$2 test_eval_ "$1" eval_ret=$? if test "$chain_lint" = "t"; then test_eval_ "(exit 117) && $1" if test "$?" != 117; then error "bug in the test script: broken &&-chain: $1" fi fi if test -z "$immediate" || test $eval_ret = 0 || test -n "$expecting_failure"; then test_eval_ "$test_cleanup" fi if test "$verbose" = "t" && test -n "$HARNESS_ACTIVE"; then echo "" fi return "$eval_ret" } test_skip_() { SHARNESS_TEST_NB=$((SHARNESS_TEST_NB + 1)) to_skip= for skp in $SKIP_TESTS; do case $this_test.$SHARNESS_TEST_NB in $skp) to_skip=t break esac done if test -z "$to_skip" && test -n "$test_prereq" && ! test_have_prereq "$test_prereq"; then to_skip=t fi case "$to_skip" in t) of_prereq= if test "$missing_prereq" != "$test_prereq"; then of_prereq=" of $test_prereq" fi say_color skip >&3 "skipping test: $*" say_color skip "ok $SHARNESS_TEST_NB # skip $1 (missing $missing_prereq${of_prereq})" : true ;; *) false ;; esac } # Public: Run test commands and expect them to succeed. # # When the test passed, an "ok" message is printed and the number of successful # tests is incremented. When it failed, a "not ok" message is printed and the # number of failed tests is incremented. # # With --immediate, exit test immediately upon the first failed test. # # Usually takes two arguments: # $1 - Test description # $2 - Commands to be executed. # # With three arguments, the first will be taken to be a prerequisite: # $1 - Comma-separated list of test prerequisites. The test will be skipped if # not all of the given prerequisites are set. To negate a prerequisite, # put a "!" in front of it. # $2 - Test description # $3 - Commands to be executed. # # Examples # # test_expect_success \ # 'git-write-tree should be able to write an empty tree.' \ # 'tree=$(git-write-tree)' # # # Test depending on one prerequisite. # test_expect_success TTY 'git --paginate rev-list uses a pager' \ # ' ... ' # # # Multiple prerequisites are separated by a comma. # test_expect_success PERL,PYTHON 'yo dawg' \ # ' test $(perl -E 'print eval "1 +" . qx[python -c "print 2"]') == "4" ' # # Returns nothing. test_expect_success() { test "$#" = 3 && { test_prereq=$1; shift; } || test_prereq= test "$#" = 2 || error "bug in the test script: not 2 or 3 parameters to test_expect_success" export test_prereq if ! test_skip_ "$@"; then say >&3 "expecting success: $2" if test_run_ "$2"; then test_ok_ "$1" else test_failure_ "$@" fi fi echo >&3 "" } # Public: Run test commands and expect them to fail. Used to demonstrate a known # breakage. # # This is NOT the opposite of test_expect_success, but rather used to mark a # test that demonstrates a known breakage. # # When the test passed, an "ok" message is printed and the number of fixed tests # is incremented. When it failed, a "not ok" message is printed and the number # of tests still broken is incremented. # # Failures from these tests won't cause --immediate to stop. # # Usually takes two arguments: # $1 - Test description # $2 - Commands to be executed. # # With three arguments, the first will be taken to be a prerequisite: # $1 - Comma-separated list of test prerequisites. The test will be skipped if # not all of the given prerequisites are set. To negate a prerequisite, # put a "!" in front of it. # $2 - Test description # $3 - Commands to be executed. # # Returns nothing. test_expect_failure() { test "$#" = 3 && { test_prereq=$1; shift; } || test_prereq= test "$#" = 2 || error "bug in the test script: not 2 or 3 parameters to test_expect_failure" export test_prereq if ! test_skip_ "$@"; then say >&3 "checking known breakage: $2" if test_run_ "$2" expecting_failure; then test_known_broken_ok_ "$1" else test_known_broken_failure_ "$1" fi fi echo >&3 "" } # Public: Run test commands and expect anything from them. Used when a # test is not stable or not finished for some reason. # # When the test passed, an "ok" message is printed, but the number of # fixed tests is not incremented. # # When it failed, a "not ok ... # TODO known breakage" message is # printed, and the number of tests still broken is incremented. # # Failures from these tests won't cause --immediate to stop. # # Usually takes two arguments: # $1 - Test description # $2 - Commands to be executed. # # With three arguments, the first will be taken to be a prerequisite: # $1 - Comma-separated list of test prerequisites. The test will be skipped if # not all of the given prerequisites are set. To negate a prerequisite, # put a "!" in front of it. # $2 - Test description # $3 - Commands to be executed. # # Returns nothing. test_expect_unstable() { test "$#" = 3 && { test_prereq=$1; shift; } || test_prereq= test "$#" = 2 || error "bug in the test script: not 2 or 3 parameters to test_expect_unstable" export test_prereq if ! test_skip_ "$@"; then say >&3 "checking unstable test: $2" if test_run_ "$2" unstable; then test_ok_ "$1" else test_known_broken_failure_ "$1" fi fi echo >&3 "" } # Public: Run command and ensure that it fails in a controlled way. # # Use it instead of "! ". For example, when dies due to a # segfault, test_must_fail diagnoses it as an error, while "! " would # mistakenly be treated as just another expected failure. # # This is one of the prefix functions to be used inside test_expect_success or # test_expect_failure. # # $1.. - Command to be executed. # # Examples # # test_expect_success 'complain and die' ' # do something && # do something else && # test_must_fail git checkout ../outerspace # ' # # Returns 1 if the command succeeded (exit code 0). # Returns 1 if the command died by signal (exit codes 130-192) # Returns 1 if the command could not be found (exit code 127). # Returns 0 otherwise. test_must_fail() { "$@" exit_code=$? if test $exit_code = 0; then echo >&2 "test_must_fail: command succeeded: $*" return 1 elif test $exit_code -gt 129 -a $exit_code -le 192; then echo >&2 "test_must_fail: died by signal: $*" return 1 elif test $exit_code = 127; then echo >&2 "test_must_fail: command not found: $*" return 1 fi return 0 } # Public: Run command and ensure that it succeeds or fails in a controlled way. # # Similar to test_must_fail, but tolerates success too. Use it instead of # " || :" to catch failures caused by a segfault, for instance. # # This is one of the prefix functions to be used inside test_expect_success or # test_expect_failure. # # $1.. - Command to be executed. # # Examples # # test_expect_success 'some command works without configuration' ' # test_might_fail git config --unset all.configuration && # do something # ' # # Returns 1 if the command died by signal (exit codes 130-192) # Returns 1 if the command could not be found (exit code 127). # Returns 0 otherwise. test_might_fail() { "$@" exit_code=$? if test $exit_code -gt 129 -a $exit_code -le 192; then echo >&2 "test_might_fail: died by signal: $*" return 1 elif test $exit_code = 127; then echo >&2 "test_might_fail: command not found: $*" return 1 fi return 0 } # Public: Run command and ensure it exits with a given exit code. # # This is one of the prefix functions to be used inside test_expect_success or # test_expect_failure. # # $1 - Expected exit code. # $2.. - Command to be executed. # # Examples # # test_expect_success 'Merge with d/f conflicts' ' # test_expect_code 1 git merge "merge msg" B master # ' # # Returns 0 if the expected exit code is returned or 1 otherwise. test_expect_code() { want_code=$1 shift "$@" exit_code=$? if test "$exit_code" = "$want_code"; then return 0 fi echo >&2 "test_expect_code: command exited with $exit_code, we wanted $want_code $*" return 1 } # Public: Compare two files to see if expected output matches actual output. # # The TEST_CMP variable defines the command used for the comparison; it # defaults to "diff -u". Only when the test script was started with --verbose, # will the command's output, the diff, be printed to the standard output. # # This is one of the prefix functions to be used inside test_expect_success or # test_expect_failure. # # $1 - Path to file with expected output. # $2 - Path to file with actual output. # # Examples # # test_expect_success 'foo works' ' # echo expected >expected && # foo >actual && # test_cmp expected actual # ' # # Returns the exit code of the command set by TEST_CMP. test_cmp() { ${TEST_CMP:-diff -u} "$@" } # Public: portably print a sequence of numbers. # # seq is not in POSIX and GNU seq might not be available everywhere, # so it is nice to have a seq implementation, even a very simple one. # # $1 - Starting number. # $2 - Ending number. # # Examples # # test_expect_success 'foo works 10 times' ' # for i in $(test_seq 1 10) # do # foo || return # done # ' # # Returns 0 if all the specified numbers can be displayed. test_seq() { i="$1" j="$2" while test "$i" -le "$j" do echo "$i" || return i=$(("$i" + 1)) done } # Public: Check if the file expected to be empty is indeed empty, and barfs # otherwise. # # $1 - File to check for emptiness. # # Returns 0 if file is empty, 1 otherwise. test_must_be_empty() { if test -s "$1" then echo "'$1' is not empty, it contains:" cat "$1" return 1 fi } # debugging-friendly alternatives to "test [-f|-d|-e]" # The commands test the existence or non-existence of $1. $2 can be # given to provide a more precise diagnosis. test_path_is_file () { if ! test -f "$1" then echo "File $1 doesn't exist. $2" false fi } test_path_is_dir () { if ! test -d "$1" then echo "Directory $1 doesn't exist. $2" false fi } # Check if the directory exists and is empty as expected, barf otherwise. test_dir_is_empty () { test_path_is_dir "$1" && if test -n "$(find "$1" -mindepth 1 -maxdepth 1)" then echo "Directory '$1' is not empty, it contains:" ls -la "$1" return 1 fi } # Public: Schedule cleanup commands to be run unconditionally at the end of a # test. # # If some cleanup command fails, the test will not pass. With --immediate, no # cleanup is done to help diagnose what went wrong. # # This is one of the prefix functions to be used inside test_expect_success or # test_expect_failure. # # $1.. - Commands to prepend to the list of cleanup commands. # # Examples # # test_expect_success 'test core.capslock' ' # git config core.capslock true && # test_when_finished "git config --unset core.capslock" && # do_something # ' # # Returns the exit code of the last cleanup command executed. test_when_finished() { test_cleanup="{ $* } && (exit \"\$eval_ret\"); eval_ret=\$?; $test_cleanup" } # Public: Schedule cleanup commands to be run unconditionally when all tests # have run. # # This can be used to clean up things like test databases. It is not needed to # clean up temporary files, as test_done already does that. # # Examples: # # cleanup mysql -e "DROP DATABASE mytest" # # Returns the exit code of the last cleanup command executed. final_cleanup= cleanup() { final_cleanup="{ $* } && (exit \"\$eval_ret\"); eval_ret=\$?; $final_cleanup" } # Public: Summarize test results and exit with an appropriate error code. # # Must be called at the end of each test script. # # Can also be used to stop tests early and skip all remaining tests. For this, # set skip_all to a string explaining why the tests were skipped before calling # test_done. # # Examples # # # Each test script must call test_done at the end. # test_done # # # Skip all remaining tests if prerequisite is not set. # if ! test_have_prereq PERL; then # skip_all='skipping perl interface tests, perl not available' # test_done # fi # # Returns 0 if all tests passed or 1 if there was a failure. test_done() { EXIT_OK=t if test -z "$HARNESS_ACTIVE"; then test_results_dir="$SHARNESS_TEST_DIRECTORY/test-results" mkdir -p "$test_results_dir" test_results_path="$test_results_dir/$this_test.$$.counts" cat >>"$test_results_path" <<-EOF total $SHARNESS_TEST_NB success $test_success fixed $test_fixed broken $test_broken failed $test_failure EOF fi if test "$test_fixed" != 0; then say_color error "# $test_fixed known breakage(s) vanished; please update test(s)" fi if test "$test_broken" != 0; then say_color warn "# still have $test_broken known breakage(s)" fi if test "$test_broken" != 0 || test "$test_fixed" != 0; then test_remaining=$((SHARNESS_TEST_NB - test_broken - test_fixed)) msg="remaining $test_remaining test(s)" else test_remaining=$SHARNESS_TEST_NB msg="$SHARNESS_TEST_NB test(s)" fi case "$test_failure" in 0) # Maybe print SKIP message if test -n "$skip_all" && test $SHARNESS_TEST_NB -gt 0; then error "Can't use skip_all after running some tests" fi [ -z "$skip_all" ] || skip_all=" # SKIP $skip_all" if test $test_remaining -gt 0; then say_color pass "# passed all $msg" fi say "1..$SHARNESS_TEST_NB$skip_all" test_eval_ "$final_cleanup" test -d "$remove_trash" && cd "$(dirname "$remove_trash")" && rm -rf "$(basename "$remove_trash")" exit 0 ;; *) say_color error "# failed $test_failure among $msg" say "1..$SHARNESS_TEST_NB" exit 1 ;; esac } # Public: Source directory of test code and sharness library. # This directory may be different from the directory in which tests are # being run. : "${SHARNESS_TEST_SRCDIR:=$(cd "$(dirname "$0")" && pwd)}" export SHARNESS_TEST_SRCDIR # Public: Build directory that will be added to PATH. By default, it is set to # the parent directory of SHARNESS_TEST_DIRECTORY. : "${SHARNESS_BUILD_DIRECTORY:="$SHARNESS_TEST_DIRECTORY/.."}" PATH="$SHARNESS_BUILD_DIRECTORY:$PATH" export PATH SHARNESS_BUILD_DIRECTORY # Public: Path to test script currently executed. SHARNESS_TEST_FILE="$0" export SHARNESS_TEST_FILE # Prepare test area. SHARNESS_TRASH_DIRECTORY="trash-directory.$(basename "$SHARNESS_TEST_FILE" ".$SHARNESS_TEST_EXTENSION")" test -n "$root" && SHARNESS_TRASH_DIRECTORY="$root/$SHARNESS_TRASH_DIRECTORY" case "$SHARNESS_TRASH_DIRECTORY" in /*) ;; # absolute path is good *) SHARNESS_TRASH_DIRECTORY="$SHARNESS_TEST_DIRECTORY/$SHARNESS_TRASH_DIRECTORY" ;; esac test "$debug" = "t" || remove_trash="$SHARNESS_TRASH_DIRECTORY" rm -rf "$SHARNESS_TRASH_DIRECTORY" || { EXIT_OK=t echo >&5 "FATAL: Cannot prepare test area" exit 1 } # # Load any extensions in $srcdir/sharness.d/*.sh # if test -d "${SHARNESS_TEST_SRCDIR}/sharness.d" then for file in "${SHARNESS_TEST_SRCDIR}"/sharness.d/*.sh do # Ensure glob was not an empty match: test -e "${file}" || break if test -n "$debug" then echo >&5 "sharness: loading extensions from ${file}" fi . "${file}" if test $? != 0 then echo >&5 "sharness: Error loading ${file}. Aborting." exit 1 fi done fi # Public: Empty trash directory, the test area, provided for each test. The HOME # variable is set to that directory too. export SHARNESS_TRASH_DIRECTORY HOME="$SHARNESS_TRASH_DIRECTORY" export HOME mkdir -p "$SHARNESS_TRASH_DIRECTORY" || exit 1 # Use -P to resolve symlinks in our working directory so that the cwd # in subprocesses like git equals our $PWD (for pathname comparisons). cd -P "$SHARNESS_TRASH_DIRECTORY" || exit 1 this_test=${SHARNESS_TEST_FILE##*/} this_test=${this_test%.$SHARNESS_TEST_EXTENSION} for skp in $SKIP_TESTS; do case "$this_test" in $skp) say_color info >&3 "skipping test $this_test altogether" skip_all="skip all tests in $this_test" test_done esac done test -n "$TEST_LONG" && test_set_prereq EXPENSIVE test -n "$TEST_INTERACTIVE" && test_set_prereq INTERACTIVE # Make sure this script ends with code 0 : # vi: set ts=4 sw=4 noet : munge-munge-0.5.15/t/test-terminal.perl000077500000000000000000000033511425467526100177660ustar00rootroot00000000000000#!/usr/bin/perl use 5.008; use strict; use warnings; use IO::Pty; use File::Copy; # Run @$argv in the background with stdio redirected to $out and $err. sub start_child { my ($argv, $out, $err) = @_; my $pid = fork; if (not defined $pid) { die "fork failed: $!" } elsif ($pid == 0) { open STDOUT, ">&", $out; open STDERR, ">&", $err; close $out; exec(@$argv) or die "cannot exec '$argv->[0]': $!" } return $pid; } # Wait for $pid to finish. sub finish_child { # Simplified from wait_or_whine() in run-command.c. my ($pid) = @_; my $waiting = waitpid($pid, 0); if ($waiting < 0) { die "waitpid failed: $!"; } elsif ($? & 127) { my $code = $? & 127; warn "died of signal $code"; return $code + 128; } else { return $? >> 8; } } sub xsendfile { my ($out, $in) = @_; # Note: the real sendfile() cannot read from a terminal. # It is unspecified by POSIX whether reads # from a disconnected terminal will return # EIO (as in AIX 4.x, IRIX, and Linux) or # end-of-file. Either is fine. copy($in, $out, 4096) or $!{EIO} or die "cannot copy from child: $!"; } sub copy_stdio { my ($out, $err) = @_; my $pid = fork; defined $pid or die "fork failed: $!"; if (!$pid) { close($out); xsendfile(\*STDERR, $err); exit 0; } close($err); xsendfile(\*STDOUT, $out); finish_child($pid) == 0 or exit 1; } if ($#ARGV < 1) { die "usage: test-terminal program args"; } my $master_out = new IO::Pty; my $master_err = new IO::Pty; $master_out->set_raw(); $master_err->set_raw(); $master_out->slave->set_raw(); $master_err->slave->set_raw(); my $pid = start_child(\@ARGV, $master_out->slave, $master_err->slave); close $master_out->slave; close $master_err->slave; copy_stdio($master_out, $master_err); exit(finish_child($pid)); munge-munge-0.5.15/t/valgrind.supp000066400000000000000000000047001425467526100170250ustar00rootroot00000000000000{ dlopen-_dlerror_run-leak Memcheck:Leak match-leak-kinds: reachable fun:calloc fun:_dlerror_run fun:dlopen@@GLIBC_2.2.5 } { exit-leak Memcheck:Leak match-leak-kinds: reachable fun:malloc ... fun:exit } { getgrent_r-leak Memcheck:Leak match-leak-kinds: reachable fun:?alloc ... fun:getgrent_r@@GLIBC_2.2.5 } { getgrgid_r-leak Memcheck:Leak match-leak-kinds: reachable fun:?alloc ... fun:getgrgid_r@@GLIBC_2.2.5 } { gethostbyaddr-leak Memcheck:Leak match-leak-kinds: reachable fun:?alloc ... fun:gethostbyaddr } { gethostbyname-leak Memcheck:Leak match-leak-kinds: definite,reachable fun:?alloc ... fun:gethostbyname } { getpwnam_r-leak Memcheck:Leak match-leak-kinds: reachable fun:?alloc ... fun:getpwnam_r@@GLIBC_2.2.5 } { getpwuid_r-leak Memcheck:Leak match-leak-kinds: reachable fun:?alloc ... fun:getpwuid_r@@GLIBC_2.2.5 } { libcrypto-AES_encrypt-value8 Memcheck:Value8 obj:*/libcrypto.so.1.1 fun:AES_encrypt ... fun:RAND_DRBG_instantiate ... fun:_random_add } { libcrypto-base64_encode_block-value8 Memcheck:Value8 fun:base64_encode_block } { libcrypto-CRYPTO_THREAD_lock_new-leak Memcheck:Leak fun:malloc fun:CRYPTO_zalloc fun:CRYPTO_THREAD_lock_new obj:*/libcrypto.so.1.1 } { libcrypto-FIPS_mode_set-cond Memcheck:Cond ... fun:FIPS_mode_set obj:*/libcrypto.so.1.1 } { libcrypto-cond Memcheck:Cond obj:*/libcrypto.so.1.1 } { libcrypto-_random_write_seed-param Memcheck:Param write(buf) fun:write fun:fd_write_n fun:_random_write_seed fun:random_fini fun:main } { libgcrypt-_gcry_check_version-leak Memcheck:Leak match-leak-kinds: reachable fun:malloc ... fun:_gcry_check_version } { libgcrypt-crypto_init-leak Memcheck:Leak match-leak-kinds: reachable fun:malloc ... obj:*/libgcrypt.so.20.* fun:crypto_init fun:main } { libgcrypt-gcry_control-leak Memcheck:Leak match-leak-kinds: reachable fun:malloc ... fun:gcry_control } { openssl-OSSL_PROVIDER_try_load Memcheck:Leak match-leak-kinds: reachable fun:?alloc ... fun:OSSL_PROVIDER_try_load fun:crypto_init fun:main } { pthread_cancel-leak Memcheck:Leak match-leak-kinds: definite fun:malloc ... fun:pthread_cancel@@GLIBC_2.34 fun:work_fini fun:job_accept fun:main }