work/0000755000000000000000000000000014141560754006735 5ustar work/.gitignore0000644000000000000000000000063714141560754010733 0ustar *.o *~ *.new debian/*.substvars debian/*.debhelper.log debian/files debian/debhelper-build-stamp debian/.debhelper debian/userv-utils debian/userv-ucgi debian/userv-dyndns debian/userv-git-daemon debian/userv-groupmanage debian/userv-ipif dist_tmp userv-utils-*.tar.gz build git-daemon/git-upload-pack git-daemon/inetd.conf git-daemon/git-daemon git-daemon/git-service git-daemon/sedscript git-daemon/logrotate work/COPYING0000644000000000000000000010451314141560754007774 0ustar 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 . work/Makefile0000644000000000000000000000234114141560754010375 0ustar # Copyright 1996-2013 Ian Jackson # Copyright 1998 David Damerell # Copyright 1999,2003 # Chancellor Masters and Scholars of the University of Cambridge # Copyright 2010 Tony Finch # # This 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 userv-utils; if not, see http://www.gnu.org/licenses/. all: @echo >&2 'See README. This is not a unified package.' SUBDIRS_DISTCLEAN= www-cgi ipif git-daemon distclean: find . \( -name '*~' -o -name '#*#' -o -name '*.o' -o -name core \ -o -name dist_tmp -o -name userv-utils-\*.tar.gz \ -o -name '.#*' \) \ -print0 | xargs -0r rm -rf -- for f in $(SUBDIRS_DISTCLEAN); do make -C $$f distclean; done work/README0000644000000000000000000000637314141560754007626 0ustar This is userv-utils. It is a collection of utilities, scripts and example configuration files that serve both as examples for how to use userv, and in some cases, hopefully as useful programs and services. Please see each individual directory for any details, installation instructions, documentation, invididual copyright statements, and anything else, that is available. If you do not know what userv is, see its WWW page at http://www.chiark.greenend.org.uk/~ian/userv/. For now at least, the userv mailing lists should be used to discuss these and other userv-using programs. Please send bug reports and suggestions to ijackson@chiark.greenend.org.uk, or to the userv-discuss mailing list if you are subscribed to it. Here is a quick summary of the currently available utilities Directory Status Description (UC=`users can ...') --------------- ----- ------------------------------------------------ groupmanage Y Y A UC create groups, add/remove members, &c ipif Y Y A UC create IP interfaces/VPNs (Linux-specific) www-cgi Y Y A UC provide CGIs which run as themselves misc/mailq* Y S S UC list mail queue even if sendmail forbids misc/ndc-reload Y S S UC reload named after editing own zone files misc/checkpass* Y Y S UC check own password; some can check any passwd git-daemon Y Y Y UC safely publish git repositories on port 9418 newsrc-lg X B X Acquire list of subscribed groups from .newsrcs dyndns Y Y Y UC edit simple DNS entries for certian domains Key to the Status: First letter is completeness: Y Complete. P Partially complete, some glue or modification needed. X Incomplete. Much extra stuff is required. Second letter is general status: Y Released; hopefully of production quality. B Beta. Not fully released, but hopefully useful with care. A Alpha. Probably buggy. Not well tested or widely used. X Example/experimental - for documentation purposes only, not recommended for use. S Too small for this question to be relevant. Third letter is documentation: Y Full installation and use instructions included. A Documentation is believed largely adequate, but a bit rough. P Partial documentation or hints. Good sysadmins should cope. X No documentation. Good luck ! S Too small to need any significant documentation. userv-utils are Copyright 1996-2013,2016 Ian Jackson Copyright 1998 David Damerell Copyright 1999,2003 Chancellor Masters and Scholars of the University of Cambridge Copyright 2010 Tony Finch Copyright 2013,2016 Mark Wooding All the utilities here are 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 userv-utils; if not, see http://www.gnu.org/licenses/. Local variables: mode: text fill-column: 77 End: work/changelog0000644000000000000000000001654114141560754010616 0ustar userv-utils (0.6.1) unstable; urgency=medium * Collect into userv-utils all the services which don't involve creating users, etc. Move the services.d files to services-available, and move the service-specific configurations into their enabled locations where appropriate. * Move the upstream changelog into ./changelog, to make room for a Debian-specific upstream changelog. * ipif: Provide ipif-access aka ipif/service-wrap, new access control wrapper program for service with a new better syntax. [Ian Jackson; fixes from Mark Wooding] * ipif: Fix some option-handling bugs. * ipif: Tidy up some compiler warnings. [Mark Wooding] -- Ian Jackson Wed, 04 Aug 2021 22:48:27 +0100 userv-utils (0.6.0~~iwj3) unstable; urgency=low * Correct binary package dependencies by referencing substvars in debian/control. * Add dependency on debhelper. * No longer mention SLIP and udptunnel in the userv-ipif Description. * Americanise spelling of /usr/share/common-licences to ...-licenses. * Add debhelper token to postinst scripts. * Change default user for git-daemon to userv-git and default user for dyndns to userv-dyndns. * Improve adduser calls: - no longer guard with calls to id, as adduser --quiet is idempotent - pass --shell /bin/false and --no-create-home * Bump Standards-Version to 3.7.0.0. * Fix typo in userv-cgi long description. * Provide various documentation for userv-cgi in /usr/share. * Remove obsolete and broken dist target in root Makefile. * Add quirkafleeg to git-daemon/Makefile to placate emacs makefile mode. * www-cgi: Overhaul of env var handling (thanks to Mark Wooding). * Make deprecated things not built by default by Makefile (and remove code in debian/rules for achieving this). -- Ian Jackson Fri, 14 Apr 2017 15:58:46 +0100 userv-utils (0.6.0~~iwj2) unstable; urgency=low * Use dh(1). WIP. -- Ian Jackson Sun, 08 Dec 2013 13:38:23 +0000 userv-utils (0.6.0~~iwj1) unstable; urgency=low * WIP * www-cgi: Promise better status for this utility. * mailq: Clarify set of relevant files in README. * dyndns: Docuument existence in README. * REAMDE, copyright: Correct locations for GPL, and contact info. * Update to GPLv3+; update copyright notices everywhere. * ipif: Update docs to reflect fact that we are now using tun/tap. * ipif: Deprecate udptunnel. * ipif: Provide head comment of service.c as a txt docs. -- Ian Jackson Wed, 04 Dec 2013 23:01:37 +0000 userv-utils (0.5.0) unstable; urgency=low * checkpasswd-*: new service * www-cgi: whitelist some more HTTP headers. * ipif: Improve documentation comment. * ipif: Some portability improvements. * Remove .cvsignore files. * Pass -g to linker, by default. * www-cgi: clean target removes *.o. -- Ian Jackson Sun, 27 Jan 2013 16:34:29 +0000 userv-utils (0.4.2) unstable; urgency=low ipif bugfix: * Fix failure which occurs when input data starts to back up: service.c:866: copydata: Assertion `r < sizeof(input_buf)' failed. -- Ian Jackson Sun, 15 Jan 2012 01:00:00 +0000 userv-utils (0.4.1) unstable; urgency=low ipif bugfixes: * Ignore empty packets (ie consecutive END bytes), as tun rejects them with EINVAL. * Tolerate ENOMEM from tun. -- Ian Jackson Sat, 14 Jan 2012 15:46:53 +0000 userv-utils (0.4) unstable; urgency=low ipif: * Now uses tun, not slip. All modern Linux kernels have tun support, and we weren't portable to non-Linux anyway. slattach has sometimes been implicated in kernel problems. Interfaces are now called "userv%d" (ie, userv0, userv1, etc.). Only "slip" is now supported. -- Ian Jackson Sat, 14 Jan 2012 15:24:57 +0000 userv-utils (0.4~beta1) unstable; urgency=low git-daemon: * New userv-git-daemon service. package admin: * Now in git. * Fixed up some portability problems. -- Ian Jackson Sat, 22 May 2010 19:50:57 +0100 userv-utils (0.3) unstable; urgency=medium dyndns: * New dyndns service. ucgi: * add HTTP_REFERER. * Fix path in www-cgi userv service default configuration. ipif/udptunnel: * Use slip, not cslip (!) * service MAXEXROUTES increased from 5 to 50. * Set default max clock skew to 45/45, not 10/30. * Allow config file to override default clock skew and lag. * Report nonzero death of m4 better. * Add a few missing #include's of . * Minor fixes to INSTALL. groupmanage: * new name-regexp feature. * admin-group is understood in config file but currently ignored. * file locations configurable. * groupmanage: do not claim that root doesn't exist. * groupmanage: configurable group name length limit. (Thanks to reports and patches from Ben Harris at Cambridge University.) Packaging changes: * Debianisation. * New Makefiles in various directories; still not wonderful. * Removed some common stuff from */Makefile to settings.make. * Copyright notices updated. * Moved changelog to debian/changelog. -- Ian Jackson Tue, 6 Jun 2006 22:02:17 +0100 userv-utils (0.2.3) unstable; urgency=low * udptunnel-reconf can write a known_hosts file for you. -- Ian Jackson Mon, 11 Feb 2002 21:46:48 +0000 userv-utils (0.2.2) unstable; urgency=low * udptunnel-reconf default script pauses for 10s between restarts. * udptunnel-reconf inittab entries default to having Sat, 15 Dec 2001 17:55:06 +0000 userv-utils (0.2.1) unstable; urgency=low * New udptunnel-reconf program for generating invoke scripts, inittab entries, and the like, for a multi-host VPN. * service.c (userv ipif) /32 prefixes work properly now. * `make distclean' works in ipif, www-cgi and top level. -- Ian Jackson Mon, 11 Dec 2000 02:45:58 +0000 userv-utils (0.2.0) unstable; urgency=low Improvements to ipif (tunnelling/VPN facility): * INSTALL instructions much improved and README created. * Patch to slattach included. * Documentation comments improved. -- Ian Jackson Mon, 18 Sep 2000 01:31:01 +0100 userv-utils (0.1.90) unstable; urgency=low * ipif/INSTALL instructions, such as they are, included. * ipif service now supports `=' character in addrs in ipif-networks, for local endpoint only. -- Ian Jackson Wed, 21 Jun 2000 23:48:10 +0100 userv-utils (0.1.9) unstable; urgency=low * Completely revamped udptunnel (in ipif) - now does encryption. -- Ian Jackson Sun, 18 Jun 2000 14:41:36 +0100 userv-utils (0.1) experimental; urgency=low * Initial release. -- Ian Jackson Tue, 9 Nov 1999 23:24:58 +0000 # Local variables: # mode: debian-changelog # End: work/debian/0000755000000000000000000000000014141560754010157 5ustar work/debian/changelog0000644000000000000000000000071014141560754012027 0ustar userv-utils (0.6.1-2) unstable; urgency=medium * Source-only upload for testing migration. * Add Lintian override for malformed-debian-changelog-version. -- Sean Whitton Sat, 06 Nov 2021 13:13:32 -0700 userv-utils (0.6.1-1) unstable; urgency=medium * Initial release (Closes: #991906). -- Sean Whitton Wed, 04 Aug 2021 15:32:01 -0700 # Local variables: # mode: debian-changelog # End: work/debian/control0000644000000000000000000000450014141560754011561 0ustar Source: userv-utils Section: admin Priority: optional Maintainer: Sean Whitton Uploaders: Ian Jackson Build-Depends: debhelper-compat (= 12), rename Standards-Version: 4.5.1 Rules-Requires-Root: binary-targets Homepage: https://www.chiark.greenend.org.uk/ucgi/~ian/git?p=userv-utils.git;a=summary Vcs-Git: https://git.spwhitton.name/userv-utils/ Vcs-Browser: https://git.spwhitton.name/userv-utils/ Package: userv-utils Architecture: any Depends: userv, ${shlibs:Depends}, ${misc:Depends} Recommends: ${perl:Depends} Description: privsep utilities collection Several small userv services, which allow certain system configuration actions to be delegated. In each case the service is disabled unless enabled by symlink /etc/userv/services.d/* -> ../services-available/*. . ipif - allow non-root users to create network interfaces ucgi - run CGI programs in providing user's account mailq - allow users to view the mail queue ndc-reload - allow certain users to reload the nameserver checkpasswd-* - allow users to run a UNIX password check groupmanage - allow users to create and manage a few groups each Package: userv-dyndns Architecture: all Depends: userv, chiark-utils-bin, adduser, ${perl:Depends}, ${misc:Depends} Recommends: bind Description: dynamic DNS for shell account users userv-dyndns is a userv service which allows non-root users to modify individual DNS records in specified zones in a controlled way. . Typically, this can be used to provide a `dyndns.org'-like service which is modifiable by shell account users. . The default configuration creates the infrastructure (including a service user) but does not allow any users to modify the DNS. Package: userv-git-daemon Architecture: all Depends: userv, git-core, adduser, ${perl:Depends}, ${misc:Depends} Description: per-user git daemon service userv-git-daemon allows users to publish git repositories which will be published via the git protocol on 9418. This is a bit like git-daemon except that the actual reading of each user's repositories is done as that user. . The default configuration does nothing: you must (a) manually copy the line from /usr/share/doc/examples/userv-git-daemon.inetd into /etc/inetd.conf and (b) specifically list hostnames and target directories in /etc/userv/git-urlmap. work/debian/copyright0000644000000000000000000000326714141560754012122 0ustar This package contains a number of small utilities and programs for use with the `userv' security boundary tool, obtained from . This package, containing the moderately portable sources and Debian packaging information, and the resulting Debian binary packages, was put together by Ian Jackson and Sean Whitton. For both upstream and Debian packaging questions, please contact userv-discuss@chiark.greenend.org.uk. userv and userv-utils are all free software; you can redistribute them and/or modify them 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. These programs are distributed in the hope that they 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 with your Debian GNU/Linux system, in /usr/share/common-licenses/GPL. If not, see . The utilities and programs under the git-daemon/ subdirectory are dedicated to the public domain by means of the CC0 1.0 public domain dedication; see /usr/share/common-licenses/CC0-1.0 on Debian systems. userv-utils are Copyright 1996-2013,2016 Ian Jackson Copyright 1998 David Damerell Copyright 1999,2003 Chancellor Masters and Scholars of the University of Cambridge Copyright 2010 Tony Finch Copyright 2013,2016 Mark Wooding work/debian/rules0000755000000000000000000000613514141560754011244 0ustar #!/usr/bin/make -f # Copyright 1996-2013,2016 Ian Jackson # Copyright 1998 David Damerell # Copyright 1999,2003 # Chancellor Masters and Scholars of the University of Cambridge # Copyright 2010 Tony Finch # # This 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 userv-utils; if not, see http://www.gnu.org/licenses/. subdirs_build= ipif ucgi git-daemon subdirs_nobuild=dyndns groupmanage misc package= userv-utils packages_indep= userv-dyndns userv-groupmanage userv-utils userv-git-daemon packages_arch= userv-ipif userv-cgi packages= $(packages_indep) $(packages_arch) SHELL=/bin/bash cwd= $(shell pwd) d= $(cwd)/debian %: dh $@ override_dh_auto_configure: override_dh_auto_build: $(checkdir) set -e; for s in $(subdirs_build); do \ $(MAKE) -C $$s all; \ done touch build override_dh_auto_install: $(checkdir) - set -e; for p in $(packages); do rm -rf $d/$$p; done - set -e; for s in $(subdirs_build) $(subdirs_nobuild); do \ t=$d/userv-$$s; \ rm -rf $$t; \ $(MAKE) -C $$s install install-docs install-examples \ prefix=$$t/usr \ etcdir=$$t/etc \ vardir=$$t/var \ gituser=root \ ; \ done - mv debian/userv-misc debian/userv-utils - mv $d/userv-ipif/usr/share/doc/userv-ipif/{service.c.txt,ipif.txt} - set -e; cd debian/userv-ucgi/usr/share/doc/userv-ucgi; \ rename 's/^/ucgi-/' * - set -e; cd debian/userv-groupmanage/usr/share/doc; \ mv groupmanage userv-groupmanage; \ rm userv-groupmanage/INSTALL - set -e; for p in userv-ipif userv-ucgi userv-groupmanage; do \ (cd debian/$$p/usr/share/doc; \ mv $$p userv-utils); \ cp -al debian/$$p/. debian/userv-utils/.; \ done - perl -pe 's{/usr/local/}{/usr/}' ucgi/www-cgi \ >debian/userv-utils/etc/userv/services.d/www-cgi - rename 's/\.example$$//' $d/userv-ipif/etc/userv/vpn/*.example \ $d/userv-dyndns/etc/userv/dyndns-service-users.example \ $d/userv-utils/etc/groupmanage.conf.example rename 's/\.distrib$$//' $d/*/etc/userv/services.d/*.distrib - mv $d/userv-utils/usr/bin/mailq $d/userv-utils/usr/bin/mailq.userv - set -e; cd $d/userv-utils/etc/userv; \ mkdir services-available; \ mv services.d/* services-available/ override_dh_install: override_dh_auto_clean: $(checkdir) rm -f build set -e; for s in $(subdirs_build); do \ $(MAKE) -C $$s -i distclean || \ $(MAKE) -C $$s -f Makefile.in distclean; \ done rm -rf *~ debian/tmp debian/*~ debian/files* debian/substvars* define checkdir test -f ipif/service.c endef # Below here is fairly generic really checkroot: $(checkdir) test root = "`whoami`" work/debian/source/0000755000000000000000000000000014141560754011457 5ustar work/debian/source/lintian-overrides0000644000000000000000000000004314141560754015035 0ustar malformed-debian-changelog-version work/debian/userv-dyndns.postinst0000755000000000000000000000220714141560754014431 0ustar #!/bin/sh set -e # Copyright 1996-2013 Ian Jackson # Copyright 1998 David Damerell # Copyright 1999,2003 # Chancellor Masters and Scholars of the University of Cambridge # Copyright 2010 Tony Finch # # This 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 userv-utils; if not, see http://www.gnu.org/licenses/. #DEBHELPER# user="$(sed -n '/^[a-z]/{p;q;}' /etc/userv/dyndns-service-users)" if [ "$user" ]; then adduser --system --force-badname --quiet --group \ --gecos 'userv dyndns' \ --home /etc/userv --no-create-home --shell /bin/false $user fi work/debian/userv-git-daemon.postinst0000755000000000000000000000236414141560754015162 0ustar #!/bin/sh set -e # Copyright 1996-2013 Ian Jackson # Copyright 1998 David Damerell # Copyright 1999,2003 # Chancellor Masters and Scholars of the University of Cambridge # Copyright 2010 Tony Finch # # This file is part of userv-git-daemon, part of userv-utils # # This 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 userv-utils; if not, see http://www.gnu.org/licenses/. GITDUSER=_userv-git defaults=/etc/default/userv-git-daemon if test -f $defaults; then . $defaults; fi #DEBHELPER# if [ "$GITDUSER" ]; then adduser --system --force-badname --quiet --group \ --gecos 'userv git daemon' \ --home /etc/userv --no-create-home --shell /bin/false $GITDUSER fi work/dyndns/0000755000000000000000000000000014141560754010234 5ustar work/dyndns/INSTALL0000644000000000000000000000342614141560754011272 0ustar # To install the dyndns service: # # 1. Install the scripts and configuration: # mkdir -p /usr/local/lib/userv/dyndns /var/lib/userv/dyndns/tmp cp install-script /usr/local/lib/userv/dyndns/install cp service update /usr/local/lib/userv/dyndns cp dyndns /etc/userv/services.d/dyndns.distrib cp dyndns-domains /etc/userv/dyndns-domains.example # Rename the .distrib and .example, or edit them to be how you # want, or merge your changes. # # Create the service user `usdyndns'. # # 2. For each zone, create # /var/lib/userv/zone,/ # and put in it the file # Manual containing the $TTL, SOA, zone cut NS RRset, # RP, and other fixed RRsets. # and edit # /etc/userv/dyndns-domains appropriately. # and then create an RR and check that it has made the zone, # before adding the new file # Zone # to your nameserver configuration. # Copyright 1996-2013 Ian Jackson # Copyright 1998 David Damerell # Copyright 1999,2003 # Chancellor Masters and Scholars of the University of Cambridge # Copyright 2010 Tony Finch # # This 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 userv-utils; if not, see http://www.gnu.org/licenses/. work/dyndns/Makefile0000644000000000000000000000222714141560754011677 0ustar # Makefile # installation runes for userv-dyndns # Copyright (C) 2003 Ian Jackson # # This 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 userv-utils; if not, see http://www.gnu.org/licenses/. include ../settings.make install: mkdir -p $(shareuserv)/dyndns $(varlibuserv)/dyndns/tmp cp service update $(shareuserv)/dyndns cp install-script $(shareuserv)/dyndns/install install-examples: mkdir -p $(services) cp dyndns $(services)/dyndns.distrib cp dyndns-domains $(etcuserv)/dyndns-domains.example echo _userv-dyndns >$(etcuserv)/dyndns-service-users.example install-docs: mkdir -p $(docdir)/userv-dyndns cp INSTALL $(docdir)/userv-dyndns work/dyndns/dyndns0000644000000000000000000000032114141560754011452 0ustar if ( grep calling-user-shell /etc/shells & grep service-user /etc/userv/dyndns-service-users ) reset no-set-environment no-suppress-args no-disconnect-hup execute /usr/share/userv/dyndns/service fi work/dyndns/dyndns-domains0000644000000000000000000000260314141560754013107 0ustar # Syntax is list of directives. # include Read at this point # eof # Settings directives, apply to succeeding subdomain lines. # zone This is for stuff in # rrs ... Allow addition/removal of (only) these RR types # ratelimit # Limit rate of changes. Up to one per # will always be allowed, and never updates more than # apart. is compared # with events in roughly last # ttlrange # Actual directive: # subdomain ratelimit 30 300 3600 zone dynamic.greenend.org.uk ttlrange 30 86400 rrs A subdomain anjou rich-avn subdomain badgers sion-net subdomain bellevue theom subdomain burrow vcla-brw subdomain confusion matt-cnf subdomain dorothee jdamery subdomain ecstacy dunc-xtc subdomain firestorm davi-mul subdomain gallery jayl-dns subdomain nosreme ceme-gal subdomain heresy cjwa-vpn subdomain lemoncurd bjha-dd subdomain lilac dame-lil subdomain nijinsky jmatthew subdomain relativity ijackson subdomain riva cjwatson subdomain sinister Mgend subdomain slappy chri-cat subdomain stardust sgtatham subdomain thistles rcooksey subdomain titus owen-dns subdomain milton stev-pub rrs A CNAME subdomain gin dh219 subdomain aibs dh219 rrs A MX CNAME subdomain test ijackson eof work/dyndns/install-script0000755000000000000000000000243614141560754013137 0ustar #!/bin/bash # Copyright 1996-2013 Ian Jackson # Copyright 1998 David Damerell # Copyright 1999,2003 # Chancellor Masters and Scholars of the University of Cambridge # Copyright 2010 Tony Finch # # This 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 userv-utils; if not, see http://www.gnu.org/licenses/. set -e zone=$1 test -d ../zone,$zone ah="` adnshost +Do +Dt -Cf -t soa $zone. || \ (test $? == 6 && echo . . 1 0 0 0 0) `" re='.* \([0-9][0-9]*\) [0-9][0-9]* [0-9][0-9]* [0-9][0-9]* [0-9][0-9]*$' serial="`expr 1 + match \"$ah\" \"$re\"`" sed Zone.new cat [_0-9a-z]*,data >>Zone.new mv Zone.new Zone echo "serial $serial" userv root ndc-reload work/dyndns/service0000755000000000000000000001402614141560754011625 0ustar #!/usr/bin/perl # usage: (cat RRs; echo .) | userv dyndns # Not all zone file formats are accepted: # - All RRs must have owners specified. # - All RRs must have TTLs specified. # - The owner must be specified as a sub-subdomain, relative # to ., and so must not have a trailing `.'; # where the owner is to be ., `@' must be used. # Copyright 1996-2013 Ian Jackson # Copyright 1998 David Damerell # Copyright 1999,2003 # Chancellor Masters and Scholars of the University of Cambridge # Copyright 2010 Tony Finch # # This 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 userv-utils; if not, see http://www.gnu.org/licenses/. use POSIX; BEGIN { $vardir= "/var/lib/userv/dyndns"; $defconf= "/etc/userv/dyndns-domains"; $libdir= "/usr/share/userv/dyndns"; } END { remove "$vardir/tmp/$$" or $! == ENOENT or warn "cannot remove tempfile:$!\n"; } use FileHandle; use IO::File; use Socket; use Socket6; @ARGV==2 or die "need and arguments\n"; ($zone,$subdomain) = @ARGV; domainsyntax("command line",$zone); domainsyntax("command line",$subdomain) unless $subdomain eq '@'; @userv_groups= split m/ /, $ENV{'USERV_GROUP'}; @rates= (1,1,1000); $ttlmin= 0; $ttlmax= 86400; sub readconf ($) { my ($cf,$fh) = @_; $fh= new FileHandle; $fh->open("< $cf") or die "$cf: $!\n"; for (;;) { $!=0; $_= <$fh>; length or die "$cf:".($? ? "read:$?" : "eof")."\n"; s/^\s+//; chomp; s/\s+$//; last if m/^eof$/; next if m/^\#/ or !m/\S/; if (m/^zone\s+(\S+)$/) { $thiszone= $1 eq $zone; } elsif (m/^ratelimit\s+(\d+)\s+(\d+)\s+(\d+)$/) { @rates= ($1,$2,$3); } elsif (m/^ttlrange\s+(\d+)\s+(\d+)$/) { ($ttlmin,$ttlmax) = ($1,$2); } elsif (m/^rrs\s+([A-Za-z0-9 \t]+)$/) { $rrt_list= $1; undef %rrt_allowed; grep { y/a-z/A-Z/; $rrt_allowed{$_}= 1; } split m/\s+/, $1; } elsif (m/^include\s+(\S.*)$/) { return if readconf($1); } elsif (m/^subdomain\s+(\S+)\s+(\S+)$/) { next unless $thiszone; next unless $1 eq $subdomain; next unless grep { $_ eq $2 } @userv_groups; return 1; } else { die "$cf:$.: config error\n"; } } close $fh or die "$cf: close: $!\n"; return 0; } readconf "$defconf" or die "permission denied\n"; chdir "$vardir" or die "chdir dyndns:$!\n"; open T,">tmp/$$" or die "create temp file: $!\n"; for (;;) { $?=0; $_= ; die "input:$.:".($? ? "$?" : "eof") unless length; chomp; last if m/^\.$/; s/^(\S+)\s+(\d+)\s+([A-Za-z][0-9A-Za-z]*)\s+// or die "input:$.:bogus line\n"; ($owner,$ttl,$type)= ($1,$2,$3); if ($owner eq '@') { $write_owner= $subdomain; } else { domainsyntax("input:$.",$owner) unless $owner eq '@'; $write_owner= $subdomain eq '@' ? $owner : "$owner.$subdomain"; } length "$write_owner.$zone." < 255 or die "input:$.:$owner:resulting domain name too long\n"; $ttl += 0; if ($ttl < $ttlmin) { warn "input:$.:$owner:capping ttl $ttl at lower bound $ttlmin\n"; $ttl=$ttlmin; } if ($ttl > $ttlmax) { warn "input:$.:$owner:capping ttl $ttl at upper bound $ttlmax\n"; $ttl=$ttlmax; } $type =~ y/a-z/A-Z/; die "input:$.:$owner:rr type not permitted:$type\n" unless $rrt_allowed{$type}; if (exists $rrset_ttl{$owner,$type}) { die "input:$.:$owner:$type:RRset has varying TTLs\n" unless $rrset_ttl{$owner,$type} == $ttl; } else { $rrset_ttl{$owner,$type}= $ttl; } die "input:$.:$owner:CNAME and other records, or multiple CNAMEs\n" if $type eq 'CNAME' ? exists $owner_types{$owner} : exists $owner_types{$owner}->{'CNAME'}; if ($type eq 'A') { defined($addr= inet_aton $_) or die "input:$.:$owner:invalid IP address\n"; $data= inet_ntoa($addr); } elsif ($type eq 'AAAA') { defined($addr= inet_pton(AF_INET6, $_)) or die "input:$.:$owner:invalid IPv6 address\n"; $data = inet_ntop(AF_INET6, $addr); } elsif ($type eq 'CNAME') { $data= domainsyntax_rel("input:$.:$owner:canonical name",$_)."."; } elsif ($type eq 'MX') { m/^(\d+)\s+(\S+)$/ or die "input:$.:$owner:invalid MX syntax\n"; ($pref,$target) = ($1,$2); $pref += 0; die "input:$.:$owner:invalid MX preference\n" if $pref<0 || $pref>65535; $target= domainsyntax_rel("input:$.:$owner:mail exchanger",$target); $data= "$pref $target."; } else { die "input:$.:$owner:unsupported RR type:$type\n"; } $owner_types{$owner}->{$type}= 1; print T "$write_owner $ttl $type $data\n" or die "write data to temp file:$!\n"; } close T or die "close RR data include:$!\n"; open STDIN, "< tmp/$$" or die "reopen RR data include:$!\n"; remove "tmp/$$" or die "close RR data include:$!\n"; chdir "zone,$zone" or die "chdir:$zone:$!\n"; exec "with-lock-ex","-w","Lock", "$libdir/update", $zone, $subdomain, @rates; die "execute update program:$!\n"; sub domainsyntax ($$) { my ($w,$d) = @_; return if eval { die "bad char:\`$&'\n" if $d =~ m/[^-.0-9a-z]/; $d= ".$d."; die "label starts with hyphen\n" if $d =~ m/\.\-/; die "label ends with hyphen\n" if $d =~ m/\-\./; die "empty label or dot at start or end\n" if $d =~ m/\.\./; die "label too long\n" if $d =~ m/\..{64,}\./; die "domain name too long\n" if length $d > 255; 1; }; die "$w:invalid domain name:\`$d':$@"; } sub domainsyntax_rel ($$) { my ($w,$d,$r) = @_; unless ($d =~ s/\.$//) { $d .= '.' unless $d =~ s/^\@$//; $d .= ($subdomain eq '@' ? "$zone" : "$subdomain.$zone"); } domainsyntax($w,$d); return $d; } work/dyndns/update0000755000000000000000000000363314141560754011451 0ustar #!/bin/bash # Copyright 1996-2013 Ian Jackson # Copyright 1998 David Damerell # Copyright 1999,2003 # Chancellor Masters and Scholars of the University of Cambridge # Copyright 2010 Tony Finch # # This 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 userv-utils; if not, see http://www.gnu.org/licenses/. set -e zone="$1" subdomain="$2" interval_min="$3" interval_avg="$4" interval_mem="$5" now=`date +%s` charge=0 case $subdomain in '@') files=_ ;; *) files=$subdomain ;; esac if test -f $files,timings && read lastup charge <$files,timings then if [ $now -lt $[ $lastup + $interval_min ] ]; then echo "wait $[ $lastup + $interval_min - $now ]" echo >&2 "must wait at least $interval_min between updates" exit 75 fi charge=$[ $charge + $interval_avg - ($now - $lastup) ] if [ $charge -gt $interval_mem ]; then echo "wait $[ $charge - $interval_mem ]" echo >&2 "must wait on average $interval_avg between updates" exit 75 fi if [ $charge -lt 0 ]; then charge=0; fi fi sort >$files,new if test -f $files,data then set +e diff >/dev/null $files,data $files,new diff=$? set -e if [ $diff = 0 ]; then echo 'unchanged'; exit 0; fi if [ $diff != 1 ]; then exit 1; fi fi echo $now $charge >$files,timings.new mv -f $files,timings.new $files,timings mv $files,new $files,data exec /usr/share/userv/dyndns/install $zone work/finger/0000755000000000000000000000000014141560754010207 5ustar work/finger/.gitignore0000644000000000000000000000011714141560754012176 0ustar config services finger-finger finger-notmyself finger-getprefs finger-setprefs work/git-daemon/0000755000000000000000000000000014141560754010761 5ustar work/git-daemon/Makefile0000644000000000000000000000311314141560754012417 0ustar # Makefile for userv-git-daemon # # This was written by Tony Finch and subsequently # heavily modified by Ian Jackson # You may do anything with it, at your own risk. # http://creativecommons.org/publicdomain/zero/1.0/ include ../settings.make gituser= userv-git varloggit= $(varlog)/git TARGETS= git-upload-pack inetd.conf git-daemon git-service logrotate SUBSTVARS= libuserv etcuserv varloggit gituser CONFIGS= $(services)/git-upload-pack \ $(etcuserv)/git-urlmap \ $(etcdir)/logrotate.d/userv-git-daemon all: $(TARGETS) sedscript: Makefile read-urlmap echo >$@.new '$(foreach f, $(SUBSTVARS), s,@$f@,$($f),g; )' echo >>$@.new '/@@READ_URLMAP@@/c\' @#' perl >>$@.new -pe 's/\\/\\\\/g; s/$$/\\/' $@.new; \ if test -x $<; then chmod +x $@.new; fi; \ mv -f $@.new $@ install: all mkdir -p $(libuserv) $(etcuserv) $(services) \ $(etcdir)/logrotate.d install -d -o $(gituser) -g adm $(varloggit) cp git-daemon git-service $(libuserv) cp git-upload-pack $(services)/git-upload-pack:new cp git-urlmap $(etcuserv)/git-urlmap:new cp logrotate $(etcdir)/logrotate.d/userv-git-daemon:new set -e; for f in $(CONFIGS); do \ if test -f $$f; then continue; fi; \ mv $$f:new $$f; \ done mkdocdir: mkdir -p $(docdir)/userv-git-daemon install-docs: mkdocdir cp README $(docdir)/userv-git-daemon/README install-examples: all mkdocdir cp inetd.conf $(docdir)/userv-git-daemon/inetd.conf distclean clean: rm -f $(TARGETS) *~ # end work/git-daemon/README0000644000000000000000000000461614141560754011650 0ustar userv-git-daemon is a replacement for the standard git daemon, which provides anonymous remote access to git repositories. It uses userv to invoke the service requested by the client, and users can configure it to map git:// URLs to repositories and enable and disable services as they see fit, without intervention from the system administrator. To install: ----------- Adjust the paths in ../settings.make as necessary. userv-git-daemon uses $(libuserv), $(etcuserv), and $(services). Type make install. Create a "userv-git" user that will run the outer part of the git-daemon. Ensure your /etc/services contains a line like "git 9418/tcp". Insert the inetd.conf fragment into your /etc/inetd.conf and tell inetd to reload. As a test user, create a 'public-git' directory, and copy a bare git repository into it, e.g. git clone --bare git://dotat.at/unifdef.git public-git/unifdef.git This repository should now be visible: git ls-remote git://localhost/~test/unifdef.git Operation: ---------- The userv-git-daemon is invoked by inetd which also tells it where to find its global git-urlmap config. The git-daemon parses the request from the network and uses the global git-urlmap config to determine which user will run the requested service. It invokes userv for the request to be performed. The most common service is git-upload-pack, which is confusingly named: it uploads from the repository to the network; other services supported by git are git-upload-archive and git-receive-pack. The git-daemon will pass any service beginning git- to userv. The userv configuration determines which services may be requested. This package includes example git-upload-pack service configurations. The service configuration uses the git-service script to run the service. It passes the global and per-user git-urlmap configs to the git-service script to determine where in the filesyetem the requested repository is. Later urlmap entries override the choices made by earlier ones. If a repository is located, the git-service script runs the requested service, which is simply the git program with the same name. Configuration: -------------- See "git-urlmap" for syntax description and an example. ---------------------------------------------- This was written by Tony Finch and subsequently heavily modified by Ian Jackson http://creativecommons.org/publicdomain/zero/1.0/ work/git-daemon/git-daemon.in0000755000000000000000000000456314141560754013350 0ustar #!/usr/bin/perl # # A git daemon with an added userv security boundary. # # This was written by Tony Finch and subsequently # heavily modified by Ian Jackson # http://creativecommons.org/publicdomain/zero/1.0/ use strict; use warnings; use POSIX; use Socket; use Sys::Syslog; BEGIN { if ($ARGV[0] =~ s/^-L//) { my $logfile= shift @ARGV; open STDERR, ">> $logfile" or die $!; } } sub ntoa { my $sockaddr = shift; return ('(local)') unless defined $sockaddr; my ($port,$addr) = sockaddr_in $sockaddr; $addr = inet_ntoa $addr; return ("[$addr]:$port",$addr,$port); } our ($client,$client_addr,$client_port) = ntoa getpeername STDIN; our ($server,$server_addr,$server_port) = ntoa getsockname STDIN; our ($service,$specpath,$spechost); printf STDERR "%s [$$] %s %s\n", strftime("%Y-%m-%d %H:%M:%S %Z", localtime), $server, $client; openlog 'userv-git-daemon', 'pid', 'daemon'; sub fail { syslog 'err', "$client @_"; exit } $SIG{ALRM} = sub { fail "timeout" }; alarm 30; sub xread { my $length = shift; my $buffer = ""; while ($length > length $buffer) { my $ret = sysread STDIN, $buffer, $length, length $buffer; fail "Expected $length bytes, got ".length $buffer if defined $ret and $ret == 0; fail "read: $!" if not defined $ret and $! != EINTR and $! != EAGAIN; } return $buffer; } my $hex_len = xread 4; fail "Bad hex in packet length" unless $hex_len =~ m|^[0-9a-fA-F]{4}$|; my $line = xread -4 + hex $hex_len; unless (($service,$specpath,$spechost) = $line =~ m|^(git-[a-z-]+) /*([!-~]+)\0host=([!-~]+)\0$|) { $line =~ s|[^ -~]+| |g; fail "Could not parse \"$line\"" } @@READ_URLMAP@@ fail "No global mapping for $uri" unless defined $serve_user; my ($hn,$ha,$at,$naddrs,@addrs) = gethostbyname $spechost; fail "hostname/address mismatch ($spechost $server_addr)" unless grep { $server_addr eq inet_ntoa $_ } @addrs; our @opts; push @opts, "-D$_=${$::{$_}}" for qw(service specpath spechost client client_addr client_port server server_addr server_port); fail "no user $serve_user" unless getpwnam($serve_user); syslog 'notice', "$client $service $uri $serve_user"; my @cmd = ('userv', '-t300', @opts, $serve_user, $service); no warnings; # suppress errors to stderr exec @cmd or fail "exec userv: $!"; # end work/git-daemon/git-service.in0000755000000000000000000000246114141560754013540 0ustar #!/usr/bin/perl # # userv-git-daemon service script # # This was written by Tony Finch and subsequently # heavily modified by Ian Jackson # http://creativecommons.org/publicdomain/zero/1.0/ use strict; use warnings; use POSIX; use Sys::Syslog; our ($client,$service,$specpath,$spechost,@opts); ${$::{$_}} = $ENV{"USERV_U_$_"} for qw(service specpath spechost client); openlog "userv-$service:$ENV{USER}", 'pid', 'daemon'; sub fail { syslog 'err', "$client @_"; exit } @@READ_URLMAP@@ fail "No user $ENV{USER} mapping for $uri" unless defined $serve_user; $serve_dir = "$ENV{HOME}/$serve_dir" unless $serve_dir =~ m|^/|; if (length $serve_repo) { my $inspect= $serve_repo; $inspect =~ s,^/,,; fail "Bad subdirectory $serve_repo" unless $inspect =~ m/$repo_regexp/o; fail "bad config - repo-regexp does not capture" unless defined $1; $serve_repo= "/$1"; } my $dir = $serve_dir.$serve_repo; my $path = $check_export ? "$dir/git-daemon-export-ok" : $dir; fail "$! $path" unless -e $path; syslog 'notice', "$client $uri $dir"; @opts = qw( --strict ) if @opts == 0 and $service eq 'git-upload-pack'; my @cmd = ($service =~ m|^(git)-(.*)$|, @opts, $dir); no warnings; # suppress errors to stderr exec @cmd or fail "exec $service: $!"; # end work/git-daemon/git-upload-pack.in0000644000000000000000000000070514141560754014274 0ustar # userv configuration for git-daemon git-upload-pack service # # This was written by Tony Finch # You may do anything with it, at your own risk. # http://creativecommons.org/publicdomain/zero/1.0/ if ( grep service-user-shell /etc/shells & glob service git-upload-pack & glob calling-user @gituser@ ) reset errors-to-syslog daemon error execute @libuserv@/git-service @etcuserv@/git-urlmap .userv/git-urlmap fi # end work/git-daemon/git-urlmap0000644000000000000000000000253614141560754012773 0ustar # Each line is one of: # # single-user [/] [] # matching requests will be handled by # and unless overridden by handled by # serving subdirectories of # # multi-user [/] # matching requests are only those those next # path element starts with ~. The # request will be handled by and unless # overridden by will be handled by # serving subdirectories of # ( must be a relative path) # # repo-regexp # For per-user service. Subrepos must match this # regexp, which must contain a single matching # group which is the filesystem pathname inside # the . The default is: # repo-regexp ^(w[-+._0-9A-Za-z]*/?\.git)$ # # [no-]require-git-daemon-export-ok # For per-user service. Default is no-. # # Last match, or last setting, wins. # s may start with ~ # here is an example, taken from chiark: # # single-user dotat.at fanf dotat-git # single-user git.chiark.greenend.org.uk webmaster /u2/git-repos # # multi-user cabal.greenend.org.uk cabal-git # multi-user git.chiark.greenend.org.uk public-git work/git-daemon/inetd.conf.in0000644000000000000000000000026214141560754013340 0ustar # Example inetd.conf line for the userv git daemon. git stream tcp nowait @gituser@ /usr/sbin/tcpd @libuserv@/git-daemon -L@varloggit@/userv-git-daemon.log @etcuserv@/git-urlmap work/git-daemon/logrotate.in0000644000000000000000000000012014141560754013302 0ustar @varloggit@/userv-git-daemon.log { rotate 7 daily missingok delaycompress } work/git-daemon/read-urlmap0000644000000000000000000000474614141560754013130 0ustar # -*- perl -*- # uses: # $specpath whole path from caller, minus any leading /s # $spechost host from caller # # sets: # # always: # $uri # # if match found for this host and path: # $serve_user username, or undef if no match (then other serve_* invalid) # $serve_dir directory as specified in config # $serve_repo subpath under $serve_dir _including_ leading / # # for use by user's service program # $repo_regexp # $require_exportok sub remain_path ($) { # return value matches {( / [^/]+ )+}x my ($vsubpath) = @_; syslog 'debug', sprintf "DEBUG remain_path %s $specpath", (defined $vsubpath ? $vsubpath : ''); return "/$specpath" if !defined $vsubpath; return "" if $vsubpath eq $specpath; return substr($specpath,length($vsubpath)) if substr($specpath,0,length($vsubpath)+1) eq "$vsubpath/"; return undef; } fail "no config ??" unless @ARGV; fail "no specpath ??" unless length $specpath; our $uri = "git://$spechost/$specpath"; our $repo_regexp= '^(\\w[-+._0-9A-Za-z]*/?\.git)$'; # stupid emacs '; our $check_export= 0; our ($serve_user, $serve_dir, $serve_repo); sub fexists ($) { my ($f) = @_; if (stat $f) { -f _ or fail "bad config $_ - not a file"; return 1; } else { $!==&ENOENT or fail "bad config $_ - could not stat: $!"; return 0; } } @ARGV = grep { fexists($_) } @ARGV; while (<>) { s/^\s*//; s/\s+$//; next unless m/\S/; next if m/^\#/; if (m{^ single-user \s+ (\S+?) (/\S*)? \s+ (\S+) (?: \s+ (\S+) )? $ }x) { my ($h,$v,$u,$d) = ($1,$2,$3,$4); next unless $h eq $spechost; $serve_repo= remain_path($v); next unless defined $serve_repo; $serve_user= $u; $serve_dir= $d; syslog 'debug', "DEBUG $ARGV:$. match". " $serve_user $serve_dir $serve_repo"; } elsif (m{^ multi-user \s+ (\S+?) (/\S*)? \s+ (\S+) $ }x) { my ($h,$v,$d) = ($1,$2,$3); next unless $1 eq $spechost; $serve_repo= remain_path($v); next unless defined $serve_repo; syslog 'debug', "DEBUG $ARGV:$. perhaps $serve_repo"; next unless $serve_repo =~ s{ ^/\~( [a-z][-+_0-9a-z]* )/ }{/}xi; $serve_user= $1; $serve_dir= $d; syslog 'debug', "DEBUG $ARGV:$. match". " $serve_user $serve_dir $serve_repo"; } elsif (m{^ repo-regexp \s+ (\S.*) $ }x) { $repo_regexp= $1; } elsif (m{^ (no-)?require-git-daemon-export-ok $ }x) { $check_export= !defined $1; } else { fail "config syntax error at $ARGV:$."; } } # end work/groupmanage/0000755000000000000000000000000014141560754011242 5ustar work/groupmanage/INSTALL0000644000000000000000000000321214141560754012271 0ustar groupmanage - installation instructions 'groupmanage' is /usr/local/bin/groupmanage - NOT setuid root -rwxr-xr-x 1 root root /usr/local/bin/groupmanage 'groupmanage.conf' is /etc/groupmanage.conf - edit to taste -rw-rw-r-- 1 root root /etc/groupmanage.conf 'services' is (typically) /etc/userv/services.d/groupmanage -rw-rw-r-- 1 root root /etc/userv/services.d/groupmanage Edit /etc/userv/system.default to add a line include-lookup service /etc/userv/services.d if you don't have one already. groupmanage depends on /etc/environment setting up a sensible PATH. /etc/grouplist must exist. We suggest inserting the comment # Syntax: # group:description:manager:maint-users:home There must be no blank lines in /etc/grouplist. groupmanage is part of userv-utils, which are Copyright 1996-2013 Ian Jackson Copyright 1998 David Damerell Copyright 1999,2003 Chancellor Masters and Scholars of the University of Cambridge Copyright 2010 Tony Finch All the utilities here are 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 userv-utils; if not, see http://www.gnu.org/licenses/. work/groupmanage/Makefile0000644000000000000000000000240414141560754012702 0ustar # Makefile # installation runes for groupmanage # Copyright 1996-2013 Ian Jackson # Copyright 1998 David Damerell # Copyright 1999,2003 # Chancellor Masters and Scholars of the University of Cambridge # Copyright 2010 Tony Finch # # This 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 userv-utils; if not, see http://www.gnu.org/licenses/. include ../settings.make install: mkdir -p $(bindir) cp groupmanage $(bindir)/. install-examples: mkdir -p $(etcdir) $(services) cp groupmanage.conf $(etcdir)/groupmanage.conf.example cp services $(services)/groupmanage.distrib install-docs: mkdir -p $(docdir)/groupmanage cp INSTALL groupmanage.text $(docdir)/groupmanage/. work/groupmanage/groupmanage0000755000000000000000000002655214141560754013507 0ustar #!/usr/bin/perl # # Copyright 1996-2013 Ian Jackson # Copyright 1998 David Damerell # Copyright 1999,2003 # Chancellor Masters and Scholars of the University of Cambridge # Copyright 2010 Tony Finch # # This 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 userv-utils; if not, see http://www.gnu.org/licenses/. sub usage { &unlock; &p_out; print(< [--info] groupmanage [ ...] groupmanage --create [ ...] actions: --clear --add ... --remove ... --manager-clear --manager-add ... --manager-remove ... --title --owner [root only] groupmanage is Copyright. It is free software, released under the GNU GPL v2 or later. There is NO WARRANTY. See the GPL for details. END exit(1); } @ARGV || &usage('too few arguments'); if ($>) { exec 'userv','root','groupmanage',@ARGV; &quit("unable to execute userv to gain root privilege: $!"); } chdir("/etc") || die "groupmanage: chdir /etc: $!\n"; $groupname= shift(@ARGV); $groupname =~ y/\n//d; $groupname =~ m/^\w[-0-9A-Za-z]*$/ || &quit("first argument is invalid - must be group name"); @ARGV || push(@ARGV,'--info'); $callinguser= exists $ENV{'USERV_UID'} ? $ENV{'USERV_UID'} : $<; %opt= ('user-create','0', 'user-create-minunameu','5', 'user-create-min','10000', 'user-create-max','19999', 'user-create-nameintitle','0', 'user-create-maxperu','5', 'group-file','group', 'gtmp-file','gtmp', 'grouplist-file','grouplist', 'name-regexp','', 'name-maxlen','8', 'admin-group','', 'finish-command',''); %ovalid= ('user-create','boolean', 'user-create-minunameu','number', 'user-create-min','number', 'user-create-max','number', 'user-create-nameintitle','boolean', 'user-create-maxperu','number', 'group-file','string', 'gtmp-file','string', 'grouplist-file','string', 'name-regexp','string', 'name-maxlen','number', 'admin-group','string', 'finish-command','string'); sub ov_boolean { $cov= $_ eq 'yes' ? 1 : $_ eq 'no' ? 0 : &quit("groupmanage.conf:$.: bad boolean value"); } sub ov_number { m/^[0-9]{1,10}$/ || &quit("groupmanage.conf:$.: bad numerical value"); } sub ov_string { } open(GMC,"groupmanage.conf") || &quit("read groupmanage.conf: $!"); while () { next if m/^\#/ || !m/\S/; s/\s*\n$//; s/^\s*([-0-9a-z]+)\s*// || &quit("groupmanage.conf:$.: bad option format"); $co= $1; defined($opt{$co}) || &quit("groupmanage.conf:$.: unknown option $co"); $cov= $_; $ovf= 'ov_'.$ovalid{$co}; &$ovf; $opt{$co}= $cov; } close(GMC); if ($ARGV[0] eq '--info') { @ARGV == 1 || &usage('no arguments allowed after --info'); &p_out; &load; &checkexists; &display; &p_out; exit(0); } sub naming { $callinguser || return; &p_out; if ($opt{'user-create-minunameu'}) { print(STDERR <- You must quote at least $opt{'user-create-minunameu'} chars of your username $createby (or all of it if it is shorter). END } if ($opt{'name-regexp'}) { print(STDERR <= $opt{'user-create-minunameu'} && substr($createby,0,length($upart)) eq $upart) || &naming; } else { $groupname =~ m/${opt{'name-regexp'}}/ || &naming; } $create= 1; shift(@ARGV); } &lock; &load; if ($create) { $bythisowner < $opt{'user-create-maxperu'} || &quit("you already have $bythisowner group(s)"); $groupfileix==-1 || &quit("group already exists, cannot create it"); $grouplistix==-1 || &quit("group is already in grouplist, cannot create it"); for ($gid= $opt{'user-create-min'}; $gid < $opt{'user-create-max'} && defined(getgrgid($gid)); $gid++) { } $gid <= $opt{'user-create-max'} || &quit("out of gids to use, contact admin"); $password=''; @members=($createby); $description= "${createby}'s -- user-defined, no title"; $owner= $createby; @managers=(); @members= ($createby); $groupfileix=$#groupfile+1; $grouplistix=$#grouplist+1; &p("created group $groupname"); } else { &checkexists; &p("modifying group $groupname"); } &weare($owner) || grep(&weare($_),@managers) || !$callinguser || &quit("you may not manage $groupname"); $action= 'none'; while (@ARGV) { $_= shift(@ARGV); if (m/^--(add|remove)$/) { $action= $1; $clist= 'members'; $what= 'member'; } elsif (m/^--owner$/) { !$callinguser || &quit("only root may change owner"); @ARGV || &usage("no username owner after --owner"); $owner= shift(@ARGV); &p("owner set to $owner"); } elsif (m/^--manager-(add|remove)$/) { $action= $1; $clist= 'managers'; $what= 'manager'; } elsif (m/^--clear$/) { &p('cleared list of members'); @members=(); $action='none'; $memc++; } elsif (m/^--manager-clear$/) { &p('cleared list of managers'); @managers=(); $action='none'; } elsif (m/^--title$/) { &weare($owner) || !$callinguser || &quit("only group's owner ($owner) may change title"); @ARGV || &usage("no title after --title"); $_= shift(@ARGV); y/\020-\176//cd; y/:\\//d; if ($opt{'user-create-nameintitle'} && $gid >= $opt{'user-create-min'} && $gid <= $opt{'user-create-max'}) { $_= "${owner}'s -- $_"; } $description= $_; &p("title set to $description"); } elsif (m/^-/) { &usage("unknown option $_"); } elsif (m/^\w[-0-9A-Za-z]*$/) { y/\n//d; $chgu=$_; defined(getpwnam($chgu)) || &quit("username $chgu does not exist"); eval "\@l = \@$clist; 1" || &quit("internal error: $@"); $already= grep($_ eq $chgu, @l); if ($action eq 'add') { if ($already) { &p("$chgu already $what"); } else { &p("added $what $chgu"); push(@l,$chgu); $memc+= ($clist eq 'members'); } } elsif ($action eq 'remove') { if ($already) { &p("removed $what $chgu"); @l= grep($_ ne $chgu, @l); $memc+= ($clist eq 'members'); } else { &p("$chgu is already not $what"); } } else { &usage("username found but no action to take for them"); } eval "\@$clist = \@l; 1" || &quit("internal error: $@"); } else { &usage("bad username or option $_"); } } &p("nb: a change to group membership only takes effect at the user's next login") if $memc; $groupfile[$groupfileix]= "$groupname:$password:$gid:".join(',',@members)."\n"; $grouplist[$grouplistix]= "$groupname:$description:$owner:".join(',',@managers).":$homedir\n"; &save($opt{'group-file'},@groupfile); &save($opt{'grouplist-file'},@grouplist); if ($opt{'finish-command'}) { !system($opt{'finish-command'}) || &quit("finish-command: $?"); } unlink($opt{'gtmp-file'}) || &quit("unlock group (remove gtmp): $!"); &p_out; exit(0); sub load { open(GF,"< $opt{'group-file'}") || &quit("read group: $!"); @groupfile=; close(GF); $groupfileix=-1; for ($i=0; $i<=$#groupfile; $i++) { $_= $groupfile[$i]; s/\n$//; next if m/^\#/; m/^(\w[-0-9A-Za-z]*):([^:]*):(\d+):([-0-9A-Za-z,]*)$/ || &quit("bad entry in group: $_"); $gname2gid{$1}=$3; next unless $1 eq $groupname; $groupfileix<0 || &quit("duplicate entries in group"); $groupfileix= $i; $password= $2; $gid= $3; @members= split(/,/,$4); } open(GL,"< $opt{'grouplist-file'}") || &quit("read grouplist: $!"); @grouplist=; close(GL); $grouplistix=-1; for ($i=0; $i<=$#grouplist; $i++) { $_= $grouplist[$i]; s/\n$//; next if m/^\#/; m/^(\w[-0-9A-Za-z]*):([^:]*):(\w[-0-9A-Za-z]*):([-0-9A-Za-z,]*):([^:]*)$/ || &quit("bad entry in grouplist: $_"); $bythisowner++ if ($create && $3 eq $createby && $gname2gid{$1} >= $opt{'user-create-min'} && $gname2gid{$1} <= $opt{'user-create-max'}); next unless $1 eq $groupname; $grouplistix<0 || &quit("duplicate entries in grouplist"); $grouplistix= $i; $description= $2; $owner= $3; $homedir= $5; @managers= split(/,/,$4); } } sub checkexists { $grouplistix>=0 || &quit("no entry in grouplist for $groupname"); $groupfileix>=0 || &quit("no entry in group for $groupname"); } sub weare { return 0 if $_[0] eq ''; @pw= getpwnam($_[0]); return @pw && $pw[2] == $callinguser ? 1 : 0; } sub save { $filename= shift(@_); unlink("$filename~"); open(DUMP,"> $filename.new") || &quit("create new $filename: $!"); print(DUMP @_) || &quit("write new $filename: $!"); close(DUMP) || &quit("close new $filename: $!"); link("$filename","$filename~") || &quit("create backup $filename: $!"); rename("$filename.new","$filename") || &quit("install new $filename: $!"); } sub quit { &unlock; &p_out; die "groupmanage: @_\n"; } sub lock { link($opt{'group-file'},$opt{'gtmp-file'}) || &quit("create gtmp: $!"); $locked++; } sub unlock { return unless $locked; $locked--; unlink($opt{'gtmp-file'}) || warn("unlock group file (remove gtmp): $!\n"); } sub display { print(<-, except that if is more than 4 characters only the first 4 need be given. All groups created by a user have that user's name in the title. Any one user may not create more than 5 groups for themselves. All group names must be less than 8 characters long, and a group once created can not easily be deleted because revoking access to a uid or gid on unix is very hard. Groups can be renamed with assistance from the system administrator. For more formal groups (for example, those corresponding to particular organisations, or which interact with system software eg mail delivery) should probably be created by the sysadmin on request and need not heed these restrictions; it might also be useful to create a home directory for shared files. When working with shared files, you should not remove (and should reinstate, if necessary) the setgid bit on the shared directories, and leave your umask set to allow group write (the default is 002). You'll then find that you're able to work in group filespace areas without having to ask other users to chmod files, or having to type incantations to switch between working on shared files and your personal files. userv-utils are Copyright 1996-2013 Ian Jackson Copyright 1998 David Damerell Copyright 1999,2003 Chancellor Masters and Scholars of the University of Cambridge Copyright 2010 Tony Finch All the utilities here are 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 userv-utils; if not, see http://www.gnu.org/licenses/. work/groupmanage/services0000644000000000000000000000024114141560754013005 0ustar # if ( grep calling-user-shell /etc/shells & glob service-user root ) reset set-environment no-suppress-args no-disconnect-hup execute groupmanage fi work/ipif/0000755000000000000000000000000014141560754007664 5ustar work/ipif/.gitignore0000644000000000000000000000011014141560754011644 0ustar service automech.[ch] udptunnel-forwarder udptunnel-reconf blowfishtest work/ipif/INSTALL.udptunnel0000644000000000000000000007143214141560754012741 0ustar This file, INSTALL, is a -*- text -*- file tutorial on how to * install userv ipif and udptunnel, * configure them to create a VPN tunnel between two hosts or networks, or * use udptunnel-reconf to create a multi-site VPN. See README for details of other available documentation. BUILD AND INSTALLATION INSTRUCTIONS ----------------------------------- 1. Install userv, 1.0.1 or later. This is in Debian GNU/Linux. 2. Make sure your Linux kernel has SLIP and TUN compiled in. 3. udptunnel works best if your ssh can do ssh-protocol-level keepalives. Currently these are only supported by using a special patch, which can be found (for various OpenSSH versions) at ftp.chiark.greenend.org.uk:/users/ian/openssh+protocolkeepalives. Pre-compiled Debian packages are available there too. 4. Obtain a fresh copy of userv-utils, if you haven't already. cd to ipif, and run `make' and (as root) `make install'. After you have done this the software will still not do anything, and by default userv ipif will not allow anyone (except root) to create network interfaces. The software will probably only work on Linux - in particular, userv ipif's service program (service.c) uses Linux-specific ways of setting up SLIP interfaces. It might be possible in principle to create alternatives for other platforms. UDPTUNNEL SETUP TUTORIAL ------------------------ 1. BACKGROUND INFORMATION Firstly, note that userv ipif and udptunnel are extremely flexible, as they aim to be `Lego brick' networking components. Many much more interesting configurations can be constructed than there is room to document here. If you want to do something strange, consult the README to locate the appropriate reference documentation. 1.1. About udptunnel udptunnel is point-to-point; you need a separate `invocation' for each pair of machines (or networks) you wish to connect. It is `one-shot': it will set up a tunnel and keep it going as long as it can, and then exit; if you want a permanent tunnel you must arrange to reinvoke udptunnel. It is asymmetric, in that one of the endpoints starts the tunnel, and the other sits and waits to be contacted. We'll call the active endpoint `alice' and the passive endpoint `bob'. Usually alice invokes udptunnel on bob via OpenSSH (`ssh'). udptunnel does not need root privilege to run. However, you do need to configure userv ipif to know that the user who will be running udptunnel is permitted to use the IP addresses and network ranges which will be used. So, though most of the configuration can be done as the normal users who will run udptunnel on each end, a small amount (editing /etc/userv/ipif-networks) needs to be done as root on each end - and the information configured as root needs to match up This tutorial will explain how to do these things. 1.2. About point-to-point tunnelling in general A tunnel is an _additional_ (in the case of udptunnel, encrypted) network link between a pair of machines. Packets are encapsulated at one end, sent over the real network between them, and decoded again at the other end. As with any network connection, it is possible to arrange for networks behind the endpoint machines to be able to communicate via the tunnel. Each endpoint machine will have at least two network interfaces: Firstly, the real `physical' interface through which the encapsulated packets will be really sent and received. Secondly, the `virtual' interface created by the tunnelling software, which represents its end of the (encrypted) tunnel link. The physical and virtual interfaces MUST have different addresses. Each endpoint machine may also have additional network interfaces; for example, it may be the router for a network which sits behind it, which an interface on that network, or it may be the endpoint for more than one tunnel. It is OK for several tunnels terminating at the same machine to use the same virtual address (provided that the tunnels are not `layered' on top of each other but are `in parallel'), and it is also OK to use as the virtual tunnel address a router's address on a private network which will be sent via the tunnel. 1.3. Diagram ____ ______________ ______________ ____ __( )__ |ALICE | | BOB| __( )__ ,' ` ' `. | _ | Tunnel | _ | ,' ` ' `. | alice | | |\\ ,- - - - - - - - - -. //| | | bob | `._private _.' | | || | | || | | `._private _.' | networks |==+--------'|| | Public | ||`--------+==| networks | | | | alice | Network | bob | | | `.~ ~.' | virtual +=============+ virtual | `.~ ~.' (__,'`.__) |______________|alice bob|______________| (__,'`.__) physical physical _ Key: HOSTNAME +===+ Actual Network |\\ Tunnel Descriptive Text ----- Data Flow | ||Endpoint host or network number - - - Encrypted Data Flow || 2. INFORMATION COLLECTION AND PRELIMINARY SETUP You will need to collect and/or decide upon various information, and make sure that your two endpoint systems can talk to each other over the public network. 2.1. Find out, or choose, private network numbers You need to make sure you know what all of the addresses in the above diagram are going to be. Usually you must choose the private and virtual addresses yourself: hosts on the private networks usually won't communicate with the global Internet other than through proxies or masquerading firewalls. You MUST choose from the reserved ranges in RFC1918, which are: 172.16.0.0/12 192.168.0.0/16 10.0.0.0/8 If you do not do so you'll end up reusing someone else's addresses, which can cause lots of hard-to-diagnose and embarrasing problems. You should CHOOSE RANDOMLY ! This makes sure that when you decide to connect your VPN to someone else's VPN, your network allocation numbers are unlikely to clash. If you both choose 192.168.0.0/24 you'll have to renumber (and will look like fools). To help with choosing random network numbers from RFC1918 space, the author maintains a web page at , which can pick network numbers for you. Additionally, there is a database there - people in Cambridge (in England) are encouraged to register their network address usage there. Please do not register in the database unless you're likely to want to connect your VPN to others already listed. 2.2. Find out, or choose, public network numbers These are usually specified by your ISP, either statically or dynamically assigned. If the active end (`alice physical') is dynamically assigned you can use the `Wait' option (see below) to avoid specifying it, but otherwise you will need to have some kind of script to find it each time you invoke udptunnel, or use a hostname which automatically tracks the source host using dynamic DNS. In some situations you may find yourself using a `public network' which is not actually the public Internet - for example, you may want to run one tunnel `through' another, or your `public network' is actually a `private', but not sufficiently secure, radio LAN. In this case you'll have to choose the addresses to use from RFC1918-space, as above. 2.3. Decide which user account(s) on alice and bob you will use These user accounts will see the plaintext for all network packets going over the tunnel and if compromised will be able steal or forge tunnel traffic. So, they should be reasonably secure. Let us assume that the account on alice is called Tbob, and the account on bob is called Talice. (NB that your system may not correctly handle usernames containing uppercase.) Each account should be in a group of its own, which will be used for the userv ipif access control. Arrange that Tbob@alice can ssh to Talice@bob without needing a passphrase or other user interaction. (Obviously, if you need to create accounts, edit groups, or change the sshd configuratioon, you may need to be root.) 2.4. Decide whether to use `udptunnel-reconf' There are two ways to set up a tunnel with udptunnel. Either you can simply give udptunnel the right command, by putting it in an appropriate script and arranging it to be called, or you can have a program `udptunnel-reconf' read some configuration files and do it for you. udptunnel-reconf is not as well documented, but its behaviour is somewhat more `cooked'. It is especially useful if you need to maintain many tunnels as part of an organised, multi-site, VPN. Using udptunnel directly is somewhat more flexible, and may be easier if you only want one tunnel. 3. SETUP INSTRUCTIONS - USING UDPTUNNEL-RECONF Edit or create the following files, as root: /etc/userv/vpn/sites /etc/userv/vpn/tunnels /etc/userv/vpn/global Run udptunnel-reconf, as root. This will create: /var/lib/userv/vpn/passive-sites /var/lib/userv/vpn/active-sites /var/lib/userv/vpn/command. It will also spit out to stdout two things: firstly, a list of suggested commands to put in your inittab, and secondly a suggested line to put in your /etc/userv/ipif-networks. Test that your setup is working, by running (one of) the /var/lib/userv/vpn/command. file(s) by hand - see section 5. If it works, you can put the relevant things in your inittab and say `init q'. To find out what all the configuration settings do, look at /usr/local/share/userv/udptunnel-vpn-defaults, which contains the default settings and shows where all the hooks are. Consult section 4 of this file to understand what the options to udptunnel do. 4. SETUP INSTRUCTIONS - INVOKING UDPTUNNEL DIRECTLY All of these steps can be done using the appropriate normal user accounts, unless otherwise indicated. 4.1. Configure the private network numbers in /etc/userv/ipif-networks (This step needs to be done as root.) On alice, in /etc/userv/ipif-networks, put ,=/32, , ,/32, , and for each of bob's private networks ,/, , You can leave out the /32 line if bob's virtual address is in one of bob's private networks. On bob, do the corresponding. In /etc/userv/ipif-networks, put ,=/32, , ,/32, , and for each of alice's private networks ,/, , Again, you can leave out if one of the virtual networks covers it. All the specifications in /etc/userv/ipif-networks must be numerical addresses - hostnames are not allowed. Also, the /32 indicating a specific host cannot be omitted. Note the use of `=' for each host's own virtual address, which indicates to userv ipif that it's OK for that gid to create a local interface with that address, but the address may not be assigned to a remote host or route. 4.2. Construct the udptunnel invocation (on alice) udptunnel has a long and complicated command line, rather than a configuration file. The best way to deal with this is to create a shell script which runs udptunnel with the right options. This script will live on alice in ~Tbob, and be run by Tbob. Let us call it `udptunnel-invoke-bob'. For the most basic setup, it should look something like this: #!/bin/sh set -e set -x udptunnel \ -e nonce -e timestamp/10/30 \ -e pkcs5/8 -e blowfish-cbcmac/128 -e blowfish-cbc/128 \ ,Any \ ,Command \ ,,1000,cslip \ 30,130,1800 \ \ ssh -o 'BatchMode yes' \ -v @ \ udptunnel You have to fill in the right values for things in angle brackets. (See also section 6. for a moderately complex example, below.) 4.4.1. Syntax of and These arguments to udptunnel are the network address ranges at each end which are to be connected via the tunnel. Let us consider just ; is just the same, but for bob's end. is a comma-separated list of networks specified as /. The network address must be numerical, and the prefix length must always be specified. If there are no private networks `behind' alice, ie the tunnel is just to connect alice to bob and things at bob's end, then specify `-' for . 4.4.2. IP masquerading (NAT) at alice's end If alice is behind a masquerading (NAT) firewall, you can still get it to work. You need to add an option `-m' before the other arguments. This will make udptunnel on alice tell udptunnel on bob to wait for alice's first encapsulated packet before deciding what alice's physcial address and port number are, as seen by bob. That way alice doesn't need to know what port number the NAT proxy will use. 4.4.3. Using fixed UDP port numbers (eg to make firewally happy) If alice is behind a firewall which will not allow incoming UDP to arbitrary ports, even when sent in reply to packets of alice's, you have to arrange for alice to use a fixed port number. Change ,Any \ to , \ udptunnel will need to be able to bind to the relevant port, so you must either (i) choose a port number over 1024, which risks other processes on alice accidentally using that port, (ii) run udptunnel as root on alice, or (iii) use authbind (authbind is a utility, included in Debian, which can allow non-root programs to bind to low ports in a controlled way). If bob is behind such a firewall too, you can replace ,Command \ with , \ 4.4.4. Clock skew and excessive delay The default configuration given above, which includes this -e nonce -e timestamp/10/30 \ will not work if there is more than 10s of clock skew between alice and bob's system clocks, or if the lag in either direction is more than 30s. It is best if your systems run with synchronised clocks (you can run NTP over the tunnel if necessary) and don't have such bad lag, of course. However, you can increase these parameters if you really want. To increase the tolerance to clock skew to some amount, make sure that both numbers are at least the amount of clock skew you're willing to tolerate. To increase the tolerance to delay it's only necessary to increase the second number. Warning: if you increase these numbers too much there is a risk that packets delayed or repeated by an attacker will be treated as genuine and cause communication or security problems. I would not recommend using a value more than 120 (2 minutes). If you really can't get reasonable clock synch at all, you can use sequence number replay detection instead of clock-based replay detection. Replace -e nonce -e timestamp/10/30 \ with -e sequence \ 4.4.5. Other things to tweak (it's usually safe to ignore this part) Do not mess with the `-e' parameters and arguments except as explained above, unless you are a cryptographer. 30,130,1800 are timeouts which control the `dead tunnel detection'. The first is the keepalive interval: when one end hasn't sent anything for that many seconds, it will send an empty keepalive packet. The second is the dead tunnel timeout: when one end hasn't received anything for that many seconds, it assumes the tunnel is dead and dies (the other end will then usually die shortly if it hasn't already). The third is the status reporting interval - at intervals of that many seconds each end will report (to udptunnel's stdout) that the tunnel is still open and give some statistics; these diagnostics also prevent the controlling ssh connection's entry in masquerading and firewall tables from timing out. 1000 (in ...,...,1000,cslip) is the MTU - the maximum size of packet which will be sent through the tunnel. It is best if this number is a certain amount smaller than the path MTU over the physical network, so that encapsulated packets do not get fragmented. (Each packet will be increased in size by 24 bytes + the size of a UDP and IP header + the effects of SLIP duplication of certain bytes.) 4.5. Testing your script After you've written your script, you should run it to see if it works. See section 5 for details. 4.6. Configure the tunnel to run automatically Now that the tunnel works if you invoke it by hand, it is time to arrange to run it automatically. If you want the tunnel to run over a dialup link only when the dialup link is up, then I'm afraid you'll have to arrange to start and kill it yourself, probably. I haven't set up such a configuration. More information about this for this document, if you manage to do it, would be good. So, I shall assume that you want the tunnel to be up all of the time (or at least, as much as possible). The best way to do this is to run it from `init', by setting it up in inittab. For example, you could put something like this in your inittab: t0:23:respawn:su Tbob -c ./udptunnel-invoke-bob 2>&1 | logger -p local2.info -t tunnel-bob (Note that if you have more than one tunnel the `id' field, at the start of the inittab line, must be different for each one.) This would use `su' to become bob and run the actual tunnelling software, and arrange for the diagnostic output to be sent to syslog with facility `local2' and priority `info', tagged with `tunnel-bob'. With an appropriate line in /etc/syslog.conf, such as local2.* /var/log/local2-all.log (remember that you have to use tabs in syslog.conf) this will produce, in /var/log/local2-all.log, all the diagnostics, including reassuring messages like this: Sep 18 00:27:48 alice tunnel-bob: udptunnel-forwarder: alice: tunnel still open: received 5262 packets, 5262 bytes Sep 18 00:28:44 alice tunnel-bob: udptunnel-forwarder: bob: tunnel still open: received 5280 packets, 5280 bytes 5. TESTING YOUR UDPTUNNEL INVOCATION SCRIPT 5.1. Invocation Log into alice as Tbob, and run ./udptunnel-invoke-bob. A great deal of diagnostic output will ensue. If all is well you will see two messages looking something like this udptunnel-forwarder: bob: tunnel open with peer 127.0.0.3:76543 udptunnel-forwarder: alice: tunnel open and the session will just sit there. This means it thinks it's working; go on to section 5.2. If it didn't say that, here are some debugging tips: * If it just sits there for a minute or two and then udptunnel times out, the physical packets aren't getting back and forth. Use tcpdump, check your firewall and routing (as below), and consult the sections above about NAT and firewalls. * If it bombed out, look for an error message in the diagnostics. There will be lots of `subprocess somethingorother exited with nonzero exit status 47', `no details received from remote' and the like, but these are probably not the ones you want to look at, because they're usually just consequences of some other failure. Permission denied. udptunnel - alice: fatal error: remote command failed (code ...) Tbob had trouble ssh'ing to Talice@bob. Check that the ssh configuration is set up, and test it separately. userv-ipif service: access denied for ...., .... udptunnel - alice: subprocess local command failed with code 2048 The arguments to udptunnel don't correspond to /etc/userv/ipif-networks on alice. Either the arguments to udptunnel or the ipif-networks file is wrong. (Or, if the message about `local command failed' mentions bob, look on bob.) udptunnel - alice: subprocess forwarder failed with code 14 The tunnel timed out - no packets were successfully received for 130 seconds. See 2.4.5 above for details of the timeout parameters. (NB, applies to `code 14' only.) usage errors from udptunnel or ssh, or sh: ...: unknown command Perhaps you dropped a \ from the udptunnel-invoke-bob script ? udptunnel not found, udptunnel-forwarder not found Check that the PATH includes /usr/local/bin. Noninteractive `ssh' invocations (ie, ones with a command specified) often have a different PATH. * Other messages: udptunnel-forwarder: alice: bad packet: blowfish-cbcmac: verify failed This can be caused by actual packet corruption on the physical network (or even by an actual hostile attack), but when using fixed port numbers these messages are common after the tunnel has died and been restarted: they correspond to packets from the previous invocation (which is usung different keys) being rejected because their checksums don't match. In this case they should go away in a minute or two. 5.2. Testing, once the tunnel claims to be working In another session on alice, you should be able to ping bob's virtual interface. If this works, test pinging between hosts on the private networks behind alice and bob. If all is well, go onto step 4. If not, here are some troubleshooting hints: * Use numerical addresses when testing. This eliminates DNS problems from your test strategy. * Use `ifconfig' and `route -n' on alice and bob to check that the interfaces and routes all look right. The tunnel will show up as a `sl' for some . * Use `tcpdump -n -i ' to watch the traffic go across some interface, to try to figure out where the traffic is going. Look both for the private traffic before it goes into the tunnel, and the physical traffic, to try to find out where it disappears. The diagnostics will tell you which physical ports it's using, something like this: udptunnel - alice: debug: using remote Wait,Wait local 131.111.232.108,1422 udptunnel - bob: debug: using remote 131.111.232.108,1422 local 195.224.38.6,2413 * alice and bob can see each other but the private networks can't ? Make sure alice and bob both have IP forwarding enabled. * Check your firewalls, if you have them. It's most helpful if your firewall configuration arranges to log rejected packets - without that, they can be a complete pain to debug. 6. DNS, firewall, mail, etc. When you have IP level connectivity between your two networks, you must also arrange for: * An appropriate firewall on each tunnel endpoint (to stop attacks from one network to another) and also at all the borders of each network (to stop traffic that is going to, or looks like it came from, the private networks). * DNS configuration so that hosts on both sides of the tunnel can see each other's names, addresses and other information. * Mail, news and other application protocols may need to be configured to use the private tunnel connectivity, rather than treating the other private network's names as being `elsewhere' and using unencrypted connectivity via the global Internet. How to do these things is beyond the scope of this document. 7. Example This example is the tunnel between chiark and Relativity. I'll quote it and explain the details, below. See also the comment at the top of udptunnel. authbind udptunnel \ -m \ -e nonce -e timestamp/10/30 -e pkcs5/8 \ -e blowfish-cbcmac/128 -e blowfish-cbc/128 \ davenant-external,410 \ chiark-public,Command \ 172.31.80.6,172.31.80.9,1000,cslip \ 30,120,1800 \ - 172.18.45.0/24 \ ssh -o 'ForwardAgent no' -o 'ForwardX11 no' \ -o 'BatchMode yes' \ -i ~ian/.ssh/identity -l ian \ -v chiark.greenend.org.uk \ udptunnel Because at Relativity the tunnel endpoint has to not be our firewall, because the firewall is a 386SX/16 and so not powerful enough, Relativity practically has to be the active partner in any tunnels it is involved in. This also necessitates the use of the `-m' option and various other things. Exposition of the example udptunnel invocation: > authbind udptunnel \ `authbind' is used because at Relativity the tunnel endpoint address has to be on a fixed port because our tunnel endpoint is not on the firewall system (if it's not on a fixed port we can't write a good firewall rule to let it through). The port we are using is port 410, a low port to prevent other processes `stealing' it, so root privilege or authbind is needed. > -m \ -m tells this invocation of udptunnel that its endpoint address and port (for encapsulated packets) are going to be NATted before the far end sees them. The effect is that instead of supplying this information to the far end, the far end is told to `wait and see'. This should not usually be used in other circumstances. (For full details see the comment at the top of udptunnel.) > -e nonce -e timestamp/10/30 -e pkcs5/8 \ > -e blowfish-cbcmac/128 -e blowfish-cbc/128 \ This is the crypto configuration. > davenant-external,410 \ This is the local physical address and port. davenant is the tunnel endpoint, and davenant-external is its public address (we run two networks on the wire at Relativity, an internal one and a public one). > chiark-public,Command \ This is the physical remote address and port. `Command' means find out the remote physical address or port by having udptunnel at the far end print its address and port when they have been allocated. Another possibility here is to use a fixed remote port number. The DNS at GR is configured so that just `chiark' means chiark via the tunnel, so we have to use chiark-public which means its public IP address. > 172.31.80.6,172.31.80.9,1000,cslip \ 172.31.80.6 is davenant's virtual address. 172.31.80.9 is chiark's virtual address for the Relativity tunnel. > 30,130,1800 \ These are the timing parameters. > - 172.18.45.0/24 \ No remote virtual networks are reachable via chiark. 172.18.45.0/24 is the Relativity house ethernet, which is to be reachable via the tunnel from chiark. > ssh -o 'ForwardAgent no' -o 'ForwardX11 no' \ > -o 'BatchMode yes' \ > -i ~ian/.ssh/identity -l ian \ > -v chiark.greenend.org.uk \ > udptunnel This is the ssh invocation to run udptunnel at the far end. At Relativity we put the udptunnel invocation in a file and run it out of inittab, like this: t0:235:respawn:/usr/local/sbin/really -u ian /usr/local/sbin/udptunnel-invoke 2>&1 | logger -p local2.info -t tunnel-chiark 8. Copyright notice This file is part of ipif, part of userv-utils userv-utils are Copyright 1996-2013 Ian Jackson Copyright 1998 David Damerell Copyright 1999,2003 Chancellor Masters and Scholars of the University of Cambridge Copyright 2010 Tony Finch All the utilities here are 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 userv-utils; if not, see http://www.gnu.org/licenses/. work/ipif/Makefile0000644000000000000000000000612014141560754011323 0ustar # Makefile for ipif/udptunnel stuff # This file is part of ipif, part of userv-util # # Copyright 1996-2013 Ian Jackson # Copyright 1998 David Damerell # Copyright 1999,2003 # Chancellor Masters and Scholars of the University of Cambridge # Copyright 2010 Tony Finch # # This 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 userv-utils; if not, see http://www.gnu.org/licenses/. include ../settings.make varlibvpn= $(varlibuserv)/vpn etcuserv= $(etcdir)/userv etcvpn= $(etcuserv)/vpn PROGRAM_TARGETS+= PROGRAM_TARGETS$(depr)+= udptunnel-forwarder udptunnel-reconf TARGETS+= service TARGETS$(depr)+= blowfishtest TARGETS+= $(PROGRAM_TARGETS) PROGRAMS$(depr)+= udptunnel PROGRAMS+= $(PROGRAM_TARGETS) DIRS+= $(libuserv) $(etcuserv) $(services) DIRS+= $(docdir)/userv-ipif DIRS+= $(etcuserv)/ipif-access DIRS$(depr)+= $(bindir) $(varlibvpn) $(shareuserv) SHAREFILES$(depr)+= udptunnel-vpn-config.m4 udptunnel-vpn-defaults MECHFILES= null pkcs5 timestamp sequence blowfish MECHOBJS= $(foreach m, $(MECHFILES), mech-$m.o) OBJS_FORWARD= forwarder.o $(MECHOBJS) blowfish.o automech.c utils.c OBJS_BFTEST= blowfishtest.o blowfish.o hex.o all: $(TARGETS) install: all mkdir -p $(DIRS) cp -b service $(libuserv)/ipif cp -b service-wrap $(libuserv)/ipif-access set -e; for f in $(PROGRAMS); do cp -b $$f $(bindir)/.; done cp ipif $(services)/ipif:new set -e; cd $(services); test -f ipif || mv ipif:new ipif set -e; for f in $(SHAREFILES); do cp $$f $(shareuserv)/.; done install-docs: sed -n '1,/^$$/p' service.c >$(docdir)/userv-ipif/service.c.txt install-examples: set -e; if [ "x$depr" = x ]; then \ mkdir -p $(etcvpn); \ cp *.example $(etcvpn)/.; \ fi udptunnel-reconf: udptunnel-reconf.pl Makefile perl -p \ -e ' print " ' \ -e '\$$shareuserv= \"$(shareuserv)\";\n ' \ -e '\$$etcvpn= \"$(etcvpn)\";\n ' \ -e '\$$varlibvpn= \"$(varlibvpn)\";\n" if m#^\# \@\@\@\-#; ' \ -e ' $$_="" if m/^\# \@\@\@\-/ .. m/^\# \-\@\@\@/; ' \ <$< >$@.new chmod +x $@.new mv -f $@.new $@ udptunnel-forwarder: $(OBJS_FORWARD) $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJS_FORWARD) blowfishtest: $(OBJS_BFTEST) $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJS_BFTEST) automech.h: automechgen.sh Makefile ./$< $(MECHFILES) automech.c: automech.h clean: rm -f *.o core automech.[ch] *~ ./#*# realclean distclean: clean rm -f $(TARGETS) forwarder.o $(MECHOBJS) automech.o utils.o: forwarder.h automech.h blowfish.o mech-blowfish.o blowfishtest.o: blowfish.h blowfishtest.o hex.o: hex.h work/ipif/README0000644000000000000000000000470314141560754010550 0ustar This directory contains: * userv ipif A userv service for allowing users to create network interfaces and handle the traffic for them. * udptunnel This is deprecated. A VPN tunnelling system based on userv ipif, which does encryption and can be used to join two hosts or whole networks. It uses its own nonstandard protocols, not IPSEC. Key setup is done via an ssh connection, and actual data packets are sent (encrypted) using UDP. With the appropriate configuration in userv ipif, users can be allowed to create VPN connections without needing root privilege. These tools have only been tested on GNU/Linux. The documentation available is: INSTALL.udptunnel Build and install instructions for both ipif and udptunnel, and tutorial on setting up userv ipif and udptunnel in the usual way. udptunnel (head comment) Configuration and invocation reference information for the udptunnel VPN facility. service.c (head comment) Reference information for userv ipif service, including syntax of /etc/userv/ipif-networks, and command line arguments to userv ipif. mech-*.c (head comments) Detailed specifications of encryption, padding, etc. transformations. For use by cryptographers only; otherwise, follow the advice elsewhere about what transformations to use. forwarder.c (head comment) Underlying UDP forwarding program invocation details. This program is normally invoked correctly by `udptunnel'. You should not need to read these details unless you are debugging or modifying udptunnel. This file is part of ipif, part of userv-utils userv-utils are Copyright 1996-2013 Ian Jackson Copyright 1998 David Damerell Copyright 1999,2003 Chancellor Masters and Scholars of the University of Cambridge Copyright 2010 Tony Finch All the utilities here are 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 userv-utils; if not, see http://www.gnu.org/licenses/. work/ipif/automechgen.sh0000755000000000000000000000255714141560754012533 0ustar #!/bin/sh # generates automech.h and automech.c # This file is part of ipif, part of userv-utils # # Copyright 1996-2013 Ian Jackson # Copyright 1998 David Damerell # Copyright 1999,2003 # Chancellor Masters and Scholars of the University of Cambridge # Copyright 2010 Tony Finch # # This 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 userv-utils; if not, see http://www.gnu.org/licenses/. exec >automech.c.new exec 3>automech.h.new cat <&3 <&3 done cat <&3 < * Copyright 1998 David Damerell * Copyright 1999,2003 * Chancellor Masters and Scholars of the University of Cambridge * Copyright 2010 Tony Finch * * This 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 userv-utils; if not, see http://www.gnu.org/licenses/. */ /* TODO: test with zero length key */ /* TODO: test with a through z as key and plain text */ #include #include #include "blowfish.h" static const blowfish__p init_p; static const blowfish__s init_s; #define S(x,i) (ek->s[i][((x)>>((3-i)<<3))&0x0ff]) #define F(x) (((S((x),0) + S((x),1)) ^ S((x),2)) + S((x),3)) #define ROUND(a,b,n) ((a) ^= F((b)) ^ ek->p[(n)]) #define GETWORD(p) (((p)[0]<<24)|((p)[1]<<16)|((p)[2]<<8)|((p)[3])) #define PUTWORD(w,p) ((p)[0]=(w)>>24,(p)[1]=(w)>>16,(p)[2]=(w)>>8,(p)[3]=(w)) static void encipher(const struct blowfish_expandedkey *ek, uint32_t *xlp, uint32_t *xrp) { uint32_t xl, xr; xl= *xlp; xr= *xrp; xl ^= ek->p[0]; ROUND (xr, xl, 1); ROUND (xl, xr, 2); ROUND (xr, xl, 3); ROUND (xl, xr, 4); ROUND (xr, xl, 5); ROUND (xl, xr, 6); ROUND (xr, xl, 7); ROUND (xl, xr, 8); ROUND (xr, xl, 9); ROUND (xl, xr, 10); ROUND (xr, xl, 11); ROUND (xl, xr, 12); ROUND (xr, xl, 13); ROUND (xl, xr, 14); ROUND (xr, xl, 15); ROUND (xl, xr, 16); xr ^= ek->p[17]; *xrp= xl; *xlp= xr; } static void decipher(const struct blowfish_expandedkey *ek, uint32_t *xlp, uint32_t *xrp) { uint32_t xl, xr; xl= *xlp; xr= *xrp; xl ^= ek->p[17]; ROUND (xr, xl, 16); ROUND (xl, xr, 15); ROUND (xr, xl, 14); ROUND (xl, xr, 13); ROUND (xr, xl, 12); ROUND (xl, xr, 11); ROUND (xr, xl, 10); ROUND (xl, xr, 9); ROUND (xr, xl, 8); ROUND (xl, xr, 7); ROUND (xr, xl, 6); ROUND (xl, xr, 5); ROUND (xr, xl, 4); ROUND (xl, xr, 3); ROUND (xr, xl, 2); ROUND (xl, xr, 1); xr ^= ek->p[0]; *xlp= xr; *xrp= xl; } void blowfish_loadkey(struct blowfish_expandedkey *ek, const uint8_t *key, int keybytes) { int i, j; uint32_t data, datal, datar; assert(keybytes>0 && keybytes<=BLOWFISH_MAXKEYBYTES); memcpy(ek->s,init_s,sizeof(ek->s)); for (i=0, j=0; i < BLOWFISH__PSIZE; i++) { data= (key[j]<<24) | (key[(j+1)%keybytes]<<16) | (key[(j+2)%keybytes]<<8) | key[(j+3)%keybytes]; ek->p[i]= init_p[i] ^ data; j = (j + 4) % keybytes; } datal= 0x00000000; datar= 0x00000000; for (i = 0; i < BLOWFISH__PSIZE; i += 2) { encipher(ek,&datal,&datar); ek->p[i]= datal; ek->p[i+1]= datar; } for (i = 0; i < 4; ++i) { for (j = 0; j < 256; j += 2) { encipher(ek,&datal,&datar); ek->s[i][j]= datal; ek->s[i][j+1]= datar; } } } void blowfish_encrypt(const struct blowfish_expandedkey *ek, const uint8_t plain[], uint8_t cipher[]) { uint32_t datal, datar; datal= GETWORD(plain); datar= GETWORD(plain+4); encipher(ek,&datal,&datar); PUTWORD(datal,cipher); PUTWORD(datar,cipher+4); } void blowfish_decrypt(const struct blowfish_expandedkey *ek, const uint8_t cipher[], uint8_t plain[]) { uint32_t datal, datar; datal= GETWORD(cipher); datar= GETWORD(cipher+4); decipher(ek,&datal,&datar); PUTWORD(datal,plain); PUTWORD(datar,plain+4); } void blowfish_cbc_setiv(struct blowfish_cbc_state *cs, const uint8_t iv[]) { cs->chainl= GETWORD(iv); cs->chainr= GETWORD(iv+4); } void blowfish_cbc_encrypt(struct blowfish_cbc_state *cs, const uint8_t plain[], uint8_t cipher[]) { uint32_t datal, datar; datal= GETWORD(plain); datar= GETWORD(plain+4); datal ^= cs->chainl; datar ^= cs->chainr; encipher(&cs->ek,&datal,&datar); cs->chainl= datal; cs->chainr= datar; PUTWORD(datal,cipher); PUTWORD(datar,cipher+4); } void blowfish_cbc_decrypt(struct blowfish_cbc_state *cs, const uint8_t cipher[], uint8_t plain[]) { uint32_t datal, datar, cipherl, cipherr; datal= GETWORD(cipher); datar= GETWORD(cipher+4); cipherl= datal; cipherr= datar; decipher(&cs->ek,&datal,&datar); datal ^= cs->chainl; datar ^= cs->chainr; cs->chainl= cipherl; cs->chainr= cipherr; PUTWORD(datal,plain); PUTWORD(datar,plain+4); } static const blowfish__p init_p= { 0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344, 0xa4093822, 0x299f31d0, 0x082efa98, 0xec4e6c89, 0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c, 0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917, 0x9216d5d9, 0x8979fb1b }; static const blowfish__s init_s= { { 0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7, 0xb8e1afed, 0x6a267e96, 0xba7c9045, 0xf12c7f99, 0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16, 0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e, 0x0d95748f, 0x728eb658, 0x718bcd58, 0x82154aee, 0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013, 0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef, 0x8e79dcb0, 0x603a180e, 0x6c9e0e8b, 0xb01e8a3e, 0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60, 0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440, 0x55ca396a, 0x2aab10b6, 0xb4cc5c34, 0x1141e8ce, 0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a, 0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e, 0xafd6ba33, 0x6c24cf5c, 0x7a325381, 0x28958677, 0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193, 0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032, 0xef845d5d, 0xe98575b1, 0xdc262302, 0xeb651b88, 0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239, 0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e, 0x21c66842, 0xf6e96c9a, 0x670c9c61, 0xabd388f0, 0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3, 0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98, 0xa1f1651d, 0x39af0176, 0x66ca593e, 0x82430e88, 0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe, 0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6, 0x4ed3aa62, 0x363f7706, 0x1bfedf72, 0x429b023d, 0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b, 0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7, 0xe3fe501a, 0xb6794c3b, 0x976ce0bd, 0x04c006ba, 0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463, 0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f, 0x6dfc511f, 0x9b30952c, 0xcc814544, 0xaf5ebd09, 0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3, 0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb, 0x5579c0bd, 0x1a60320a, 0xd6a100c6, 0x402c7279, 0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8, 0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab, 0x323db5fa, 0xfd238760, 0x53317b48, 0x3e00df82, 0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db, 0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573, 0x695b27b0, 0xbbca58c8, 0xe1ffa35d, 0xb8f011a0, 0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b, 0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790, 0xe1ddf2da, 0xa4cb7e33, 0x62fb1341, 0xcee4c6e8, 0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4, 0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0, 0xd08ed1d0, 0xafc725e0, 0x8e3c5b2f, 0x8e7594b7, 0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c, 0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad, 0x2f2f2218, 0xbe0e1777, 0xea752dfe, 0x8b021fa1, 0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299, 0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9, 0x165fa266, 0x80957705, 0x93cc7314, 0x211a1477, 0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf, 0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49, 0x00250e2d, 0x2071b35e, 0x226800bb, 0x57b8e0af, 0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa, 0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5, 0x83260376, 0x6295cfa9, 0x11c81968, 0x4e734a41, 0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915, 0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400, 0x08ba6fb5, 0x571be91f, 0xf296ec6b, 0x2a0dd915, 0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664, 0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a }, { 0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623, 0xad6ea6b0, 0x49a7df7d, 0x9cee60b8, 0x8fedb266, 0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1, 0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e, 0x3f54989a, 0x5b429d65, 0x6b8fe4d6, 0x99f73fd6, 0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1, 0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e, 0x09686b3f, 0x3ebaefc9, 0x3c971814, 0x6b6a70a1, 0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737, 0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8, 0xb03ada37, 0xf0500c0d, 0xf01c1f04, 0x0200b3ff, 0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd, 0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701, 0x3ae5e581, 0x37c2dadc, 0xc8b57634, 0x9af3dda7, 0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41, 0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331, 0x4e548b38, 0x4f6db908, 0x6f420d03, 0xf60a04bf, 0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af, 0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e, 0x5512721f, 0x2e6b7124, 0x501adde6, 0x9f84cd87, 0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c, 0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2, 0xef1c1847, 0x3215d908, 0xdd433b37, 0x24c2ba16, 0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd, 0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b, 0x043556f1, 0xd7a3c76b, 0x3c11183b, 0x5924a509, 0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e, 0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3, 0x771fe71c, 0x4e3d06fa, 0x2965dcb9, 0x99e71d0f, 0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a, 0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4, 0xf2f74ea7, 0x361d2b3d, 0x1939260f, 0x19c27960, 0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66, 0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28, 0xc332ddef, 0xbe6c5aa5, 0x65582185, 0x68ab9802, 0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84, 0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510, 0x13cca830, 0xeb61bd96, 0x0334fe1e, 0xaa0363cf, 0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14, 0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e, 0x648b1eaf, 0x19bdf0ca, 0xa02369b9, 0x655abb50, 0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7, 0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8, 0xf837889a, 0x97e32d77, 0x11ed935f, 0x16681281, 0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99, 0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696, 0xcdb30aeb, 0x532e3054, 0x8fd948e4, 0x6dbc3128, 0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73, 0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0, 0x45eee2b6, 0xa3aaabea, 0xdb6c4f15, 0xfacb4fd0, 0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105, 0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250, 0xcf62a1f2, 0x5b8d2646, 0xfc8883a0, 0xc1c7b6a3, 0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285, 0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00, 0x58428d2a, 0x0c55f5ea, 0x1dadf43e, 0x233f7061, 0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb, 0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e, 0xa6078084, 0x19f8509e, 0xe8efd855, 0x61d99735, 0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc, 0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9, 0xdb73dbd3, 0x105588cd, 0x675fda79, 0xe3674340, 0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20, 0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7 }, { 0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934, 0x411520f7, 0x7602d4f7, 0xbcf46b2e, 0xd4a20068, 0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af, 0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840, 0x4d95fc1d, 0x96b591af, 0x70f4ddd3, 0x66a02f45, 0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504, 0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a, 0x28507825, 0x530429f4, 0x0a2c86da, 0xe9b66dfb, 0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee, 0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6, 0xaace1e7c, 0xd3375fec, 0xce78a399, 0x406b2a42, 0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b, 0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2, 0x3a6efa74, 0xdd5b4332, 0x6841e7f7, 0xca7820fb, 0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527, 0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b, 0x55a867bc, 0xa1159a58, 0xcca92963, 0x99e1db33, 0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c, 0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3, 0x95c11548, 0xe4c66d22, 0x48c1133f, 0xc70f86dc, 0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17, 0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564, 0x257b7834, 0x602a9c60, 0xdff8e8a3, 0x1f636c1b, 0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115, 0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922, 0x85b2a20e, 0xe6ba0d99, 0xde720c8c, 0x2da2f728, 0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0, 0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e, 0x0a476341, 0x992eff74, 0x3a6f6eab, 0xf4f8fd37, 0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d, 0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804, 0xf1290dc7, 0xcc00ffa3, 0xb5390f92, 0x690fed0b, 0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3, 0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb, 0x37392eb3, 0xcc115979, 0x8026e297, 0xf42e312d, 0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c, 0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350, 0x1a6b1018, 0x11caedfa, 0x3d25bdd8, 0xe2e1c3c9, 0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a, 0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe, 0x9dbc8057, 0xf0f7c086, 0x60787bf8, 0x6003604d, 0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc, 0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f, 0x77a057be, 0xbde8ae24, 0x55464299, 0xbf582e61, 0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2, 0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9, 0x7aeb2661, 0x8b1ddf84, 0x846a0e79, 0x915f95e2, 0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c, 0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e, 0xb77f19b6, 0xe0a9dc09, 0x662d09a1, 0xc4324633, 0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10, 0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169, 0xdcb7da83, 0x573906fe, 0xa1e2ce9b, 0x4fcd7f52, 0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027, 0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5, 0xf0177a28, 0xc0f586e0, 0x006058aa, 0x30dc7d62, 0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634, 0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76, 0x6f05e409, 0x4b7c0188, 0x39720a3d, 0x7c927c24, 0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc, 0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4, 0x1e50ef5e, 0xb161e6f8, 0xa28514d9, 0x6c51133c, 0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837, 0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0 }, { 0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b, 0x5cb0679e, 0x4fa33742, 0xd3822740, 0x99bc9bbe, 0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b, 0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4, 0x5748ab2f, 0xbc946e79, 0xc6a376d2, 0x6549c2c8, 0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6, 0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304, 0xa1fad5f0, 0x6a2d519a, 0x63ef8ce2, 0x9a86ee22, 0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4, 0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6, 0x2826a2f9, 0xa73a3ae1, 0x4ba99586, 0xef5562e9, 0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59, 0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593, 0xe990fd5a, 0x9e34d797, 0x2cf0b7d9, 0x022b8b51, 0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28, 0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c, 0xe029ac71, 0xe019a5e6, 0x47b0acfd, 0xed93fa9b, 0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28, 0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c, 0x15056dd4, 0x88f46dba, 0x03a16125, 0x0564f0bd, 0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a, 0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319, 0x7533d928, 0xb155fdf5, 0x03563482, 0x8aba3cbb, 0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f, 0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991, 0xea7a90c2, 0xfb3e7bce, 0x5121ce64, 0x774fbe32, 0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680, 0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166, 0xb39a460a, 0x6445c0dd, 0x586cdecf, 0x1c20c8ae, 0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb, 0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5, 0x72eacea8, 0xfa6484bb, 0x8d6612ae, 0xbf3c6f47, 0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370, 0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d, 0x4040cb08, 0x4eb4e2cc, 0x34d2466a, 0x0115af84, 0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048, 0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8, 0x611560b1, 0xe7933fdc, 0xbb3a792b, 0x344525bd, 0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9, 0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7, 0x1a908749, 0xd44fbd9a, 0xd0dadecb, 0xd50ada38, 0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f, 0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c, 0xbf97222c, 0x15e6fc2a, 0x0f91fc71, 0x9b941525, 0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1, 0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442, 0xe0ec6e0e, 0x1698db3b, 0x4c98a0be, 0x3278e964, 0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e, 0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8, 0xdf359f8d, 0x9b992f2e, 0xe60b6f47, 0x0fe3f11d, 0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f, 0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299, 0xf523f357, 0xa6327623, 0x93a83531, 0x56cccd02, 0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc, 0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614, 0xe6c6c7bd, 0x327a140a, 0x45e1d006, 0xc3f27b9a, 0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6, 0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b, 0x53113ec0, 0x1640e3d3, 0x38abbd60, 0x2547adf0, 0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060, 0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e, 0x1948c25c, 0x02fb8a8c, 0x01c36ae4, 0xd6ebe1f9, 0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f, 0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6 } }; work/ipif/blowfish.h0000644000000000000000000000443414141560754011657 0ustar /* * This file is part of ipif, part of userv-utils * * Copyright 1996-2013 Ian Jackson * Copyright 1998 David Damerell * Copyright 1999,2003 * Chancellor Masters and Scholars of the University of Cambridge * Copyright 2010 Tony Finch * * This 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 userv-utils; if not, see http://www.gnu.org/licenses/. */ #ifndef BLOWFISH__H_INCLUDED #define BLOWFISH__H_INCLUDED #include #define BLOWFISH_BLOCKBYTES 8 #define BLOWFISH_MAXKEYBYTES 56 #define BLOWFISH__N 16 #define BLOWFISH__PSIZE BLOWFISH__N+2 typedef uint32_t blowfish__p[BLOWFISH__PSIZE]; typedef uint32_t blowfish__s[4][256]; struct blowfish_expandedkey { blowfish__p p; blowfish__s s; }; /* It's ok to pass the [_cbc]_(en|de)crypt functions the same * input and output pointers. */ void blowfish_loadkey(struct blowfish_expandedkey *ek, const uint8_t *key, int keybytes); void blowfish_encrypt(const struct blowfish_expandedkey *ek, const uint8_t plain[BLOWFISH_BLOCKBYTES], uint8_t cipher[BLOWFISH_BLOCKBYTES]); void blowfish_decrypt(const struct blowfish_expandedkey *ek, const uint8_t cipher[BLOWFISH_BLOCKBYTES], uint8_t plain[BLOWFISH_BLOCKBYTES]); struct blowfish_cbc_state { struct blowfish_expandedkey ek; uint32_t chainl, chainr; }; void blowfish_cbc_setiv(struct blowfish_cbc_state *cs, const uint8_t iv[BLOWFISH_BLOCKBYTES]); void blowfish_cbc_encrypt(struct blowfish_cbc_state *cs, const uint8_t plain[BLOWFISH_BLOCKBYTES], uint8_t cipher[BLOWFISH_BLOCKBYTES]); void blowfish_cbc_decrypt(struct blowfish_cbc_state *cs, const uint8_t cipher[BLOWFISH_BLOCKBYTES], uint8_t plain[BLOWFISH_BLOCKBYTES]); #endif work/ipif/blowfish.vectors0000644000000000000000000000724614141560754013121 0ustar # ecb # OR # key # iv # plain # cbc ecb 0000000000000000 0000000000000000 4EF997456198DD78 ecb FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFF 51866FD5B85ECB8A ecb 3000000000000000 1000000000000001 7D856F9A613063F2 ecb 1111111111111111 1111111111111111 2466DD878B963C9D ecb 0123456789ABCDEF 1111111111111111 61F9C3802281B096 ecb 1111111111111111 0123456789ABCDEF 7D0CC630AFDA1EC7 ecb 0000000000000000 0000000000000000 4EF997456198DD78 ecb FEDCBA9876543210 0123456789ABCDEF 0ACEAB0FC6A0A28D ecb 7CA110454A1A6E57 01A1D6D039776742 59C68245EB05282B ecb 0131D9619DC1376E 5CD54CA83DEF57DA B1B8CC0B250F09A0 ecb 07A1133E4A0B2686 0248D43806F67172 1730E5778BEA1DA4 ecb 3849674C2602319E 51454B582DDF440A A25E7856CF2651EB ecb 04B915BA43FEB5B6 42FD443059577FA2 353882B109CE8F1A ecb 0113B970FD34F2CE 059B5E0851CF143A 48F4D0884C379918 ecb 0170F175468FB5E6 0756D8E0774761D2 432193B78951FC98 ecb 43297FAD38E373FE 762514B829BF486A 13F04154D69D1AE5 ecb 07A7137045DA2A16 3BDD119049372802 2EEDDA93FFD39C79 ecb 04689104C2FD3B2F 26955F6835AF609A D887E0393C2DA6E3 ecb 37D06BB516CB7546 164D5E404F275232 5F99D04F5B163969 ecb 1F08260D1AC2465E 6B056E18759F5CCA 4A057A3B24D3977B ecb 584023641ABA6176 004BD6EF09176062 452031C1E4FADA8E ecb 025816164629B007 480D39006EE762F2 7555AE39F59B87BD ecb 49793EBC79B3258F 437540C8698F3CFA 53C55F9CB49FC019 ecb 4FB05E1515AB73A7 072D43A077075292 7A8E7BFA937E89A3 ecb 49E95D6D4CA229BF 02FE55778117F12A CF9C5D7A4986ADB5 ecb 018310DC409B26D6 1D9D5C5018F728C2 D1ABB290658BC778 ecb 1C587F1C13924FEF 305532286D6F295A 55CB3774D13EF201 ecb 0101010101010101 0123456789ABCDEF FA34EC4847B268B2 ecb 1F1F1F1F0E0E0E0E 0123456789ABCDEF A790795108EA3CAE ecb E0FEE0FEF1FEF1FE 0123456789ABCDEF C39E072D9FAC631D ecb 0000000000000000 FFFFFFFFFFFFFFFF 014933E0CDAFF6E4 ecb FFFFFFFFFFFFFFFF 0000000000000000 F21E9A77B71C49BC ecb 0123456789ABCDEF 0000000000000000 245946885754369A ecb FEDCBA9876543210 FFFFFFFFFFFFFFFF 6B5C5A9C5D9E0A5A ecb F0 FEDCBA9876543210 F9AD597C49DB005E ecb F0E1 FEDCBA9876543210 E91D21C1D961A6D6 ecb F0E1D2 FEDCBA9876543210 E9C2B70A1BC65CF3 ecb F0E1D2C3 FEDCBA9876543210 BE1E639408640F05 ecb F0E1D2C3B4 FEDCBA9876543210 B39E44481BDB1E6E ecb F0E1D2C3B4A5 FEDCBA9876543210 9457AA83B1928C0D ecb F0E1D2C3B4A596 FEDCBA9876543210 8BB77032F960629D ecb F0E1D2C3B4A59687 FEDCBA9876543210 E87A244E2CC85E82 ecb F0E1D2C3B4A5968778 FEDCBA9876543210 15750E7A4F4EC577 ecb F0E1D2C3B4A596877869 FEDCBA9876543210 122BA70B3AB64AE0 ecb F0E1D2C3B4A5968778695A FEDCBA9876543210 3A833C9AFFC537F6 ecb F0E1D2C3B4A5968778695A4B FEDCBA9876543210 9409DA87A90F6BF2 ecb F0E1D2C3B4A5968778695A4B3C FEDCBA9876543210 884F80625060B8B4 ecb F0E1D2C3B4A5968778695A4B3C2D FEDCBA9876543210 1F85031C19E11968 ecb F0E1D2C3B4A5968778695A4B3C2D1E FEDCBA9876543210 79D9373A714CA34F ecb F0E1D2C3B4A5968778695A4B3C2D1E0F FEDCBA9876543210 93142887EE3BE15C ecb F0E1D2C3B4A5968778695A4B3C2D1E0F00 FEDCBA9876543210 03429E838CE2D14B ecb F0E1D2C3B4A5968778695A4B3C2D1E0F0011 FEDCBA9876543210 A4299E27469FF67B ecb F0E1D2C3B4A5968778695A4B3C2D1E0F001122 FEDCBA9876543210 AFD5AED1C1BC96A8 ecb F0E1D2C3B4A5968778695A4B3C2D1E0F00112233 FEDCBA9876543210 10851C0E3858DA9F ecb F0E1D2C3B4A5968778695A4B3C2D1E0F0011223344 FEDCBA9876543210 E6F51ED79B9DB21F ecb F0E1D2C3B4A5968778695A4B3C2D1E0F001122334455 FEDCBA9876543210 64A6E14AFD36B46F ecb F0E1D2C3B4A5968778695A4B3C2D1E0F00112233445566 FEDCBA9876543210 80C7D7D45A5479AD ecb F0E1D2C3B4A5968778695A4B3C2D1E0F0011223344556677 FEDCBA9876543210 05044B62FA52D080 key 0123456789ABCDEFF0E1D2C3B4A59687 iv FEDCBA9876543210 plain 37363534333231204E6F77206973207468652074696D6520666F722000000000 cbc 6B77B4D63006DEE605B156E27403979358DEB9E7154616D959F1652BD5FF92CC work/ipif/blowfishspeed.c0000644000000000000000000000415714141560754012675 0ustar /* * This file is part of ipif, part of userv-utils * * Copyright 1996-2013 Ian Jackson * Copyright 1998 David Damerell * Copyright 1999,2003 * Chancellor Masters and Scholars of the University of Cambridge * Copyright 2010 Tony Finch * * This 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 userv-utils; if not, see http://www.gnu.org/licenses/. */ #include #include #include #include "blowfish.h" static void checkrw(int r, int exp_r, const char *op, FILE *f) { if (ferror(f)) { perror(op); exit(3); } if (feof(f)) { fprintf(stderr,"unexpected eof on %s\n",op); exit(2); } assert(r==exp_r); } int main(void) { struct blowfish_cbc_state cbc; unsigned char keybuf[BLOWFISH_MAXKEYBYTES], ivbuf[BLOWFISH_BLOCKBYTES]; unsigned char ibuf[BLOWFISH_BLOCKBYTES], obuf[BLOWFISH_BLOCKBYTES]; int r; r= fread(keybuf,1,sizeof(keybuf),stdin); checkrw(r,sizeof(keybuf),"input",stdin); blowfish_loadkey(&cbc.ek,keybuf,sizeof(keybuf)); r= fread(ibuf,1,sizeof(ivbuf),stdin); checkrw(r,sizeof(ivbuf),"input",stdin); blowfish_cbc_setiv(&cbc,ivbuf); for (;;) { r= fread(ibuf,1,sizeof(ibuf),stdin); if (r=0) break; checkrw(r,sizeof(ibuf),"input",stdin); blowfish_cbc_encrypt(&cbc,ibuf,obuf); r= fwrite(obuf,1,sizeof(obuf),stdout); checkrw(r,sizeof(obuf),"output",stdout); } memset(ibuf+r,sizeof(ibuf)-r,sizeof(ibuf)-r); blowfish_cbc_encrypt(&cbc,ibuf,obuf); r= fwrite(obuf,1,sizeof(obuf),stdout); checkrw(r,sizeof(obuf),"output",stdout); return 0; }; work/ipif/blowfishtest.c0000644000000000000000000001115614141560754012551 0ustar /* * test program for blowfish; very hard to use (sorry!) */ /* * This file is part of ipif, part of userv-utils * * Copyright 1996-2013 Ian Jackson * Copyright 1998 David Damerell * Copyright 1999,2003 * Chancellor Masters and Scholars of the University of Cambridge * Copyright 2010 Tony Finch * * This 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 userv-utils; if not, see http://www.gnu.org/licenses/. */ #include #include #include #include #include "blowfish.h" #include "hex.h" int main(void) { char buf[200], keybuf[200], plainbuf[200], cipherbuf[200], comparebuf[200], ivbuf[200]; char keytxt[sizeof(buf)+1], plaintxt[sizeof(buf)+1], ciphertxt[sizeof(buf)+1]; uint8_t key[BLOWFISH_MAXKEYBYTES*2], plain[100], cipher[100], compare[100]; uint8_t iv[BLOWFISH_BLOCKBYTES]; int keysz, plainsz, ciphersz, cskey, csiv, csplain, i; struct blowfish_expandedkey ek; struct blowfish_cbc_state cs; setvbuf(stdout,0,_IOLBF,BUFSIZ); buf[sizeof(buf)-2]=0; keytxt[sizeof(buf)]= 0; plaintxt[sizeof(buf)]= 0; ciphertxt[sizeof(buf)]= 0; cskey= csiv= csplain= 0; while (fgets(buf,sizeof(buf),stdin)) { if (buf[sizeof(buf)-2]) { fprintf(stderr,"line too long %s...\n",buf); exit(1); } if (sscanf(buf,"ecb %s %s %s\n",keytxt,plaintxt,ciphertxt) ==3) { unhex("ecb key",keytxt,key,&keysz,1,sizeof(key)); unhex("ecb plain",plaintxt,plain,0,BLOWFISH_BLOCKBYTES,BLOWFISH_BLOCKBYTES); unhex("ecb cipher",ciphertxt,cipher,0,BLOWFISH_BLOCKBYTES,BLOWFISH_BLOCKBYTES); printf("ecb %s %s %s\n", tohex(key,keysz,keybuf), tohex(plain,BLOWFISH_BLOCKBYTES,plainbuf), tohex(cipher,BLOWFISH_BLOCKBYTES,cipherbuf)); blowfish_loadkey(&ek,key,keysz); blowfish_encrypt(&ek,plain,compare); if (memcmp(cipher,compare,BLOWFISH_BLOCKBYTES)) { fprintf(stderr,"encryption mismatch - got %s\n", tohex(compare,BLOWFISH_BLOCKBYTES,comparebuf)); exit(1); } blowfish_decrypt(&ek,cipher,compare); if (memcmp(plain,compare,BLOWFISH_BLOCKBYTES)) { fprintf(stderr,"decryption mismatch - got %s\n", tohex(compare,BLOWFISH_BLOCKBYTES,comparebuf)); exit(1); } } else if (sscanf(buf,"key %s\n",keytxt)) { unhex("key",keytxt,key,&keysz,1,sizeof(key)); blowfish_loadkey(&cs.ek,key,keysz); cskey= 1; } else if (sscanf(buf,"iv %s\n",keytxt)) { unhex("iv",keytxt,iv,0,BLOWFISH_BLOCKBYTES,BLOWFISH_BLOCKBYTES); csiv= 1; } else if (sscanf(buf,"plain %s\n",plaintxt)) { unhex("plain",plaintxt,plain,&plainsz,0,sizeof(plain)); csplain= 1; } else if (sscanf(buf,"cbc %s\n",ciphertxt)) { if (!cskey || !csiv || !csplain) { fprintf(stderr,"failed to specify%s%s%s\n", cskey ? "" : " key", csiv ? "" : " iv", csplain ? "" : " plain"); exit(1); } unhex("cbc cipher",ciphertxt,cipher,&ciphersz,0,sizeof(cipher)); printf("key %s\niv %s\nplain %s\ncipher %s\n", tohex(key,keysz,keybuf), tohex(iv,BLOWFISH_BLOCKBYTES,ivbuf), tohex(plain,plainsz,plainbuf), tohex(cipher,ciphersz,cipherbuf)); if (plainsz % BLOWFISH_BLOCKBYTES || ciphersz % BLOWFISH_BLOCKBYTES || plainsz != ciphersz) { fprintf(stderr,"size mismatch plain=%d cipher=%d block=%d\n", plainsz,ciphersz,BLOWFISH_BLOCKBYTES); exit(1); } blowfish_cbc_setiv(&cs,iv); for (i=0; i * * * * [] * | [ ...] * | [ ...] * '' * * Remote addr may '' to mean wait to receive a packet and reply to * whereever we get a good packet from first, in which case port * should not be specified. * * is zero or more of * w means generate and write encdec keys, rather than reading them * K means do crypto debug (use with care!) * * encdec keys datastream has keys for packets from key datastream * writer to reader first, then keys for packets from reader to * writer. * * Every addr or port must be numeric. There is very little argument checking. * * Exit status: * SIGALARM timed out * 0 terminated due to outbound packet stream EOF * 4 other error * 8 system problem * 12 usage error * 16 bad trouble */ /* * This file is part of ipif, part of userv-utils * * Copyright 1996-2013 Ian Jackson * Copyright 1998 David Damerell * Copyright 1999,2003 * Chancellor Masters and Scholars of the University of Cambridge * Copyright 2010 Tony Finch * * This 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 userv-utils; if not, see http://www.gnu.org/licenses/. */ #include #include #include #include #include #include #include #include #include #include #include #include "forwarder.h" #define MAXMECHS 10 static size_t buffer_size; static struct utsname uname_result; static const char *opt_chars; static int public_local_fd, private_in_fd, private_out_fd; static int mtu2, keepalive, timeout, reannounce; static int public_remote_specd; static struct sockaddr_in public_remote; static int encdec_keys_fd, encdec_keys_write, crypto_debug; static int n_mechs; static const struct mechanism *mechs[MAXMECHS]; static struct mechdata *md_in[MAXMECHS], *md_out[MAXMECHS]; static int maxprefix, maxsuffix; static struct buffer buf_in, buf_out; static unsigned char *accum_buf; static size_t accum_used, accum_avail; static time_t nextsendka; static void cdebug(int mechno /*or -1*/, const char *msg) { if (!crypto_debug) return; printf("%-8.8s: CRYPTO: %-20s %s\n", uname_result.nodename, mechno >= 0 ? mechs[mechno]->name : "", msg); } static void cdebughex(int mechno /*or -1*/, const char *msg, const void *ptr, size_t sz, size_t skipbefore, int spc_offset, int dot_offset) { const unsigned char *p; size_t i; unsigned j= dot_offset; if (!crypto_debug) return; printf("%-8.8s: CRYPTO: %-20s %-10s", uname_result.nodename, mechno >= 0 ? mechs[mechno]->name : "", msg); for (i=0; istart, buf->size, buf->start - buf->base, spc_offset, dot_offset); } void get_random(void *ptr, size_t sz) { static FILE *randfile; size_t r; if (!randfile) { randfile= fopen("/dev/urandom","rb"); if (!randfile && errno==ENOENT) randfile= fopen("/dev/random","rb"); if (!randfile) sysfail("open random number generator"); } r= fread(ptr,1,sz,randfile); if (r != sz) (ferror(randfile) ? sysfail : fail)("cannot read random number generator"); cdebughex(-1, "get_random", ptr, sz, 0,0,0); } void random_key(void *ptr, size_t sz) { if (encdec_keys_write) { get_random(ptr,sz); write_must(encdec_keys_fd,ptr,sz,"write keys datastream"); } else { read_must(encdec_keys_fd,ptr,sz,"read keys datastream"); cdebughex(-1, "random_key", ptr, sz, 0,0,0); } } static void setnonblock(int fd, int nonblock) { int r; r= fcntl(fd,F_GETFL); if (r==-1) sysfail("fcntl F_GETFL"); r= fcntl(fd,F_SETFL, nonblock ? r|O_NONBLOCK : r&~O_NONBLOCK); if (r==-1) sysfail("fcntl F_SETFL"); } static const struct mechanism *find_mech(const char *name) { const struct mechanism *mech, *const *mechlist; for (mechlist= mechanismlists; *mechlist; mechlist++) for (mech= *mechlist; mech->name; mech++) if (!strcmp(mech->name,name)) return mech; fprintf(stderr,"%s: unknown mechanism: %s\n",programid,name); exit(4); } static void inbound(void) { static int any_recvd; static time_t nextreann; static unsigned long npackets, nbytes; struct sockaddr_in this_saddr; size_t this_saddrlen; int r, i, different; const char *emsg; buf_in.start= buf_in.base+1; buf_in.size= buffer_size-2; setnonblock(public_local_fd,1); this_saddrlen= sizeof(this_saddr); r= recvfrom(public_local_fd, buf_in.start, buf_in.size, 0, &this_saddr, &this_saddrlen); if (!r) { diag("empty ciphertext"); return; } if (r<0) { if (errno != EAGAIN && errno != EINTR) { sysdiag("receive"); sleep(1); } return; } if (this_saddr.sin_family != AF_INET) { fprintf(stderr,"%s: received unknown AF %lu\n", programid, (unsigned long)this_saddr.sin_family); return; } assert(this_saddrlen == sizeof(this_saddr)); assert(r <= buf_in.size); buf_in.size= r; cdebugbuf(-1, "decode", &buf_in, 3,0); for (i=n_mechs-1; i>=0; i--) { emsg= mechs[i]->decode(md_in[i],&buf_in); if (emsg) { if (*emsg) fprintf(stderr, "%s: bad packet: %s: %s\n", programid, mechs[i]->name, emsg); else cdebug(i,"silently discarded"); return; } cdebugbuf(i, "decode", &buf_in, 3,0); } npackets++; nbytes += buf_in.size; alarm(timeout); different= (!public_remote_specd || public_remote.sin_addr.s_addr != this_saddr.sin_addr.s_addr || public_remote.sin_port != this_saddr.sin_port); if (different) { if (public_remote_specd==2) { fprintf(stderr, "%s: packet from unexpected sender %s:%lu\n", programid, inet_ntoa(this_saddr.sin_addr), (unsigned long)ntohs(this_saddr.sin_port)); return; } fprintf(stderr, "%s: tunnel open with peer %s:%lu\n", programid, inet_ntoa(this_saddr.sin_addr), (unsigned long)ntohs(this_saddr.sin_port)); nextsendka= now(); public_remote_specd= 1; memcpy(&public_remote,&this_saddr,sizeof(public_remote)); } else if (!any_recvd) { diag("tunnel open"); } else if (reannounce && now() >= nextreann) { fprintf(stderr, "%s: tunnel still open: received %lu packets, %lu bytes\n", programid, npackets, nbytes); } else { goto no_set_reann; /* only reset this if we don't print a message. */ } if (reannounce) nextreann= now() + reannounce; no_set_reann: any_recvd= 1; if (!buf_in.size || *buf_in.start != 0300) { *--buf_in.start= 0300; buf_in.size++; } if (buf_in.start[buf_in.size-1] != 0300) { buf_in.start[buf_in.size++]= 0300; } setnonblock(private_in_fd,0); write_must(private_in_fd, buf_in.start, buf_in.size, "write down"); } static void sendpacket(const unsigned char *message, size_t size) { int i, r; buf_out.start= buf_out.base+maxprefix; buf_out.size= size; memcpy(buf_out.start, message, size); nextsendka= now() + keepalive; cdebugbuf(-1, "encode", &buf_out, 4,0); for (i=0; iencode(md_out[i],&buf_out); cdebugbuf(i, "encode", &buf_out, 4,0); } assert(public_remote_specd); setnonblock(public_local_fd,1); for (;;) { r= sendto(public_local_fd, buf_out.start, buf_out.size, 0, &public_remote, sizeof(public_remote)); if (r == buf_out.size) break; if (r >= 0) { diag("unexpected short send"); return; } if (errno != EINTR) { sysdiag("send"); return; } } } static void outbound(void) { int r; unsigned char *after_eaten, *delim; size_t this_packet; setnonblock(private_out_fd,1); for (;;) { r= read(private_out_fd, accum_buf + accum_used, accum_avail - accum_used); if (!r) { diag("outbound datastream closed, quitting"); exit(0); } if (r<0) { if (errno == EAGAIN) return; if (errno == EINTR) continue; } accum_used += r; assert(accum_used<=accum_avail); after_eaten= accum_buf; while ((delim= memchr(after_eaten, 0300, accum_used))) { this_packet= delim - after_eaten; if (this_packet) sendpacket(after_eaten, this_packet); accum_used -= this_packet+1; after_eaten = delim+1; } memmove(accum_buf, after_eaten, accum_used); if (accum_used == accum_avail) { diag("missing interpacket delimiter in output datastream"); accum_used= 0; } } } int main(int argc, const char *const *const argv_in) { const char *arg; const char *const *argv_save; const char *const *argv_done; struct pollfd pollfds[2]; int i, polltimeout, r; time_t tnow; argv= argv_in; if (uname(&uname_result)) { perror(PROGRAM ": uname failed"); exit(16); } sprintf(programid, PROGRAM ": %.*s", SYS_NMLN, uname_result.nodename); opt_chars= getarg_string(); encdec_keys_write= !!strchr(opt_chars,'w'); crypto_debug= !!strchr(opt_chars,'K'); public_local_fd= getarg_ulong(); private_in_fd= getarg_ulong(); private_out_fd= getarg_ulong(); encdec_keys_fd= getarg_ulong(); mtu2= getarg_ulong() * 2; keepalive= getarg_ulong(); timeout= getarg_ulong(); reannounce= getarg_ulong(); arg= getarg_string(); if (*arg) { public_remote_specd= 1; public_remote.sin_family= AF_INET; arg_assert(inet_aton(arg,&public_remote.sin_addr)); public_remote.sin_port= htons(getarg_ulong()); } if (crypto_debug) { diag("crypto debugging enabled!"); setvbuf(stdout,0,_IOLBF,0); } maxprefix= 0; i= 0; while ((arg= *++argv)) { arg_assert(*arg++ == '|'); arg_assert(i <= MAXMECHS); mechs[i]= find_mech(arg); cdebug(i,"writer->reader setup"); argv_save= argv; if (encdec_keys_write) mechs[i]->encsetup(&md_out[i], &maxprefix, &maxsuffix); else mechs[i]->decsetup(&md_in[i]); argv_done= argv; argv= argv_save; cdebug(i,"reader->writer setup"); if (encdec_keys_write) mechs[i]->decsetup(&md_in[i]); else mechs[i]->encsetup(&md_out[i], &maxprefix, &maxsuffix); assert(argv == argv_done); i++; } n_mechs= i; if (maxprefix<1) maxprefix= 1; if (maxsuffix<1) maxsuffix= 1; buffer_size= mtu2 + maxprefix + maxsuffix; buf_in.base= xmalloc(buffer_size); buf_out.base= xmalloc(buffer_size); accum_avail= mtu2 + 1; accum_buf= xmalloc(accum_avail); alarm(timeout); pollfds[0].fd= public_local_fd; pollfds[0].events= POLLIN; pollfds[1].fd= private_out_fd; for (;;) { pollfds[1].events= public_remote_specd ? POLLIN : 0; pollfds[0].revents= 0; pollfds[1].revents= 0; if (keepalive) { tnow= now(); if (tnow >= nextsendka && public_remote_specd) sendpacket((unsigned char*)"\300",1); polltimeout= (nextsendka - tnow)*1000; } else { polltimeout= -1; } r= poll(pollfds,2,polltimeout); if (!r) continue; if (r==-1 && errno==EINTR) continue; if (r==-1) sysfail("poll"); if (pollfds[0].revents & (POLLIN|POLLERR)) inbound(); if (pollfds[1].revents & (POLLIN|POLLERR)) outbound(); } } work/ipif/forwarder.h0000644000000000000000000000714614141560754012040 0ustar /* * Encrypting tunnel for userv-ipif tunnels, header file */ /* * This file is part of ipif, part of userv-utils * * Copyright 1996-2013 Ian Jackson * Copyright 1998 David Damerell * Copyright 1999,2003 * Chancellor Masters and Scholars of the University of Cambridge * Copyright 2010 Tony Finch * * This 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 userv-utils; if not, see http://www.gnu.org/licenses/. */ #ifndef MECHS_H #define MECHS_H #include #include #include #include struct buffer { unsigned char *base; unsigned char *start; size_t size; }; struct mechdata; typedef void mes_functype(struct mechdata **md_r, int *maxprefix_io, int *maxsuffix_io); typedef void mds_functype(struct mechdata **md_r); typedef void menc_functype(struct mechdata *md, struct buffer*); typedef const char *mdec_functype(struct mechdata *md, struct buffer*); struct mechanism { const char *name; mes_functype *encsetup; mds_functype *decsetup; menc_functype *encode; mdec_functype *decode; }; #include "automech.h" extern const struct mechanism *const mechanismlists[]; /* setup function may call getarg_xxx functions and then * reads/writes key material to/from fd * * setup_in function may increase maxprefix and maxsuffix * code functions modify buffer in place * decode function returns 0 meaning packet decoded ok, * "" meaning discard it quietly, or message to print for verbose discard */ const char *getarg_string(void); unsigned long getarg_ulong(void); #define PROGRAM "udptunnel-forwarder" extern char programid[]; void *buf_append(struct buffer *buf, size_t amount); void *buf_prepend(struct buffer *buf, size_t amount); void *buf_unappend(struct buffer *buf, size_t amount); /* may give 0 */ void *buf_unprepend(struct buffer *buf, size_t amount); /* may give 0 */ void sysfail(const char *msg); void fail(const char *msg); void sysdiag(const char *msg); void diag(const char *msg); extern const char *const *argv; time_t now(void); void *xmalloc(size_t sz); void get_random(void *ptr, size_t sz); void random_key(void *ptr, size_t sz); void write_must(int fd, const void *p_in, int sz, const char *what); void read_must(int fd, void *p_in, int sz, const char *what); void arg_assert_fail(const char *msg); #define arg_assert(v) (v ? (void)0 : arg_assert_fail(#v)) #define XMALLOC(variable) ((variable)= xmalloc(sizeof(*(variable)))) #define BUF_UNSOMEEND(var,buf,sz,whichend) \ do { var= whichend(buf,sz); if (!var) return "message truncated"; } while(0) #define BUF_UNAPPEND(var,buf,sz) BUF_UNSOMEEND(var,buf,sz,buf_unappend) #define BUF_UNPREPEND(var,buf,sz) BUF_UNSOMEEND(var,buf,sz,buf_unprepend) #define STANDARD_MECHANISMLIST(mechstring,filename) \ const struct mechanism mechlist_##filename []= { \ STANDARD_MECHANISM(mechstring,filename) \ { 0 } \ }; #define STANDARD_MECHANISM(mechstring,mechname) \ { mechstring, mes_##mechname, mds_##mechname, menc_##mechname, mdec_##mechname }, #endif work/ipif/global.example0000644000000000000000000000115614141560754012504 0ustar m4_dnl You can edit this file, which is m4 input. m4_dnl It defines global settings for your site. Settings here m4_dnl override both the defaults shipped with udptunnelconf and m4_dnl those which are mentioned in the `sites' file. SET( lend, [172.31.80.6]) SET( lnets, [172.18.45.0/24]) SET( lcommand, [authbind udptunnel -m]) SET( lpublic, [davenant-external]) SET( lport, [ERROR]) SET( lgroup, tunnel) SET( invoke_hook, [PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin export PATH]) SET( sshverbose, []) SET( inittab_runlevels, [235]) SET( inittab_pfx, [/usr/local/sbin/really -u tunnel]) work/ipif/hex.c0000644000000000000000000000362014141560754010615 0ustar /* * This file is part of ipif, part of userv-utils * * Copyright 1996-2013 Ian Jackson * Copyright 1998 David Damerell * Copyright 1999,2003 * Chancellor Masters and Scholars of the University of Cambridge * Copyright 2010 Tony Finch * * This 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 userv-utils; if not, see http://www.gnu.org/licenses/. */ #include #include #include #include #include #include "hex.h" const char *tohex(uint8_t *data, int len, char *buf) { char *p; for (p= buf; len>0; len--, data++, p+=2) sprintf(p,"%02x",*data); return buf; } void unhex(const char *what, const char *txt, uint8_t *datar, int *lenr, int minlen, int maxlen) { int l, v; char buf[3], *ep; l= strlen(txt); if (l%1) { fprintf(stderr,"odd number of hex digits in %s\n",what); exit(EX_DATAERR); } l>>=1; if (lmaxlen) { fprintf(stderr,"too many hex digits in %s\n",what); exit(EX_DATAERR); } if (lenr) *lenr= l; while (l) { buf[0]= *txt++; buf[1]= *txt++; buf[2]= 0; v= strtoul(buf,&ep,16); if (*ep) { fprintf(stderr,"not hex digit in %s: %c\n",what,*ep); exit(EX_DATAERR); } *datar++= v; l--; } } work/ipif/hex.h0000644000000000000000000000226514141560754010626 0ustar /* * This file is part of ipif, part of userv-utils * * Copyright 1996-2013 Ian Jackson * Copyright 1998 David Damerell * Copyright 1999,2003 * Chancellor Masters and Scholars of the University of Cambridge * Copyright 2010 Tony Finch * * This 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 userv-utils; if not, see http://www.gnu.org/licenses/. */ #ifndef HEX__H_INCLUDED #define HEX__H_INCLUDED #include const char *tohex(uint8_t *data, int len, char *buf); void unhex(const char *what, const char *txt, uint8_t *datar, int *lenr, int minlen, int maxlen); #endif work/ipif/ipif0000644000000000000000000000045014141560754010535 0ustar # See /usr/share/doc/userv-ipif/service.c.txt # if ( grep calling-user-shell /etc/shells & glob service-user root ) reset no-set-environment no-suppress-args no-disconnect-hup execute /usr/lib/userv/ipif-access /etc/userv/ipif-access /usr/lib/userv/ipif /etc/userv/ipif-networks -- fi work/ipif/ipif-networks0000644000000000000000000000017414141560754012412 0ustar # chiark per-user VPN subnets 172.31.80.0/24 # gid,range group, description 100,172.31.80.0/28, ian, Relativity-chiark VPN work/ipif/mech-blowfish.c0000644000000000000000000001020714141560754012557 0ustar /* * Blowfish mechanism for udp tunnel * * mechanisms: blowfish-cbc, blowfish-cbcmac * arguments: key size in bits (must be multiple of 8) * * key values: 8 byte random IV and n byte random key * * restrictions: plaintext length must be multiple of block size (8 bytes) * encoding: do CBC encryption overwriting message * encoding for MAC: do CBC and prepend last ciphertext block */ /* * This file is part of ipif, part of userv-utils * * Copyright 1996-2013 Ian Jackson * Copyright 1998 David Damerell * Copyright 1999,2003 * Chancellor Masters and Scholars of the University of Cambridge * Copyright 2010 Tony Finch * * This 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 userv-utils; if not, see http://www.gnu.org/licenses/. */ #include "forwarder.h" #include "blowfish.h" struct mechdata { unsigned char iv[BLOWFISH_BLOCKBYTES]; struct blowfish_cbc_state cbc; }; static void mds_blowfish(struct mechdata **md_r) { struct mechdata *md; unsigned long keysize; unsigned char key[BLOWFISH_MAXKEYBYTES]; XMALLOC(md); keysize= getarg_ulong(); arg_assert(!(keysize & 7)); keysize >>= 3; arg_assert(keysize > 0 && keysize <= BLOWFISH_MAXKEYBYTES); random_key(md->iv,sizeof(md->iv)); random_key(key,keysize); blowfish_loadkey(&md->cbc.ek, key,keysize); *md_r= md; } static void mes_blowfish(struct mechdata **md_r, int *maxprefix_io, int *maxsuffix_io) { mds_blowfish(md_r); } static void mds_bfmac(struct mechdata **md_r) { mds_blowfish(md_r); } static void mes_bfmac(struct mechdata **md_r, int *maxprefix_io, int *maxsuffix_io) { mds_blowfish(md_r); *maxprefix_io += BLOWFISH_BLOCKBYTES; } #define MSGSIZE_OUT \ msgsize= buf->size; \ arg_assert(!(msgsize & (BLOWFISH_BLOCKBYTES-1))); #define MSGSIZE_IN \ msgsize= buf->size; \ if (msgsize & (BLOWFISH_BLOCKBYTES-1)) return "not multiple of block size" #define FOREACH_BLOCK(func,inptr,outptr) \ { \ unsigned char *ptr; \ blowfish_cbc_setiv(&md->cbc, md->iv); \ for (ptr= buf->start; \ ptr < buf->start + msgsize; \ ptr += BLOWFISH_BLOCKBYTES) { \ func(&md->cbc,inptr,outptr); \ } \ } static void menc_blowfish(struct mechdata *md, struct buffer *buf) { unsigned long msgsize; MSGSIZE_OUT; FOREACH_BLOCK(blowfish_cbc_encrypt,ptr,ptr); } static const char *mdec_blowfish(struct mechdata *md, struct buffer *buf) { unsigned long msgsize; MSGSIZE_IN; FOREACH_BLOCK(blowfish_cbc_decrypt,ptr,ptr); return 0; } static void menc_bfmac(struct mechdata *md, struct buffer *buf) { unsigned long msgsize; unsigned char outblock[BLOWFISH_BLOCKBYTES]; MSGSIZE_OUT; FOREACH_BLOCK(blowfish_cbc_encrypt,ptr,outblock); memcpy(buf_prepend(buf,BLOWFISH_BLOCKBYTES), outblock, BLOWFISH_BLOCKBYTES); } static const char *mdec_bfmac(struct mechdata *md, struct buffer *buf) { unsigned long msgsize; unsigned char outblock[BLOWFISH_BLOCKBYTES]; unsigned char *checkblock; BUF_UNPREPEND(checkblock,buf,BLOWFISH_BLOCKBYTES); MSGSIZE_IN; FOREACH_BLOCK(blowfish_cbc_encrypt,ptr,outblock); if (memcmp(checkblock,outblock,BLOWFISH_BLOCKBYTES)) return "verify failed"; return 0; } const struct mechanism mechlist_blowfish[]= { STANDARD_MECHANISM("blowfish-cbcmac", bfmac) STANDARD_MECHANISM("blowfish-cbc", blowfish) { 0 } }; work/ipif/mech-null.c0000644000000000000000000000274114141560754011720 0ustar /* * Null mechanism for udp tunnel (for testing purposes only) * * mechanisms: null * arguments: none * * key values: none * restrictions: none * encoding: no transformation */ /* * This file is part of ipif, part of userv-utils * * Copyright 1996-2013 Ian Jackson * Copyright 1998 David Damerell * Copyright 1999,2003 * Chancellor Masters and Scholars of the University of Cambridge * Copyright 2010 Tony Finch * * This 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 userv-utils; if not, see http://www.gnu.org/licenses/. */ #include "forwarder.h" static void mes_null(struct mechdata **md_r, int *maxprefix_io, int *maxsuffix_io) { } static void mds_null(struct mechdata **md_r) { } static void menc_null(struct mechdata *md, struct buffer *buf) { } static const char *mdec_null(struct mechdata *md, struct buffer *buf) { return 0; } STANDARD_MECHANISMLIST("null",null) work/ipif/mech-pkcs5.c0000644000000000000000000000536514141560754012000 0ustar /* * PKCS#5 padding mechanism for udp tunnel * * mechanism: pkcs5 * arguments: block size to pad to, must be power of 2 and <=128 * * restrictions: none * encoding: append between 1 and n bytes, all of the same value being * the number of bytes appended */ /* * This file is part of ipif, part of userv-utils * * Copyright 1996-2013 Ian Jackson * Copyright 1998 David Damerell * Copyright 1999,2003 * Chancellor Masters and Scholars of the University of Cambridge * Copyright 2010 Tony Finch * * This 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 userv-utils; if not, see http://www.gnu.org/licenses/. */ #include "forwarder.h" struct mechdata { unsigned mask; }; static unsigned long setup(struct mechdata **md_r) { struct mechdata *md; unsigned long blocksize; XMALLOC(md); blocksize= getarg_ulong(); md->mask= blocksize - 1; arg_assert(!(md->mask & blocksize)); arg_assert(blocksize <= 255); *md_r= md; return blocksize; } static void mes_pkcs5(struct mechdata **md_r, int *maxprefix_io, int *maxsuffix_io) { unsigned long blocksize; blocksize= setup(md_r); *maxsuffix_io += blocksize + 1; } static void mds_pkcs5(struct mechdata **md_r) { setup(md_r); } static void menc_pkcs5(struct mechdata *md, struct buffer *buf) { unsigned char *pad; int padlen; /* eg with blocksize=4 mask=3 mask+2=5 */ /* msgsize 20 21 22 23 24 */ padlen= md->mask - buf->size; /* -17 -18 -19 -16 -17 */ padlen &= md->mask; /* 3 2 1 0 3 */ padlen++; /* 4 3 2 1 4 */ pad= buf_append(buf,padlen); memset(pad,padlen,padlen); } static const char *mdec_pkcs5(struct mechdata *md, struct buffer *buf) { unsigned char *padp; unsigned padlen; int i; BUF_UNAPPEND(padp,buf,1); padlen= *padp; if (!padlen || (padlen > md->mask+1)) return "invalid length"; BUF_UNAPPEND(padp,buf,padlen-1); for (i=0; i * Copyright 1998 David Damerell * Copyright 1999,2003 * Chancellor Masters and Scholars of the University of Cambridge * Copyright 2010 Tony Finch * * This 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 userv-utils; if not, see http://www.gnu.org/licenses/. */ #include #include "forwarder.h" struct mechdata { uint32_t number; int anyseen; /* decode only */ }; static void mes_sequence(struct mechdata **md_r, int *maxprefix_io, int *maxsuffix_io) { struct mechdata *md; XMALLOC(md); get_random(&md->number,sizeof(md->number)); *maxprefix_io += 4; *md_r= md; } static void mds_sequence(struct mechdata **md_r) { struct mechdata *md; XMALLOC(md); md->anyseen= 0; *md_r= md; } static void menc_sequence(struct mechdata *md, struct buffer *buf) { md->number++; *(uint32_t*)buf_prepend(buf,4)= htonl(md->number); } static const char *mdec_check(struct mechdata *md, struct buffer *buf) { uint32_t *sp, sequence; BUF_UNPREPEND(sp,buf,4); sequence= ntohl(*sp); if (md->anyseen) if (sequence - md->number >= 0x800000UL) return "out of order packet"; md->number= sequence; md->anyseen= 1; return 0; } static const char *mdec_skip(struct mechdata *md, struct buffer *buf) { uint32_t *sp; BUF_UNPREPEND(sp,buf,4); return 0; } const struct mechanism mechlist_sequence[]= { { "nonce", mes_sequence, mds_sequence, menc_sequence, mdec_skip }, { "sequence", mes_sequence, mds_sequence, menc_sequence, mdec_check }, { 0 } }; work/ipif/mech-timestamp.c0000644000000000000000000000515214141560754012750 0ustar /* * Timestamp mechanism for udp tunnel * * mechanism: timestamp * arguments: * * restrictions: none * encoding: prepend 4 bytes of UNIX time in network byte order * * is maximum age in seconds we will accept a packet (or 0 * for any age); is maximum future age in seconds we will * accept a packet (or 0 for any future age). * */ /* * This file is part of ipif, part of userv-utils * * Copyright 1996-2013 Ian Jackson * Copyright 1998 David Damerell * Copyright 1999,2003 * Chancellor Masters and Scholars of the University of Cambridge * Copyright 2010 Tony Finch * * This 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 userv-utils; if not, see http://www.gnu.org/licenses/. */ #include #include #include "forwarder.h" #define WARN_EVERY 30 struct mechdata { time_t max_skew, max_age; time_t next_warn; }; static void mds_timestamp(struct mechdata **md_r) { struct mechdata *md; md= xmalloc(sizeof(md)); md->max_skew= getarg_ulong(); md->max_age= getarg_ulong(); md->next_warn= now(); *md_r= md; } static void mes_timestamp(struct mechdata **md_r, int *maxprefix_io, int *maxsuffix_io) { mds_timestamp(md_r); *maxprefix_io += 4; } static void menc_timestamp(struct mechdata *md, struct buffer *buf) { *(uint32_t*)buf_prepend(buf,4)= htonl(now()); } static const char *mdec_timestamp(struct mechdata *md, struct buffer *buf) { static char cbuf[40]; uint32_t *tp, timestamp; time_t tnow; long age; BUF_UNPREPEND(tp,buf,4); timestamp= ntohl(*tp); tnow= now(); age= timestamp - (uint32_t)tnow; if (age > 0) { if (!md->max_age || age <= md->max_age) return 0; sprintf(cbuf,"packet too old (%lds)",age); } else if (age < 0) { if (!md->max_skew || age >= -md->max_skew) return 0; sprintf(cbuf,"too much skew (%lds)",-age); } else { return 0; } if (tnow < md->next_warn) return ""; md->next_warn= tnow+WARN_EVERY; return cbuf; } STANDARD_MECHANISMLIST("timestamp",timestamp); work/ipif/service-wrap0000755000000000000000000002110414141560754012217 0ustar #!/usr/bin/perl -w # # When invoked appropriately, it creates a point-to-point network # interface with specified parameters. It arranges for packets sent out # via that interface by the kernel to appear on its own stdout in SLIP or # CSLIP encoding, and packets injected into its own stdin to be given to # the kernel as if received on that interface. Optionally, additional # routes can be set up to arrange for traffic for other address ranges to # be routed through the new interface. # # This is the access control wrapper for the service program. # Arrangments should be made to invoke this as root from userv. # # Usage: # # .../ipif1 -- ... # # Config file is a series of lines, or a directory. If a directory, # all files with names matching ^[-A-Za-z0-9_]+$ are processed. # # permit .... # # if caller, local addr, all remote addrs and networks, and # ifname, all match, permits the request (and stops reading # the config) # # group | # matches caller if they are in that group # user | # matches caller if they are that user # everyone # always matches caller # # hostnet / # equivalent to local remote # local # matches local address when it is # remote / # matches aplicable remote addrs (including p-t-p) # addrs |/ # matches applicable local ore remote addrs # # ifname # matches interface name if it is exactly # ( may contain %d, which is interpreted by # the kernel) # wildcards are not supported # if a permit has no ifname at all, it is as if # `ifname userv%d' was specified # # include # # # # If none of the `permit' lines match, will process in # old format. See service.c head comment. may be # `' or `#' or `/dev/null' to process new-style config only. # # -- use strict; use POSIX; use Carp; use NetAddr::IP::Lite qw(:nofqdn :lower); use File::Basename; our $default_ifname = 'userv%d'; sub badusage ($) { my ($m) = @_; die "bad usage: $m\n"; } sub oneaddr ($) { my ($ar) = @_; my $x = $$ar; $x // badusage "missing IP address"; $x = new NetAddr::IP::Lite $x // badusage "bad IP address"; $x->masklen == $x->bits or badusage "IP network where addr expected"; die if $x->addr =~ m,/,; $$ar = $x; } @ARGV == 6 or badusage "wrong number of arguments"; our ($v1config, $realservice, $v0config, $sep, $addrsarg, $rnets) = @ARGV; $sep eq '--' or badusage "separator should be \`--'"; my ($local_addr, $peer_addr, $mtu, $protocol, $ifname) = split /\,/, $addrsarg; oneaddr \$local_addr; oneaddr \$peer_addr; $mtu = 1500 unless length $mtu; $mtu =~ m/^[1-9]\d{1,4}/ or badusage "bad mtu"; $mtu += 0; $protocol = 'slip' unless length $protocol; $protocol =~ m/\W/ and badusage "bad protocol"; $ifname = $default_ifname unless length $ifname; our @rnets = ($rnets eq '-' ? () : split /\,/, $rnets); @rnets = map { new NetAddr::IP::Lite $_ } @rnets; sub execreal ($) { my ($use_v0config) = @_; exec $realservice, $use_v0config, '--', (join ',', $local_addr->addr, $peer_addr->addr, $mtu, $protocol, $ifname), @rnets ? (join ",", map { "$_" } @rnets) : "-" or die "exec $realservice: $!\n"; } our $cfgpath; sub badcfg ($) { my ($m) = @_; die "bad configuration: $cfgpath:$.: $m\n"; } our %need_allow; # $need_allow{CLASS}[] # $need_allow{CLASS}[]{Desc} # For error messages # $need_allow{CLASS}[]{Allow} # Starts out nonexistent # $need_allow{CLASS}[]{IpAddr} # CLASS eq Local or Remote only sub allowent ($@) { my ($desc, @xtra) = @_; return { Desc => $desc, @xtra }; } sub allowent_addr ($$) { my ($what, $addr) = @_; return allowent "$what $addr", IpAddr => $addr; } sub need_allow_item ($$) { my ($cl, $ne) = @_; push @{ $need_allow{$cl} }, $ne } sub need_allow_singleton ($$) { my ($cl, $ne) = @_; $need_allow{$cl} ||= [ $ne ]; } sub maybe_allow__entry ($$) { my ($ne, $yes) = @_; $ne->{Allowed} ||= $yes; } sub maybe_allow_singleton ($$) { my ($cl, $yes) = @_; my $ents = $need_allow{$cl}; die $cl unless @$ents==1; maybe_allow__entry $ents->[0], $yes; } sub default_allow_singleton ($$) { # does nothing if maybe_allow_singleton was called for this $cl; # otherwise allows the singleton iff $yes my ($cl, $yes) = @_; my $ents = $need_allow{$cl}; die $cl unless @$ents==1; $ents->[0]{Allowed} //= $yes; } sub maybe_allow_caller_env ($$$) { my ($spec, @envvars) = @_; foreach my $envvar (@envvars) { my $val = $ENV{$envvar} // die $envvar; my @vals = split / /, $val; #use Data::Dumper; print Dumper($spec,$envvar,\@vals); maybe_allow_singleton 'Caller', !!grep { $_ eq $spec } @vals; } } sub maybe_allow_addrs ($$) { my ($cl, $permitrange) = @_; foreach my $ne (@{ $need_allow{$cl} }) { confess unless defined $ne->{IpAddr}; maybe_allow__entry $ne, $permitrange->contains($ne->{IpAddr}); } } sub readconfig ($); sub readconfig ($) { local ($cfgpath) = @_; my $dirfh; if (opendir $dirfh, $cfgpath) { while ($!=0, my $ent = readdir $dirfh) { next if $ent =~ m/[^-A-Za-z0-9_]/; readconfig "$cfgpath/$ent"; } die "$0: $cfgpath: $!\n" if $!; return; } die "$0: $cfgpath: $!\n" unless $!==ENOENT || $!==ENOTDIR; my $cfgfh = new IO::File $cfgpath, "<"; if (!$cfgfh) { die "$0: $cfgpath: $!\n" unless $!==ENOENT; return; } while (<$cfgfh>) { s/^\s+//; s/\s+$/\n/; next if m/^\#/; next unless m/\S/; if (s{^permit\s+}{}) { %need_allow = (); need_allow_singleton 'Caller', allowent 'caller'; need_allow_singleton 'Local', allowent_addr "local interface", $local_addr; need_allow_singleton 'Ifname', allowent 'interface name'; need_allow_item 'Remote', allowent_addr "peer point-to-point addr", $peer_addr; foreach (@rnets) { need_allow_item 'Remote', allowent_addr "remote network", $_; } #use Data::Dumper; print Dumper(\%need_allow); while (m{\S}) { if (s{^user\s+(\S+)\s+}{}) { maybe_allow_caller_env $1, 'USERV_USER', 'USERV_UID'; } elsif (s{^group\s+(\S+)\s+}{}) { maybe_allow_caller_env $1, 'USERV_GROUP', 'USERV_GID'; } elsif (s{^everyone\s+}{}) { maybe_allow_singleton 'Caller', 1; } elsif (s{^hostnet\s+(\S+/\d+)\s+}{}) { my $hn = new NetAddr::IP::Lite $1 or badcfg "invalid ip address in hostnet"; my $host = new NetAddr::IP::Lite $hn->addr or die; my $net = $hn->network() or die; maybe_allow_addrs 'Local', $host; maybe_allow_addrs 'Remote', $net; } elsif (s{^(local|remote|addrs)\s+(\S+)\s+}{}) { my $h = $1; my $s = new NetAddr::IP::Lite $2 or badcfg "invalid ip address or mask in $h"; maybe_allow_addrs 'Local', $s if $h =~ m/addrs|local/; maybe_allow_addrs 'Remote', $s if $h =~ m/addrs|remote/; } elsif (s{^ifname\s+(\S+)\s+}{}) { my ($spec) = $1; maybe_allow_singleton 'Ifname', $ifname eq $spec; } elsif (m{^\S+}) { badcfg "unknown keyword in permit \`$1'"; } else { die; } } default_allow_singleton 'Ifname', $ifname eq $default_ifname; my @wrong; foreach my $clval (values %need_allow) { foreach my $ne (@$clval) { next if $ne->{Allowed}; push @wrong, $ne->{Desc}; } } if (!@wrong) { # yay! if ($protocol eq 'debug') { print "config $cfgpath:$.: matches\n"; exit 0; } execreal '*'; } if ($protocol eq 'debug') { #use Data::Dumper; print Dumper(\%need_allow); print "config $cfgpath:$.: mismatch: $_\n" foreach @wrong; } } elsif (m{^include\s+(\S+)$}) { my $include = $1; $include =~ s{^(?!/)}{ dirname($cfgpath)."/" }e; readconfig $include; } else { badcfg "unknown config directive or bad syntax"; } } $cfgfh->error and die $!; close $cfgfh; } sub try_v0config() { return unless $v0config; return unless $v0config =~ m{^[^#]}; return if $v0config eq '/dev/null'; if ($v0config =~ m{^/}) { if (!stat $v0config) { die "v0 config $v0config: $!\n" unless $!==ENOENT; return; } } print "trying v0 config $v0config...\n" if $protocol eq 'debug'; execreal $v0config; } readconfig $v1config; try_v0config(); die "permission denied\n"; work/ipif/service.c0000644000000000000000000006327214141560754011502 0ustar /* * userv service (or standalone program) for per-user IP subranges. * * This is the service program, which is invoked as root from userv (or may * be invoked firectly). * * Its arguments are supposed to be, in order, as follows: * * The first two arguments are usually supplied by the userv * configuration. See the file `ipif/ipif' in the source tree, which * is installed in /etc/userv/services.d/ipif by `make install': * * * * Specifies address ranges and gids which own them. The default * configuration supplies /etc/userv/ipif-networks, which is then read * for a list of entries, one per line. * * -- * Serves to separate the user-supplied and therefore untrusted * arguments from the trusted first argument. * * The remaining arguments are supplied by the (untrusted) caller: * * ,,[,[][,[]]] * * As for slattach. The only supported protocol is slip. * Alternatively, set to `debug' to print debugging info and * exit. is address of the interface to be created * on the local system; is the address of the * point-to-point peer. They must be actual addresses (not * hostnames). * * /,/,... * * List of additional routes to add for this interface. routes will * be set up on the local system arranging for packets for those * networks to be sent via the created interface. must be an * IPv4 address, and mask must be an integer (dotted-quad masks are * not supported). If no additional routes are to be set up, use `-' * or supply an empty argument. * * Each item - whether a line in a file such as * /etc/userv/ipif-networks, or the single trusted argument supplied * on the service program command line - is one of: * * / * ./ * ../ * * Reads a file which contains lines which are each * items. * * ,[=][-|+]/(-|+/...)[,] * * Indicates that may allocate addresses in the relevant address * range ( is ignored). must be numeric. To specify a * single host address, you must specify a mask of /32. If `=' is * specified then the specific subrange is only allowed for the local * endpoint address, but not for remote addresses. * * More than one range may be given, with each range prefixed * by + or -. In this case each address range in the rule will * scanned in order, and the first range in the rule that matches * any desired rule will count: if that first matching range is * prefixed by `+' (or nothing) then the rule applies, if it * is prefixed by `-' (or nothing matches), the rule does not. * * * * Means that anything is to be permitted. This should not appear in * /etc/userv/ipif-networks, as that would permit any user on the * system to create any interfaces with any addresses and routes * attached. It is provided so that root can usefully invoke the ipif * service program directly (not via userv), without needing to set up * permissions in /etc/userv/ipif-networks. * * Only `*' permits interface name patterns other than the default * value of `userv%d'. * * #... * * Comment. Blank lines are also ignored. * * NB: Permission is granted if _any_ config entry matches the request. * * The service program should be run from userv with no-disconnect-hup. */ /* * This file is part of ipif, part of userv-utils * * Copyright 1996-2013 Ian Jackson * Copyright 1998 David Damerell * Copyright 1999,2003 * Chancellor Masters and Scholars of the University of Cambridge * Copyright 2010 Tony Finch * * This 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 userv-utils; if not, see http://www.gnu.org/licenses/. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define NARGS 4 #define MAXEXROUTES 50 #define ATXTLEN 16 static const unsigned long gidmaxval= (unsigned long)((gid_t)-2); static const char *const protos_ok[]= { "slip", 0 }; static const char default_ifnamepat[]= "userv%d"; static const char *configstr, *proto; static unsigned long localaddr, peeraddr, mtu; static int localpming, peerpming; static int localallow, peerallow, ifnameallow, allallow; static char *ifnamepat; static int nexroutes; static struct exroute { unsigned long prefix, mask; int allow, pming; char prefixtxt[ATXTLEN], masktxt[ATXTLEN]; } exroutes[MAXEXROUTES]; static char localtxt[ATXTLEN]; static char peertxt[ATXTLEN]; static struct pplace { struct pplace *parent; const char *filename; int lineno; } *cpplace; static int tunfd; static char *ifname; static void terminate(int estatus) { exit(estatus); } static void fatal(const char *fmt, ...) __attribute__((format(printf,1,2))); static void fatal(const char *fmt, ...) { va_list al; va_start(al,fmt); fputs("userv-ipif service: fatal error: ",stderr); vfprintf(stderr, fmt, al); putc('\n',stderr); terminate(8); } static void sysfatal(const char *fmt, ...) __attribute__((format(printf,1,2))); static void sysfatal(const char *fmt, ...) { va_list al; int e; e= errno; va_start(al,fmt); fputs("userv-ipif service: fatal system error: ",stderr); vfprintf(stderr, fmt, al); fprintf(stderr,": %s\n", strerror(e)); terminate(12); } static void badusage(const char *fmt, ...) __attribute__((format(printf,1,2))); static void badusage(const char *fmt, ...) { va_list al; struct pplace *cpp; if (cpplace) { fprintf(stderr, "userv-ipif service: %s:%d: ", cpplace->filename, cpplace->lineno); } else { fputs("userv-ipif service: invalid usage: ",stderr); } va_start(al,fmt); vfprintf(stderr, fmt, al); putc('\n',stderr); if (cpplace) { for (cpp=cpplace->parent; cpp; cpp=cpp->parent) { fprintf(stderr, "userv-ipif service: %s:%d: ... in file included from here\n", cpp->filename, cpp->lineno); } } terminate(16); } static char *ip2txt(unsigned long addr, char *buf) { sprintf(buf, "%lu.%lu.%lu.%lu", (addr>>24) & 0x0ff, (addr>>16) & 0x0ff, (addr>>8) & 0x0ff, (addr) & 0x0ff); return buf; } static unsigned long eat_number(const char **argp, const char *what, unsigned long min, unsigned long max, const char *endchars, int *endchar_r) { /* If !endchars then the endchar must be a nul, otherwise it may be * a nul (resulting in *argp set to 0) or something else (*argp set * to point to after delim, *endchar_r set to delim). * *endchar_r may be 0. */ unsigned long rv; char *ep; int endchar; if (!*argp) { badusage("missing number %s",what); } rv= strtoul(*argp,&ep,0); if ((endchar= *ep)) { if (!endchars) badusage("junk after number %s",what); if (!strchr(endchars,endchar)) badusage("invalid character or delimiter `%c' in or after number, %s:" " expected %s (or none?)", endchar,what,endchars); *argp= ep+1; } else { *argp= 0; } if (endchar_r) *endchar_r= endchar; if (rv < min || rv > max) badusage("number %s value %lu out of range %lu..%lu", what, rv, min, max); return rv; } static int addrnet_overlap(unsigned long p1, unsigned long m1, unsigned long p2, unsigned long m2) { unsigned long mask; mask= m1&m2; return (p1 & mask) == (p2 & mask); } static void addrnet_mustdiffer(const char *w1, unsigned long p1, unsigned long m1, const char *w2, unsigned long p2, unsigned long m2) { if (!addrnet_overlap(p1,m1,p2,m2)) return; badusage("%s %08lx/%08lx overlaps/clashes with %s %08lx/%08lx", w1,p1,m1, w2,p2,m2); } static unsigned long eat_addr(const char **argp, const char *what, const char *endchars, int *endchar_r) { char whatbuf[100]; unsigned long rv; int i; for (rv=0, i=0; i<4; i++) { rv <<= 8; sprintf(whatbuf,"%s byte #%d",what,i); rv |= eat_number(argp,whatbuf, 0,255, i<3 ? "." : endchars, endchar_r); } return rv; } static void eat_prefixmask(const char **argp, const char *what, const char *endchars, int *endchar_r, unsigned long *prefix_r, unsigned long *mask_r, int *len_r) { /* mask_r and len_r may be 0 */ char whatbuf[100]; int len; unsigned long prefix, mask; prefix= eat_addr(argp,what, "/",0); sprintf(whatbuf,"%s length",what); len= eat_number(argp,whatbuf, 0,32, endchars,endchar_r); mask= len ? (~0UL << (32-len)) : 0UL; if (prefix & ~mask) badusage("%s prefix %08lx not fully contained in mask %08lx", what,prefix,mask); *prefix_r= prefix; if (mask_r) *mask_r= mask; if (len_r) *len_r= len; } static char *eat_optionalstr(const char **argp, const char *what, const char *def) { ptrdiff_t len; const char *start= *argp; if (!start) { len = 0; } else { const char *comma= strchr(start, ','); if (comma) { len= comma - start; *argp= comma + 1; } else { len= strlen(start); *argp= 0; } } if (!len) { start= def; len= strlen(def); } char *r = malloc(len+1); if (!r) sysfatal("malloc for command line string"); memcpy(r,start,len); r[len]= 0; return r; } static int addrnet_isin(unsigned long prefix, unsigned long mask, unsigned long mprefix, unsigned long mmask) { return !(~mask & mmask) && (prefix & mmask) == mprefix; } /* Totally hideous algorithm for parsing the config file lines. * For each config file line, we first see if its gid applies. If not * we skip it. Otherwise, we do * permit_begin * which sets pming to 1 * for each range. pming may be 0 if we've determined that * this line does not apply to . * permit_range * which calls permit_range_thing for each * which checks to see if is inside the relevant * range (for +) or overlaps it (for -) and updates * allow and pming. */ static void permit_begin(void) { int i; localpming= peerpming= 1; for (i=0; iparent) { if (!strcmp(cpp->filename,filename)) badusage("recursive configuration file `%s'",filename); } file= fopen(filename,"r"); if (!file) badusage("cannot open configuration file `%s': %s", filename, strerror(errno)); if (!proto) printf("config file `%s':\n",filename); npp.parent= cpplace; npp.filename= filename; npp.lineno= 0; cpplace= &npp; while (fgets(buf, sizeof(buf), file)) { npp.lineno++; l= strlen(buf); if (!l) continue; truncated= (buf[l-1] != '\n'); while (l>0 && isspace((unsigned char) buf[l-1])) l--; if (!l) continue; buf[l]= 0; if (truncated) { while ((c= getc(file)) != EOF && c != '\n'); if (c == EOF) break; } pconfig(buf,truncated); } if (ferror(file)) badusage("failed while reading configuration file: %s", strerror(errno)); cpplace= npp.parent; fclose(file); } static void pconfig(const char *configstr, int truncated) { unsigned long fgid, tgid, pprefix, pmask; int plen, localonly, plus, rangeix, delim; char ptxt[ATXTLEN]; char whattxt[100]; const char *gidlist; switch (configstr[0]) { case '*': permit_begin(); permit_range(0UL,0UL,1,0); ifnameallow= 1; return; case '#': return; case '/': case '.': if (truncated) badusage("filename too long (`%.100s...')",configstr); pfile(configstr); return; default: if (!isdigit((unsigned char)configstr[0])) badusage("unknown configuration directive"); fgid= eat_number(&configstr,"gid", 0,gidmaxval, ",",0); if (!proto) printf(" %5lu", fgid); gidlist= getenv("USERV_GID"); if (!gidlist) fatal("USERV_GID not set"); for (;;) { if (!gidlist) { if (!proto) printf(" no matching gid\n"); return; } tgid= eat_number(&gidlist,"userv-gid", 0,gidmaxval, " ",0); if (tgid == fgid) break; } if (configstr[0] == '=') { localonly= 1; configstr++; } else { localonly= 0; } permit_begin(); rangeix= 0; plus= 1; switch (configstr[0]) { case '-': plus= 0; /* fall through */ case '+': configstr++; default:; } for (;;) { sprintf(whattxt, "%s-prefix#%d", plus ? "permitted" : "notpermitted", rangeix); eat_prefixmask(&configstr,whattxt, ",+-",&delim, &pprefix,&pmask,&plen); if (!configstr && truncated) badusage("gid,prefix/len,... spec too long"); if (!proto) printf(" %c%s/%d:", plus?'+':'-',ip2txt(pprefix,ptxt), plen); permit_range(pprefix,pmask,plus,localonly); if (delim==',') break; plus= delim=='-' ? 0 : 1; rangeix++; } putchar('\n'); return; } } static void checkallow(int allow, const char *what, const char *prefixtxt, const char *masktxt) { if (allow) return; fprintf(stderr,"userv-ipif service: access denied for %s, %s/%s\n", what, prefixtxt, masktxt); allallow= 0; } static void parseargs(int argc, const char *const *argv) { unsigned long routeaddr, routemask; const char *carg; const char *const *cprotop; int i; char erwhatbuf[100], erwhatbuf2[100]; if (argc < NARGS+1) { badusage("too few arguments"); } if (argc > NARGS+1) { badusage("too many arguments"); } configstr= *++argv; carg= *++argv; if (strcmp(carg,"--")) badusage("separator argument `--' not found, got `%s'",carg); carg= *++argv; localaddr= eat_addr(&carg,"local-addr", ",",0); peeraddr= eat_addr(&carg,"peer-addr", ",",0); mtu= eat_number(&carg,"mtu", 576,65536, ",",0); localallow= peerallow= 0; char *protostr= eat_optionalstr(&carg,"protocol","slip"); if (!strcmp(protostr,"debug")) { proto= 0; } else { for (cprotop= protos_ok; (proto= *cprotop) && strcmp(proto,protostr); cprotop++); if (!proto) fatal("invalid protocol"); } ifnamepat= eat_optionalstr(&carg,"ifname pattern",default_ifnamepat); addrnet_mustdiffer("local-addr",localaddr,~0UL, "peer-addr",peeraddr,~0UL); carg= *++argv; if (strcmp(carg,"-")) { for (nexroutes=0; carg && *carg; nexroutes++) { if (nexroutes == MAXEXROUTES) fatal("too many extra routes (only %d allowed)",MAXEXROUTES); sprintf(erwhatbuf,"route#%d",nexroutes); eat_prefixmask(&carg,erwhatbuf, ",",0, &routeaddr,&routemask,0); if (routemask == ~0UL) { addrnet_mustdiffer(erwhatbuf,routeaddr,routemask, "local-addr",localaddr,~0UL); addrnet_mustdiffer(erwhatbuf,routeaddr,routemask, "peer-addr",peeraddr,~0UL); } for (i=0; i= strlen(ifnamepat)+1); strcpy(ifr.ifr_name, ifnamepat); tunfd= open("/dev/net/tun", O_RDWR); if (!tunfd) sysfatal("open /dev/net/tun"); r= fcntl(tunfd, F_GETFD); if (r==-1) sysfatal("fcntl(tunfd,F_GETFD)"); r= fcntl(tunfd, F_SETFD, r|FD_CLOEXEC); if (r==-1) sysfatal("fcntl(tunfd,F_SETFD,|FD_CLOEXEC)"); r= ioctl(tunfd, TUNSETIFF, (void*)&ifr); if (r) sysfatal("ioctl TUNSETIFF"); /* ifr.ifr_name might not be null-terminated. crazy abi. */ ifname= malloc(sizeof(ifr.ifr_name)+1); if (!ifname) sysfatal("malloc for interface name"); memcpy(ifname, ifr.ifr_name, sizeof(ifr.ifr_name)); ifname[sizeof(ifr.ifr_name)]= 0; } static void netconfigure(void) { char mtutxt[100]; int i; if (task("ifconfig")) { sprintf(mtutxt,"%lu",mtu); execlp("ifconfig", "ifconfig", ifname, localtxt, "netmask","255.255.255.255", "pointopoint",peertxt, "-broadcast", "mtu",mtutxt, "up", (char*)0); sysfatal("cannot exec ifconfig"); } for (i=0; i=ip_end) break; uint8_t c= *ip++; if (c==SLIP_END) { rx_packet(output_buf, op-output_buf); op= output_buf; eaten= ip - input_buf; continue; } if (c==SLIP_ESC) { if (ip>=ip_end) { /* rescan this when there's more */ ip--; break; } c= *ip++; if (c==SLIP_ESC_END) c=SLIP_END; else if (c==SLIP_ESC_ESC) c=SLIP_ESC; else fatal("unexpected byte 0%o after SLIP_ESC",c); } if (op == output_buf+mtu) fatal("SLIP packet exceeds mtu"); *op++= c; } output_len= op - output_buf; scanned= ip - input_buf; input_waiting -= eaten; memmove(input_buf, input_buf+eaten, input_waiting); scanned -= eaten; } static void tx_packet(uint8_t *output_buf, const uint8_t *ip, int inlen) { /* output_buf is passed as a parameter since it's in copydata's stack frame */ assert(!output_waiting); uint8_t *op= output_buf; *op++= SLIP_END; while (inlen-- >0) { uint8_t c= *ip++; if (c==SLIP_END) { *op++= SLIP_ESC; *op++= SLIP_ESC_END; } else if (c==SLIP_ESC) { *op++= SLIP_ESC; *op++= SLIP_ESC_ESC; } else *op++= c; } *op++= SLIP_END; assert(op <= output_buf + mtu*2+2); output_waiting= op - output_buf; } static void copydata(void) __attribute__((noreturn)); static void copydata(void) { uint8_t output_buf[mtu*2+2]; uint8_t input_buf[mtu*2+2]; uint8_t rx_packet_buf[mtu]; int r, i; struct pollfd polls[3]; memset(polls, 0, sizeof(polls)); polls[0].fd= 0; polls[0].events= POLLIN; polls[1].fd= 1; polls[2].fd= tunfd; /* We don't do flow control on input packets; instead, we just throw * away ones which the kernel doesn't accept. So we always poll for * those. * * Output packets we buffer, so we poll only as appropriate for those. */ /* Start by transmitting one END byte to say we're ready. */ output_buf[0]= SLIP_END; output_waiting= 1; for (;;) { if (output_waiting) { r= write(1, output_buf, output_waiting); if (r<0) { if (errno==EINTR) continue; if (errno!=EAGAIN) sysfatal("error writing SLIP output (packets being received)"); } else { assert(r>0); output_waiting -= r; memmove(output_buf, output_buf+r, output_waiting); } } if (output_waiting) { polls[1].events |= POLLOUT; polls[2].events &= ~POLLIN; } else { polls[1].events &= ~POLLOUT; polls[2].events |= POLLIN; } r= poll(polls,3,-1); if (r<0) { if (errno==EINTR) continue; sysfatal("poll() failed"); } assert(r>0); /* we used an infinite timeout */ for (i=0; i0) { input_waiting += r; assert(input_waiting <= sizeof(input_buf)); more_rx_data(input_buf, rx_packet_buf); } else if (r==0) { terminate(0); } else { if (!(errno==EINTR || errno==EAGAIN)) sysfatal("error reading input SLIP data (packets to transmit)"); } } /* We handle what would be (polls[1].events & POLLOUT) above, * unconditionally. That eliminates the need to poll in the usual case */ if (polls[2].events & POLLIN) { uint8_t packet_buf[mtu]; r= read(tunfd, packet_buf, mtu); if (r>0) { tx_packet(output_buf, packet_buf, r); } else { assert(r<0); if (!(errno==EAGAIN || errno==EWOULDBLOCK)) sysfatal("error reading packet (being transmitted) from tun"); } } } } int main(int argc, const char *const *argv) { parseargs(argc,argv); pconfig(configstr,0); checkpermit(); if (!proto) dumpdebug(); createif(); netconfigure(); setnonblock(tunfd); setnonblock(0); setnonblock(1); copydata(); } work/ipif/sites.example0000644000000000000000000000216714141560754012376 0ustar m4_dnl This file is m4 input. It gives a list of the known sites m4_dnl participating in the Sinister Greenend Organisation VPN. m4_dnl m4_dnl It should not usually be edited locally, BUT it should be m4_dnl reviewed locally as installing a malicious copy would be m4_dnl equivalent to giving it control over your computer ! m4_dnl m4_dnl It defines settings for each site. Settings here m4_dnl can be overridden by things in `global', and on a per- m4_dnl tunnel basis by entries in `tunnels'. SITE(relativity) SET( rend, [172.31.80.6]) SET( rnets, [172.18.45.0/24]) SITE(greenend) SET( rpublic, [sinister.dynamic.greenend.org.uk]) SET( rend, [192.168.73.70]) SET( rnets, [192.168.0.0/23,192.168.73.0/24,172.16.22.0/24]) SET( rcommandprefix, [PATH=/usr/local/bin:'$PATH']) SET( proto, [slip]) SITE(rapun) SET( rpublic, [rapun.sel.cam.ac.uk]) SET( rend, [172.31.80.10]) SITE(chiark) SET( rpublic, [login.chiark.greenend.org.uk]) SET( rend, [172.31.80.8]) SITE(ecstacy) SET( rpublic, [ecstacy.dynamic.greenend.org.uk]) SET( rend, [172.31.80.7]) SET( rnets, [192.168.76.0/24]) SET( rcommandprefix, [PATH=/usr/local/bin:'$PATH']) work/ipif/tunnels.example0000644000000000000000000000107114141560754012730 0ustar m4_dnl You can edit this file, which is m4 input. m4_dnl It defines settings for each site. Settings here m4_dnl can be overridden by things in `global', and they m4_dnl override things set in `sites'. You can also define m4_dnl entirely new sites here with ACTIVE or PASSIVE - m4_dnl there is no need for them to be listed in `sites'. ACTIVE(greenend) SET( lport, [412]) SET( ruser, [tgroad]) SET( proto, [slip]) SET( lnets, V_lnets[,172.18.239.192/28]) ACTIVE(ecstacy) SET( lport, [411]) SET( ruser, davenant) ACTIVE(rapun) SET( lport, [413]) SET( ruser, [ian]) work/ipif/udptunnel0000755000000000000000000003551614141560754011642 0ustar #!/usr/bin/perl # Encrypting VPN tunnel for use with userv-ipif. # # This comment is reference documentation. See ipif/INSTALL for the # installation instructions and setup tutorial. # # usage: # To make a tunnel between two machines `alice' and `bob', # on `alice', the active endpoint, run: # # udptunnel # [ -l[] ... . # | -e [/...] # | -m (`masquerade support': bob gets `Wait' instead of our addr/port) # | -d (`dump keys': when no peer, spew keys rather than reading them; # we always send keys to our peer if there is one) # | -Dcrypto (debug crypto - use with care, prints keys, packets &c on screen!) # | -f # ... # ] # , # , # ,,, # ,[,] # # [ [ ...] ] # # This will run udptunnel-forwarder on alice, and use # (usually an ssh invocation) to run udptunnel appropriately on bob. # Key material will be generated by alice and fed to udptunnel on bob # via 's stdin, and the physical address and port on bob # will be (if so configured) returned via 's stdout. # # The tunnel will stay up until one of the subprocesses involved dies, # or the keepalive timeout expires. If you want the tunnel to remain # up permanently, you must arrange to invoke it repeatedly (eg, from # inittab). See INSTALL. # # may be slip or cslip # # will be the MTU of the tunnel interfaces; it is best if this # is enough smaller than the path MTU between the physical interfaces # that the encapsulated packets will fit without fragmentation. # # Any <..-addr> supplied to udptunnel may also be hostname; these will # all be looked up on alice and IP addresses passed to bob. # # The `local' physical address and ports (ie, alice's own details), # may have these special values: # `Any' choose one ourselves and do not print it (the port chosen # will be supplied to bob) # `Print' choose one ourselves and print both port and addr # (this is not usually useful specified directly; it's # used by udptunnel when it invokes itself on bob via # , to have its other self print the # relevant value. # # The `remote' physical address and port (ie, on alice, bob's details), # may also have the special values: # `Command' wait for to tell us the values (this is # usually the right choice on alice for at least the # port). must be specified (ie, this # only makes sense on alice). # `Wait' alice will wait to receive a packet from bob and use # whatever address and port it came from # # These special values are case-sensitive. When alice runs udptunnel # on bob they are automatically translated to appropriate other values # in the arguments to bob's udptunnel. # # If is specified it should run udptunnel at the # bob end; it will be invoked as # [ ... ] # [ <-e arguments passed along> ] # , # , # ,,, # ,[,] # # # If it was given Print for , udptunnel's first stdout # output will be the real , pair. It # may then produce more stdout which, if any, will be forwarded to the # local end's stdout as debugging info. # # After this, if any encryption was specified, the encryption key # material will be fed into its stdin. See the documentation in the # mech-*.c files for details of the parameters. udptunnel on alice # will arrange to feed the keys fd of udptunnel-forwarder into the # stdin of the udptunnel on bob. # # is as follows: # # actual addr/port that addr/port # `Command' `Print' # `Wait' `Any' # # is as follows: # # (-m not specified) (-m specified) # actual addr/port that addr/port `Wait' # `Print' the chosen address `Wait' # `Any' `Wait' for addr, `Wait' # chosen port for port # # In each case udptunnel will run userv ipif locally, as # userv root ipif ,,, # # or, if -l was given, userv root ipif is replaced with the argument(s) # following -l option(s) until `.'. # # udptunnel will also run udptunnel-forwarder with appropriate options. # # recommended encryption parameters are: # -e nonce (prepend 32 bit counter) # -e timestamp// (prepend 32 bit time_t, and check on receipt) # -e pkcs5/8 (pad as per PKCS#5 to 8-byte boundary) # -e blowfish-cbcmac/128 (prepend CBC MAC with random IV and 128 bit key) # -e blowfish-cbc/128 (encrypt with CBC, random IV and 128 bit key) # where is perhaps 10 and perhaps 30. If your # clocks are not sufficiently well synchronised, you could replace # `-e nonce -e timestamp/...' with just `-e sequence'. Do not just # remove `-e timestamp/...'. # Copyright 1996-2013 Ian Jackson # Copyright 1998 David Damerell # Copyright 1999,2003 # Chancellor Masters and Scholars of the University of Cambridge # Copyright 2010 Tony Finch # # This 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 userv-utils; if not, see http://www.gnu.org/licenses/. use Socket; use POSIX; use Fcntl; $progname= $0; $progname =~ s,.*/,,; $|=1; chomp($hostname= `uname -n`); $? and die "$progname: cannot get hostname (uname failed with code $?)\n"; sub quit ($) { die "$progname - $hostname: fatal error: $_[0]\n"; } sub debug ($) { print "$progname - $hostname: debug: $_[0]\n"; } sub fail ($) { quit("unexpected system call failure: $_[0]: $!"); } sub warning ($) { warn "$progname - $hostname: $_[0]\n"; } sub eat_addr_port ($) { my ($x) = @_; @ARGV or quit(", missing"); $_= shift(@ARGV); (m/^$x,/i && m/^[a-z]/ || m/,$x$/i && m/,[a-z]/) and warning("$_: use Mixed Case for special values"); m/^([0-9a-z][0-9a-z-+.]+|$x)\,(\d+|$x)$/ or quit("$_: , bad syntax". (m/[A-Z]/ ? ' (use lowercase for hostnames)' : '')); return ($1,$2); } sub conv_host_addr ($) { my ($s,$r,@h) = @_; return INADDR_ANY() if $s =~ m/^[A-Z][a-z]/; return $r if defined($r= inet_aton($s)); @h= gethostbyname($s) or quit("$s: cannot get address"); $h[2] eq &AF_INET or quit("$s: address is not IPv4"); @h < 5 or quit("$s: name maps to no addresses"); $r= $h[4]; @h == 5 or warning("$s: name has several addresses, using ".inet_ntoa($r)); return $r; } sub conv_port_number ($) { my ($s,$r) = @_; return 0 if $s =~ m/^[A-Z][a-z]/; $r= $s+0; $r>0 && $r<65536 or quit("$s: port out of range"); return $r; } sub show_addr ($) { my ($s,@s) = @_; @s= unpack_sockaddr_in($s); return inet_ntoa($s[1]); } sub show_port ($) { my ($s,@s) = @_; @s= unpack_sockaddr_in($s); return $s[0]; } sub show_addr_port ($) { my ($s) = @_; return show_addr($s).','.show_port($s); } sub arg_value ($$) { my ($val,$opt) = @_; $_= '-'; return $val if length $val; @ARGV or quit("$opt needs value"); return shift @ARGV; } @lcmd= (); @encryption= (); $masq= 0; $dump= 0; $fcmd= 'udptunnel-forwarder'; $xfwdopts= ''; while ($ARGV[0] =~ m/^-/) { $_= shift @ARGV; last if m/^--?$/; while (!m/^-$/) { if (s/^-l//) { push @lcmd,$_ if length; while (@ARGV && ($_= shift @ARGV) ne '.') { push @lcmd, $_; } $_= '-' } elsif (s/^-f//) { $fcmd= arg_value($_,'-f'); } elsif (s/^-e//) { $encrarg= arg_value($_,'-e'); push @remoteopts, "-e$encrarg"; @thisencryption= split m#/#, $encrarg; $thisencryption[0] =~ s/^/\|/; push @encryption, @thisencryption; } elsif (s/^-m/-/) { $masq= 1; } elsif (s/^-d/-/) { $dump= 1; } elsif (s/^-Dcrypto$/-/) { $xfwdopts.= 'K'; push @remoteopts, '-Dcrypto'; } else { quit("unknown option \`$_'"); } } } # Variables \$[lr]a?p?(|s|d|r) # Local/Remote Address&/Port # actualvalue/Specified/Displaypassdown/fromRemote/passtoForwarder # ($las,$lps)= eat_addr_port('Print|Any'); $la= conv_host_addr($las); $lp= conv_port_number($lps); $ls= pack_sockaddr_in $lp,$la; ($ras,$rps)= eat_addr_port('Wait|Command'); $ra= conv_host_addr($ras); $rp= conv_port_number($rps); $rs= pack_sockaddr_in $rp,$ra; $_= shift @ARGV; m/^([.0-9]+),([.0-9]+),(\d+),(slip|cslip)$/ or quit("lvaddr,rvaddr,mtu,proto missing or bad syntax or proto not [c]slip"); ($lva,$rva,$mtu,$proto) = ($1,$2,$3,$4); $_= shift @ARGV; if (m/^(\d+),(\d+)$/) { ($keepalive,$timeout,$reannounce)= ($1+0,$2+0,0); $ka_to_ra= "$keepalive,$timeout"; } elsif (m/^(\d+),(\d+),(\d+)$/) { ($keepalive,$timeout,$reannounce)= ($1+0,$2+0,$3); "$keepalive,$timeout", $ka_to_ra= "$keepalive,$timeout,$reannounce"; } else { quit("keepalive,timeout missing or bad syntax"); } $keepalive && ($timeout > $keepalive*2) or quit("timeout must be < 2*keepalive") if $timeout; # Variables \$[lr]exn # Local/Remote Extra Nets $lexn= shift @ARGV; $rexn= shift @ARGV; defined($udp= getprotobyname('udp')) or fail("getprotobyname udp"); socket(L,PF_INET,SOCK_DGRAM,$udp) or fail("socket"); bind(L,$ls) or quit("bind failed: $!"); defined($ls= getsockname(L)) or fail("getsockname"); $lad= show_addr($ls); $lpd= show_port($ls); $lapd= "$lad,$lpd"; print "$lapd\n" or fail("print addr/port") if ($las eq 'Print' || $lps eq 'Print'); $rapcmd= ($ras eq 'Command' || $rps eq 'Command'); quit("need remote-command if Command for remote addr/port") if $rapcmd && !@ARGV; sub xform_remote ($$) { my ($showed,$spec) = @_; return 'Print' if $spec eq 'Command'; return 'Any' if $spec eq 'Wait'; return $showed; } if (@ARGV) { warning("-d specified with remote command, ignoring") if $dump; $dump= 1; $rad= xform_remote(show_addr($rs),$ras); $rpd= xform_remote(show_port($rs),$rps); @rcmd= (@ARGV, @remoteopts, "$rad,$rpd", $masq ? 'Wait,Wait' : $las eq 'Any' ? "Wait,$lpd" : $lapd, "$rva,$lva,$mtu,$proto", $ka_to_ra, $rexn, $lexn); debug("remote command @rcmd"); if ($rapcmd) { pipe(RAPREAD,RCMDREADSUB) or fail("pipe"); } pipe(RCMDWRITESUB,DUMPKEYS) or fail("pipe"); defined($c_rcmd= fork) or fail("fork for remote"); if (!$c_rcmd) { open STDIN, "<&RCMDWRITESUB" or fail("reopen stdin for remote command"); open STDOUT, ">&RCMDREADSUB" or fail("reopen stdout for remote command") if $rapcmd; close RAPREAD if $rapcmd; close DUMPKEYS; close RCMDWRITESUB; close RCMDREADSUB; close L; exec @rcmd; fail("failed to execute remote command $rcmd[0]"); } close RCMDWRITESUB; if ($rapcmd) { close RCMDREADSUB if $rapcmd; $_= ''; while (!m/\n/) { $!=0; defined($nread= sysread(RAPREAD,$_,1,length)) or fail("read from remote command"); if (!$nread) { close DUMPKEYS; close RAPREAD; waitpid $c_rcmd,0 or fail("wait for remote command"); quit($? ? "remote command failed (code $?)" : "no details received from remote"); } } chomp; m/^([.0-9]+)\,(\d+)$/ or quit("invalid details from remote end: \`$_'"); ($rar,$rpr) = ($1,$2); $ra= conv_host_addr($rar); $rp= conv_port_number($rpr); defined($c_catremdebug= fork) or fail("fork for cat remote debug"); if (!$c_catremdebug) { open(STDIN,"<&RAPREAD") or fail("redirect remote debug"); close DUMPKEYS; close L; exec "cat"; fail("execute cat"); } close RAPREAD; } } elsif ($dump) { open DUMPKEYS, ">&STDOUT" or fail("reopen stdout for key material"); $dump= 1; } else { open DUMPKEYS, "<&STDIN" or fail("reopen stdout for key material"); } $rs= pack_sockaddr_in $rp,$ra; if ($ras eq 'Wait' || $rps eq 'Wait') { @rapf= (''); $rapd= ('Wait,Wait'); } else { @rapf= (show_addr($rs), show_port($rs)); $rapd= show_addr_port($rs); } @lcmd= qw(userv root ipif) unless @lcmd; debug("using remote $rapd local $lapd"); push @lcmd, ("$lva,$rva,$mtu,$proto",$lexn); debug("local command @lcmd."); pipe(UR,UW) or fail("up pipe"); pipe(DR,DW) or fail("down pipe"); defined($c_lcmd= fork) or fail("fork for local command"); if (!$c_lcmd) { close UR; close DW; open(STDIN,"<&DR") or fail("reopen stdin for packets"); open(STDOUT,">&UW") or fail("reopen stdout for packets"); exec @lcmd; quit("cannot execute $lcmd[0]: $!"); } close UW; close DR; $xfwdopts.= 'w' if $dump; @fcmd= ($fcmd, $xfwdopts, fileno(L), fileno(DW), fileno(UR), fileno(DUMPKEYS), $mtu, $keepalive, $timeout, $reannounce, @rapf, @encryption); debug("forwarding command @fcmd."); defined($c_fwd= fork) or fail("fork for udptunnel-forwarder"); if (!$c_fwd) { foreach $fd (qw(L DW UR DUMPKEYS)) { fcntl($fd, F_SETFD, 0) or fail("set no-close-on-exec $fd"); } exec @fcmd; fail("cannot execute $fcmd[0]"); } close L; close DUMPKEYS; close UR; close DW; %procs= ($c_fwd, 'forwarder', $c_lcmd, 'local command'); $procs{$c_rcmd}= 'remote command' if $c_rcmd; $procs{$c_catremdebug}= 'debug cat' if $c_catremdebug; $estatus= 0; while (keys %procs) { ($c= wait) >0 or fail("wait failed (expecting ". join('; ',keys %procs). ")"); $status= $?; warning("unexpected child reaped: pid $c, code $status"), next unless exists $procs{$c}; $str= $procs{$c}; delete $procs{$c}; $status ? warning("subprocess $str failed with code $status") : debug("subprocess $str finished"); if ($c==$c_lcmd || $c==$c_fwd || $c==$c_rcmd) { kill 15, grep (exists $procs{$_}, $c_fwd, $c_rcmd); } $estatus=1 unless $c == $c_catremdebug; } debug("all processes terminated, exiting with status $estatus"); exit $estatus; work/ipif/udptunnel-reconf.pl0000755000000000000000000001426714141560754013526 0ustar #!/usr/bin/perl # udptunnel-reconf # Set up the relevant stuff in /etc/userv/vpn, and then run # this. It should tell you what to do to inittab and ipif-networks. # This file is part of ipif, part of userv-utils # # Copyright 1996-2013 Ian Jackson # Copyright 1998 David Damerell # Copyright 1999,2003 # Chancellor Masters and Scholars of the University of Cambridge # Copyright 2010 Tony Finch # # This 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 userv-utils; if not, see http://www.gnu.org/licenses/. use Socket; # @@@- $shareuserv= "`pwd`"; $etcvpn= "`pwd`"; $varlibvpn= "`pwd`"; # -@@@ sub badusage () { die "usage: udptunnel-reconf []\n"; } $debug=0; sub fault ($) { die "$0: $_[0]\n"; } while ($ARGV[0] =~ m/^-/) { $_= shift @ARGV; last if m/^--$/; if (m/^-d$/) { $debug++; next; } badusage(); } if (@ARGV) { $etcvpn= shift @ARGV; } badusage() if @ARGV; chdir $etcvpn or fault("$etcvpn: $!"); sub run_m4 ($$$) { my ($wanted, $site, $variable) = @_; $x= "m4 -P -DWANTED=$wanted -DWHVARIABLE=V_$variable -DV_global=global ". "-DV_site=$site -DV_varlibvpn=$varlibvpn ". "-DV_defaults=$shareuserv/udptunnel-vpn-defaults ". "$shareuserv/udptunnel-vpn-config.m4"; print STDERR $x,"\n" if $debug>=2; open X, "$x |" or die $!; undef $/; $m4out= ; $/= "\n"; $!=0; close X; $? and die "m4 failed with code $? $!"; $m4out =~ s/^\s+//; $m4out =~ s/\n+/\n/g; $m4out =~ s/\s+$//; print STDERR "$wanted/$variable($site) -> \`$m4out'\n" if $debug>=1; # $m4out='' if $wanted eq 'VARIABLE' && substr($m4out,0,2) eq 'V_'; return $m4out; } sub check_junk ($$) { my ($emsg, $site) = @_; $j= run_m4('JUNK',$site,''); $j =~ s/^\# //g; fault("$emsg: $j") if length $j; } sub var_global ($) { return run_m4('VARIABLE','',$_[0]) } sub var_site ($) { return run_m4('VARIABLE',$site,$_[0]) } check_junk("error in config",''); @actives= split /\s+/, run_m4('ACTIVES','',''); @passives= split /\s+/, run_m4('PASSIVES','',''); foreach $site (@actives, @passives) { check_junk("error in config for site $site",$site); } sub parse_addr_mask ($) { my ($r) = @_; my ($mask,$iaddr); if ($r =~ s,/(\d+)$,,) { $mask=$1; } else { $mask=32; } fault("invalid mask length $1") if $mask<0 || $mask>32; $mask= $mask ? ~0 << (32-$mask) : 0; $iaddr= inet_aton($r); fault("invalid address $r") unless defined $iaddr; $iaddr= (unpack "N",$iaddr)[0]; return ($iaddr, $mask); } sub ipif_permit ($$$$) { my ($group,$local,$net,$why) = @_; my ($pmask,$piaddr,$fmask,$fiaddr,@lgroup,$lgid); @lgroup= getgrnam($group); @lgroup or fault("invalid group \`$group' ($why)"); $lgid= $lgroup[2]; if (!$local) { ($piaddr,$pmask) = parse_addr_mask($net); foreach $fref (@forbid_remote) { ($fiaddr,$fmask) = @$fref; $jmask= $fmask & $pmask; #printf STDERR "%8lx %8lx %l8x %8lx", $pmask,$pmask fault("local network $net claimed as remote ($why)") if (($fiaddr&$jmask) == ($piaddr&$jmask)); } } $ipif_file .= "$lgid,$local$net, $group, $why\n"; } $glgroup= var_global('lgroup'); $glend= var_site('lend')."/32"; if ($glend !~ m/^V_/ && $glgroup !~ m/^V_/ && length $glend && length $glgroup) { ipif_permit($glgroup, '=', "$glend", 'local endpoint'); } else { $glend='X'; $glgroup='X'; } foreach $site (@actives, @passives) { $forbid_remote= var_site('forbid_remote'); @forbid_remote= (); if ($forbid_remote ne '-') { foreach $r (split /[, \t]+/, $forbid_remote) { push @forbid_remote, [ parse_addr_mask($r) ]; } } $tlend= var_site('lend')."/32"; $tlgroup= var_site('lgroup'); if ($tlend ne $glend || $tlgroup ne $glgroup) { ipif_permit($tlgroup, '=', $tlend, "$site - local endpoint"); } $trend= var_site('rend').'/32'; $ix= 0; $trnets= var_site('rnets'); ipif_permit($tlgroup, '', $trend, "$site - remote endpoint"); if ($trnets ne '-') { foreach $rnet (split /,/, $trnets) { ipif_permit($tlgroup, '', $rnet, "$site - remote network #$ix"); $ix++; } } } sub write_file ($$$$) { my ($fn,$why,$head,$body) = @_; length $fn or fault("location to write $why not specified"); open F, ">$fn.new" or fault("create $fn.new: $!"); print F $head."\n# AUTOGENERATED BY $0 - DO NOT EDIT\n".$body or die $!; close F or die $!; rename "$fn.new",$fn or die $!; } $ipifnetsfile= var_global(ipifnetsfile); write_file($ipifnetsfile,'ipifnetsfile','', $ipif_file); $active_file= ''; $knownhosts_file= ''; $inittab= ''; $ix= 0; foreach $site (@actives) { $active_file.= "$site\t".var_site('activesxinfo')."\n"; $inittab.= sprintf("t%d", $ix++).':'.var_site('inittab_line')."\n"; $hostkey= var_site('rhostkey'); $knownhosts_file.= var_site('sshdest').' '.$hostkey."\n" if length $hostkey; $invoke_file= var_site('invoke_file'); write_file($invoke_file, 'invoke_file', var_site('invoke_head')."\n", var_site('invoke_body')); chmod 0777&~umask, $invoke_file or die $!; } write_file(var_global('knownhostsfile'),'knownhostsfile', '',$knownhosts_file); write_file(var_global('activesfile'),'activesfile', '',$active_file); print "# You can cut and paste all or part of this into your inittab if you like:\n", $inittab; print "# And consider adding this line, or some of this file's contents,\n". "# to your /etc/userv/ipif-networks:\n", "$ipifnetsfile\n" if $ipifnetsfile =~ m,^/,; $passive_file= ''; foreach $site (@passives) { $passive_file.= "$site\t".var_site('passivesxinfo')."\n"; } write_file(var_global('passivesfile'),'passivesfile', '',$passive_file); system var_global('postconfigure'); $? and exit -1; exit 0; work/ipif/udptunnel-vpn-config.m40000644000000000000000000000426314141560754014215 0ustar m4_dnl udptunnel-vpn-config.m4: macros for udptunnel-reconf et al m4_dnl This file is part of ipif, part of userv-utils m4_dnl m4_dnl Copyright 1996-2013 Ian Jackson m4_dnl Copyright 1998 David Damerell m4_dnl Copyright 1999,2003 m4_dnl Chancellor Masters and Scholars of the University of Cambridge m4_dnl Copyright 2010 Tony Finch m4_dnl m4_dnl This is free software; you can redistribute it and/or modify it m4_dnl under the terms of the GNU General Public License as published by m4_dnl the Free Software Foundation; either version 3 of the License, or m4_dnl (at your option) any later version. m4_dnl m4_dnl This program is distributed in the hope that it will be useful, but m4_dnl WITHOUT ANY WARRANTY; without even the implied warranty of m4_dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU m4_dnl General Public License for more details. m4_dnl m4_dnl You should have received a copy of the GNU General Public License m4_dnl along with userv-utils; if not, see http://www.gnu.org/licenses/. m4_define(V_JUNK,1)m4_divert(V_JUNK) m4_define(V_VARIABLE,2) m4_define(V_ACTIVES,3) m4_define(V_PASSIVES,4) m4_changequote([,]) m4_define(V_WARGS, [ m4_define([$1], [m4_ifelse($][#,$2,[$3], [# ]m4___file__:m4___line__[: wrong number of args to $1])])]) V_WARGS([SET], 2, [V_SET([V_$1], [$2])]) m4_define(V_YES, [m4_define([V_SET],[m4_define($][@)])]) m4_define(V_NO, [m4_define([V_SET], [])]) m4_define(V_ACTPA, [ V_WARGS($1, 1, [m4_divert(V_$1S)$][1 m4_dnl m4_divert(V_JUNK)m4_ifelse($][1,V_site, [V_YES], [V_NO] )])]) m4_dnl V_WARGS(, 2, [m4_divert(V_PASSIVES)$1 m4_dnl m4_dnl m4_divert(V_JUNK)m4_ifelse([$1],V_site, [$2])]) m4_divert(V_JUNK) V_YES m4_include(V_defaults) V_WARGS(SITE, 1, [m4_ifelse([$1],V_site, [V_YES], [V_NO])]) V_YES m4_include(V_sites) m4_undefine([SITE]) V_ACTPA(ACTIVE) V_ACTPA(PASSIVE) V_YES m4_include(V_tunnels) V_YES m4_include(V_global) m4_divert(V_VARIABLE) WHVARIABLE m4_divert(V_JUNK) m4_define(V_WANTED, V_[]WANTED) m4_divert(0) m4_undivert(V_WANTED) m4_divert(-1) m4_undivert(V_JUNK) m4_undivert(V_ACTIVES) m4_undivert(V_PASSIVES) m4_undivert(V_VARIABLE) work/ipif/udptunnel-vpn-defaults0000644000000000000000000000643314141560754014241 0ustar m4_dnl udptunnel-vpn-defaults: default settings for udptunnel-reconf m4_dnl This file is part of ipif, part of userv-utils m4_dnl m4_dnl Copyright 1996-2013 Ian Jackson m4_dnl Copyright 1998 David Damerell m4_dnl Copyright 1999,2003 m4_dnl Chancellor Masters and Scholars of the University of Cambridge m4_dnl Copyright 2010 Tony Finch m4_dnl m4_dnl This is free software; you can redistribute it and/or modify it m4_dnl under the terms of the GNU General Public License as published by m4_dnl the Free Software Foundation; either version 3 of the License, or m4_dnl (at your option) any later version. m4_dnl m4_dnl This program is distributed in the hope that it will be useful, but m4_dnl WITHOUT ANY WARRANTY; without even the implied warranty of m4_dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU m4_dnl General Public License for more details. m4_dnl m4_dnl You should have received a copy of the GNU General Public License m4_dnl along with userv-utils; if not, see http://www.gnu.org/licenses/. SET( lcommand, [udptunnel]) SET( clock_maxskew, 45) SET( crypto, [-e nonce -e timestamp/V_clock_maxskew/V_clock_maxskew -e pkcs5/8 \ -e blowfish-cbcmac/128 -e blowfish-cbc/128]) SET( lpublic, [`hostname`]) SET( lport, [Any]) m4_dnl rpublic -- usually set in sites SET( rport, [Command]) m4_dnl lend -- usually set in global m4_dnl rend -- usually set in sites SET( mtu, [1000]) SET( proto, [slip]) SET( to_restart, [10]) SET( to_poll, [30]) SET( to_quit, [130]) SET( to_report, [1800]) SET( timeouts, [V_to_poll,V_to_quit,V_to_report]) SET( lnets, [-])m4_dnl often overridden in global SET( rnets, [-])m4_dnl often overridden in sites SET( forbid_remote, [V_lnets]) SET( rcommandprefix, []) SET( rcommand, [V_rcommandprefix udptunnel]) SET( sshprotoka, [-o 'ProtocolKeepAlives 300']) SET( sshstdopts, [-o 'ForwardAgent no' -o 'ForwardX11 no' -o 'BatchMode yes']) SET( sshverbose, [-v]) SET( sshopts, []) SET( ssh, [ssh V_sshstdopts \ V_sshprotoka V_sshverbose \ V_sshopts]) SET( sshinvoke, [V_ssh V_ruser@V_sshdest]) SET( sshdest, [V_rpublic]) SET( sites, [sites]) SET( tunnels, [tunnels]) m4_dnl varlibvpn -- global can override SET( ipifnetsfile, [V_varlibvpn/ipif-networks]) SET( activesfile, [V_varlibvpn/active-sites]) SET( activesxinfo, []) SET( passivesfile, [V_varlibvpn/passive-sites]) SET( passivesxinfo, []) SET( postconfigure, []) SET( invoke_file, [V_varlibvpn/command.V_site]) SET( invoke_head, [#!/bin/sh]) SET( invoke_hook, []) SET( syslog_facility, local2) SET( syslog_priority, info) SET( inittab_runlevels, 2345) SET( inittab_pfx, []) SET( inittab_sfx, [&1 | logger -p V_syslog_facility.V_syslog_priority -t tunnel-V_site]) SET( inittab_command,[V_inittab_pfx V_invoke_file V_inittab_sfx]) SET( inittab_line, [V_inittab_runlevels:respawn:V_inittab_command]) SET( invoke_body, [set -e V_invoke_hook echo "STARTING TUNNEL `date`" >&2 set +e V_command rc=$? set -e echo "TUNNEL CLOSED rc=$rc" >&2 sleep V_to_restart echo "TUNNEL MAYRESTART" >&2 exit $rc ]) m4_dnl lgroup -- usually set in global SET( command, [V_lcommand \ V_crypto \ V_lpublic,V_lport \ V_rpublic,V_rport \ V_lend,V_rend,V_mtu,V_proto \ V_timeouts \ V_rnets \ V_lnets \ V_sshinvoke V_rcommand ]) work/ipif/utils.c0000644000000000000000000000635714141560754011203 0ustar /* * General utility functions for udp tunnel */ /* * Copyright 1996-2013 Ian Jackson * Copyright 1998 David Damerell * Copyright 1999,2003 * Chancellor Masters and Scholars of the University of Cambridge * Copyright 2010 Tony Finch * * This 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 userv-utils; if not, see http://www.gnu.org/licenses/. */ #include #include #include #include #include #include "forwarder.h" const char *const *argv; char programid[SYS_NMLN+sizeof(PROGRAM)+3]; void arg_assert_fail(const char *msg) { fprintf(stderr, PROGRAM ": argument error (!`%s')\n",msg); exit(12); } void sysfail(const char *msg) { fprintf(stderr, "%s: fatal system error: %s: %s\n", programid, msg, strerror(errno)); exit(8); } void fail(const char *msg) { fprintf(stderr, "%s: fatal error: %s\n", programid, msg); exit(4); } void sysdiag(const char *msg) { fprintf(stderr, "%s: system/network error: %s: %s\n", programid, msg, strerror(errno)); } void diag(const char *msg) { fprintf(stderr, "%s: %s\n", programid, msg); } time_t now(void) { time_t r; if (time(&r) == (time_t)-1) sysfail("get time of day"); return r; } void *xmalloc(size_t sz) { void *r; r= malloc(sz); if (!r) sysfail("allocate memory"); return r; } void write_must(int fd, const void *p_in, int sz, const char *what) { const unsigned char *p= p_in; int r; while (sz) { r= write(fd,p,sz); if (r<0) { if (errno == EINTR) continue; else sysfail(what); } assert(r && r <= sz); p += r; sz -= r; } } void read_must(int fd, void *p_in, int sz, const char *what) { unsigned char *p= p_in; int r; while (sz) { r= read(fd,p,sz); if (r<0) { if (errno == EINTR) continue; else sysfail(what); } if (r==0) fail(what); assert(r <= sz); p += r; sz -= r; } } const char *getarg_string(void) { const char *arg; arg= *++argv; arg_assert(arg); return arg; } unsigned long getarg_ulong(void) { char *ep; unsigned long ul; ul= strtoul(getarg_string(),&ep,0); arg_assert(!*ep); return ul; } void *buf_append(struct buffer *buf, size_t amount) { void *p; p= buf->start + buf->size; buf->size += amount; return p; } void *buf_prepend(struct buffer *buf, size_t amount) { buf->size += amount; return buf->start -= amount; } void *buf_unappend(struct buffer *buf, size_t amount) { if (buf->size < amount) return 0; return buf->start + (buf->size -= amount); } void *buf_unprepend(struct buffer *buf, size_t amount) { void *p; p= buf->start; buf->start += amount; buf->size -= amount; return p; } work/misc/0000755000000000000000000000000014141560754007670 5ustar work/misc/Makefile0000644000000000000000000000227014141560754011331 0ustar # Makefile # # Copyright 1996-2013 Ian Jackson # Copyright 1998 David Damerell # Copyright 1999,2003 # Chancellor Masters and Scholars of the University of Cambridge # Copyright 2010 Tony Finch # # This 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 userv-utils; if not, see http://www.gnu.org/licenses/. include ../settings.make install: mkdir -p $(bindir) cp mailq-wrapper $(bindir)/mailq mkdir -p $(sbindir) cp checkpasswd-service $(sbindir)/checkpasswd-service install-examples: mkdir -p $(services) cp mailq ndc-reload checkpasswd-self checkpasswd-other \ $(services)/. install-docs: work/misc/checkpasswd-other0000644000000000000000000000033614141560754013233 0ustar # if ( grep calling-user /etc/userv/checkpasswd-service-users & glob service-user root ) reset no-set-environment disconnect-hup no-suppress-args execute checkpasswd-service /var/run/checkpasswd.synch 0.5 -- fi work/misc/checkpasswd-self0000644000000000000000000000033214141560754013037 0ustar # if ( grep service /etc/userv/default-services-enabled & glob service-user root ) reset no-set-environment disconnect-hup suppress-args execute checkpasswd-service /var/run/checkpasswd.synch 0.5 -- SELF fi work/misc/checkpasswd-service0000755000000000000000000000412214141560754013552 0ustar #!/usr/bin/perl -w # checkpasswd-service # part of userv-utils # protocols: # # userv root checkpasswd-self <<'END' # < PASSWORD # < ^D # > STATUS MESSAGE... # # userv root checkpasswd-other USERNAME <<'END' # < PASSWORD # < ^D # > STATUS MESSAGE... # # STATUS MESSAGE may be # 0 ok # 2 incorrect password # 4 no such user # 5 password disabled # Copyright 1996-2013 Ian Jackson # Copyright 1998 David Damerell # Copyright 1999,2003 # Chancellor Masters and Scholars of the University of Cambridge # Copyright 2010 Tony Finch # # This 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 userv-utils; if not, see http://www.gnu.org/licenses/. use strict; use IO::File; use Fcntl qw(:flock); my ($lockpath, $delay, $separator, $username) = @ARGV; die "$0: bad usage\n" unless @ARGV == 4 || $lockpath =~ m#^/# || $delay =~ m/^[0-9.]+$/ || $separator eq '--' || $username =~ m/^\w/; $username = $ENV{'USERV_USER'} if $username eq 'SELF'; sub result { print "@_\n" or die $!; exit 0; } my @pwent = getpwnam($username); result 4, "no such user" unless @pwent; my $encrpw= $pwent[1]; result 5, "password disabled" unless length $encrpw >= 13; $!=0; my $pw = ; chomp $pw or die "reading password: $!\n"; my $lockf = new IO::File $lockpath, "w+" or die "open $lockpath: $!\n"; flock($lockf, LOCK_EX) or die "lock $lockpath: $!\n"; select(undef,undef,undef,0.5); close $lockf; my $crval = crypt($pw,$encrpw); result 2, "incorrect password" unless $crval eq $encrpw; result 0, "ok"; work/misc/mailq0000644000000000000000000000023514141560754010716 0ustar if ( grep calling-user-shell /etc/shells & glob service-user mail ) reset no-set-environment suppress-args disconnect-hup execute sendmail -bp fi work/misc/mailq-wrapper0000755000000000000000000000175114141560754012403 0ustar #!/bin/sh # Copyright 1996-2013 Ian Jackson # Copyright 1998 David Damerell # Copyright 1999,2003 # Chancellor Masters and Scholars of the University of Cambridge # Copyright 2010 Tony Finch # # This 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 userv-utils; if not, see http://www.gnu.org/licenses/. set -e if $# != 0; then echo >&2 'usage: mailq' exit 127 fi exec userv mail mailq # Copyright 1998 David Damerell # Copyright 1999,2003 # Chancellor Masters and Scholars of the University of Cambridge # Copyright 2010 Tony Finch # # This 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 userv-utils; if not, see http://www.gnu.org/licenses/. $minreaddays= 21; $maxperuser= 250; $fetchdir= "/var/lib/news/fetch"; chdir("/etc/news") || die $!; open(CONF,"nntp-merge.conf") || die $!; while() { next if m/^\#/ || !m/^\S/; next if m/^(myfqdn|xref|server|server-nosearch|fetch|read|post|permit|believe|minreaddays)\s/; if (m/^maxperuser\s+(\d+)\s+$/) { $maxperuser= $1; } elsif (m/^extrarc\s+(\S+)\s+$/) { push(@extrarc,$1); } else { die "$_ ?"; } } open IGN,") { chomp; next if m/^\#/; s/\s*$//; $ign{$_}= 1; } close IGN or die $!; open PASS,") { chomp; next if m/^\#/; $user= $_; next if $ign{$user}; open GL,"userv -t 30 $user newsrc-listgroups |" or die $!; scan("user $user",1); close GL; $? and warn "getgroups: error getting groups for $user (code $?)"; } close PASS or die $!; for $f (@extrarc) { open GL,"< $f" or die $!; scan("file $f",0); close GL or die $!; } chdir($fetchdir) || die $!; open(NG,">all-read-groups.new") || die $!; print(NG join("\n",sort keys %yes)."\n") || die $!; close(NG) || die $!; rename("all-read-groups.new","all-read-groups") || die $!; printf "total %d groups\n",scalar(keys %yes); exit(0); sub scan ($) { my ($where,$toomanyenf) = @_; @g= (); while () { die "bad group in $where" unless m/^[-a-z0-9+]+\.[-a-z0-9+._]+$/i; push @g, $&; } warn("too many from $where"), return if $toomanyenf && @g > $maxperuser; map { $yes{$_}=1; } @g; printf "%-20s - %4d groups\n",$where,scalar(@g); } work/newsrc-lg/newsrc-listgroups0000755000000000000000000000315714141560754014304 0ustar #!/usr/bin/perl # # Copyright 1996-2013 Ian Jackson # Copyright 1998 David Damerell # Copyright 1999,2003 # Chancellor Masters and Scholars of the University of Cambridge # Copyright 2010 Tony Finch # # This 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 userv-utils; if not, see http://www.gnu.org/licenses/. $minreaddays= 21; $maxperuser= 250; open(CONF,"$ARGV[0]") or die $!; while() { next if m/^\#/ || !m/^\S/; next if m/^(myfqdn|xref|server|server-nosearch|fetch|read|post|permit|believe|extrarc)\s/; if (m/^minreaddays\s+(\d+)\s+$/) { $minreaddays= $1; } elsif (m/^maxperuser\s+(\d+)\s+$/) { $maxperuser= $1; } else { die "$_ ?"; } } $newsrc= ".newsrc"; exit 0 if -l $newsrc || ! -f _ || -M _ > $minreaddays; @g= (); open NEWSRC, $newsrc or die $!; while () { next unless s/:.*\n$//; next unless m/^[-a-z0-9+]+\.[-a-z0-9+._]+$/i; push @g, "$_\n"; } close NEWSRC or die $!; exit 0 if @g > $maxperuser; print sort @g or die $!; close STDOUT or die $!; exit 0; work/newsrc-lg/services0000644000000000000000000000111614141560754012403 0ustar # # Every user's newsrc is checked by the newsrc-listgroups program # and if it hasn't got too many groups in it, they will be fetched. # # The service should spit out a list of legal newsgroup names, # and will always be invoked by something in group news. reset no-set-environment suppress-args ignore-fd 0 if ! glob calling-group news error Sorry (caller). fi if ! grep service-user-shell /etc/shells message Warning - newsrc-listgroups for user whose shell not in shells execute /bin/true quit fi execute /usr/local/lib/news/feed+read/newsrc-listgroups /etc/news/nntp-merge.conf work/settings.make0000644000000000000000000000307214141560754011436 0ustar # common makefile settings for userv-utils # Copyright 1996-2013,2016 Ian Jackson # Copyright 1998 David Damerell # Copyright 1999,2003 # Chancellor Masters and Scholars of the University of Cambridge # Copyright 2010 Tony Finch # # This 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 userv-utils; if not, see http://www.gnu.org/licenses/. etcdir= /etc prefix= /usr/local bindir= $(prefix)/bin sbindir= $(prefix)/sbin vardir= /var libdir= $(prefix)/lib sharedir= $(prefix)/share docdir= $(sharedir)/doc libuserv= $(libdir)/userv shareuserv= $(sharedir)/userv varlog= $(vardir)/log varlib= $(vardir)/lib varlibuserv= $(varlib)/userv etcuserv= $(etcdir)/userv services= $(etcuserv)/services.d CFLAGS= -Wall -Wwrite-strings -Wmissing-prototypes -Wstrict-prototypes \ -Wpointer-arith -D_GNU_SOURCE -Wno-pointer-sign \ $(OPTIMISE) $(DEBUG) $(SUBDIR_CFLAGS) LDFLAGS= $(SUBDIR_LDFLAGS) $(DEBUG) OPTIMISE= -O2 DEBUG= -g depr ?= disable # set depr to '' to enable deprecated output work/ucgi/0000755000000000000000000000000014141560754007664 5ustar work/ucgi/.gitignore0000644000000000000000000000002014141560754011644 0ustar ucgi ucgitarget work/ucgi/INSTALL0000644000000000000000000000363314141560754010722 0ustar To install the www-cgi service: 1. Run make to build ucgi and ucgitarget. 2. Create the directory /usr/local/lib/user-cgi/cgi 3. Install the programs: (a) ucgitarget as /usr/local/lib/user-cgi/target (b) ucgi as /usr/local/lib/user-cgi/ucgi (c) a symlink /usr/local/lib/user-cgi/ucgi-debug -> ucgi (d) the script `check' as /usr/local/lib/user-cgi/check 4. Put the extra ScriptAlias directives in srm.conf.fragment in the appropriate part of your webserver configuration. 5. Install the userv service: (a) Put the file www-cgi in /etc/userv/services.d (you may need to adjust it for your local configuration) (b) If you don't already have it, add this line to /etc/userv/system.default: include-lookup service /etc/userv/services.d 6. As a test user, create a `public-cgi' directory, and a symlink in it called `check' which points to /usr/local/lib/user-cgi/check. 7. Test that all is working by visiting http://www.example.com/ucgi-debug/~fred/check http://www.example.com/ucgi/~fred/check Copyright 1996-2013 Ian Jackson Copyright 1998 David Damerell Copyright 1999,2003 Chancellor Masters and Scholars of the University of Cambridge Copyright 2010 Tony Finch Copyright 2013,2016 Mark Wooding All the utilities here are 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 userv-utils; if not, see http://www.gnu.org/licenses/. work/ucgi/Makefile0000644000000000000000000000322614141560754011327 0ustar # Copyright 1996-2013,2016 Ian Jackson # Copyright 1998 David Damerell # Copyright 1999,2003 # Chancellor Masters and Scholars of the University of Cambridge # Copyright 2010 Tony Finch # Copyright 2013,2016 Mark Wooding # # This 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 userv-utils; if not, see http://www.gnu.org/licenses/. include ../settings.make uslibdir= $(libdir)/userv/ucgi uslibcgidir= $(uslibdir)/cgi usdocdir= $(docdir)/userv-ucgi TARGETS= ucgi ucgitarget all: $(TARGETS) OBJS= ucgi.o ucgitarget.o ucgicommon.o ucgi: ucgi.o ucgicommon.o ucgitarget: ucgitarget.o ucgicommon.o $(OBJS): ucgi.h install: all mkdir -p $(uslibcgidir) cp -b ucgitarget $(uslibdir)/target cp -b ucgi $(uslibcgidir)/ ln -sf ucgi $(uslibcgidir)/ucgi-debug install-examples: install-docs: mkdir -p $(usdocdir)/examples cp INSTALL README.custom-env-filter $(usdocdir)/. cp srm.conf.fragment $(usdocdir)/examples/. sed -e 's#/usr/local#$(prefix)#' user-cgi.text \ >$(usdocdir)/userv-cgi.text clean distclean realclean: rm -f $(TARGETS) *.o work/ucgi/README.custom-env-filter0000644000000000000000000000225414141560754014131 0ustar Allow customization of the environment filters. Sites can configure ucgi's environment filters, and end users can configure ucgitarget's filters. By default, ucgi will look in /etc/userv/ucgi.env-filter, but if UCGI_ENV_FILTER is set in its environment, it will look there instead. The filter may contain wildcards and so on. By default, ucgitarget looks in .userv/ucgitarget.env-filter, or /etc/userv/ucgitarget.env-filter, if the former doesn't exist; but if passed a `-e FILTER' option on its command line, it will look in the file FILTER instead. This filter may /not/ contain wildcards. In both cases, if an explicitly named filter file can't be found then the program fails; if the default filter files can't be found then they fall back to built-in lists. The reason for the asymmetry in interfaces is: it's hard to pass command-line options to CGI scripts from webservers, but pretty easy to set environment variables; whereas it's hard to pass environment variables to a service program in a Userv configuration file, but easy to pass command-line arguments. The `?DEFAULTS' pattern can be specified to match the default set (which is different in `ucgi' and `ucgitarget'). work/ucgi/check0000755000000000000000000000013714141560754010670 0ustar #!/bin/sh echo "Content-type: text/plain" echo echo "ucgi check - args:" "$@" printenv | sort work/ucgi/srm.conf.fragment0000644000000000000000000000015214141560754013134 0ustar ScriptAlias /ucgi/ /usr/lib/user-cgi/cgi/ucgi/ ScriptAlias /ucgi-debug/ /usr/lib/user-cgi/cgi/ucgi-debug/ work/ucgi/ucgi.c0000644000000000000000000001066214141560754010764 0ustar /* * Usage: as CGI script */ /* * Copyright 1996-2013,2016 Ian Jackson * Copyright 1998 David Damerell * Copyright 1999,2003 * Chancellor Masters and Scholars of the University of Cambridge * Copyright 2010 Tony Finch * Copyright 2013,2016 Mark Wooding * * This 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 userv-utils; if not, see http://www.gnu.org/licenses/. */ #include #include #include #include #include #include #include "ucgi.h" static const char *const default_envok[] = { "AUTH_TYPE", "CONTENT_TYPE", "CONTENT_LENGTH", "DOCUMENT_ROOT", "GATEWAY_INTERFACE", "HTTP_*", "HTTPS", "PATH_INFO", "PATH_TRANSLATED", "QUERY_STRING", "REDIRECT_*", "REMOTE_*", "REQUEST_METHOD", "REQUEST_URI", "SCRIPT_*", "SERVER_*", "SSL_*", 0 }; struct buildargs { const char **v; int n, max; }; static void addarg(struct buildargs *args, const char *a) { if (args->n > args->max) error("too many arguments", 500); args->v[args->n++]= a; } static void add_userv_var(const char *fulln, const char *en, const char *ev, void *p) { struct buildargs *args= p; size_t l; char *a; l= strlen(ev); if (l > MAX_ENVVAR_VALUE) error("environment variable too long", 500); a= xmalloc(strlen(en)+l+6); sprintf(a,"-DE_%s=%s",en,ev); addarg(args, a); } int main(int argc, const char **argv) { char *username; const char *slash2, *pathi, *ev, *av; const char *const *envok = 0; size_t usernamelen, l; struct buildargs args; pid_t child, rchild; int status; l= strlen(argv[0]); if (l>6 && !strcmp(argv[0]+l-6,"-debug")) debugmode= 1; if (debugmode) { if (fputs("Content-Type: text/plain\n\n",stdout)==EOF || fflush(stdout)) syserror("write stdout"); if (dup2(1,2)<0) { perror("dup stdout to stderr"); exit(-1); } D( printf(";;; UCGI\n"); ) } if (argc > MAX_ARGS) error("too many arguments", 500); ev= getenv("UCGI_ENV_FILTER"); if (ev) envok= load_filters(LOADF_MUST, ev, LF_END); else envok= load_filters(0, "/etc/userv/ucgi.env-filter", LF_END); pathi= getenv("PATH_INFO"); if (!pathi) error("PATH_INFO not found", 500); D( if (debugmode) { printf(";; find user name...\n" ";; initial PATH_INFO = `%s'\n", pathi); } ) if (pathi[0] != '/' || pathi[1] != '~') error("PATH_INFO must start with /~", 400); slash2= strchr(pathi+2,'/'); if (!slash2) error("PATH_INFO must have more than one /", 400); usernamelen= slash2-(pathi+2); if (usernamelen > MAX_USERNAME_LEN) error("PATH_INFO username too long", 400); username= xmalloc(usernamelen+1); memcpy(username,pathi+2,usernamelen); username[usernamelen]= 0; D( if (debugmode) printf(";; user = `%s'; tail = `%s'\n", username, slash2); ) if (!isalpha(username[0])) error("username 1st character is not alphabetic", 400); xsetenv("PATH_INFO",slash2,1); args.n= 0; args.max= argc + MAX_ENVVARS + 10; args.v= xmalloc(args.max * sizeof(*args.v)); addarg(&args, "userv"); if (debugmode) addarg(&args, "-DDEBUG=1"); filter_environment(FILTF_WILDCARD, "", envok, default_envok, add_userv_var, &args); addarg(&args, username); addarg(&args, "www-cgi"); while ((av= (*++argv))) addarg(&args, av); addarg(&args, 0); if (debugmode) { D( fflush(stdout); ) child= fork(); if (child==-1) syserror("fork"); if (child) { rchild= waitpid(child,&status,0); if (rchild==-1) syserror("waitpid"); printf("\nexit status %d %d\n",(status>>8)&0x0ff,status&0x0ff); exit(0); } } D( if (debugmode) { int i; printf(";; final command line...\n"); for (i = 0; args.v[i]; i++) printf(";; %s\n", args.v[i]); fflush(stdout); } ) execvp("userv",(char*const*)args.v); syserror("exec userv"); return -1; } work/ucgi/ucgi.h0000644000000000000000000000350514141560754010767 0ustar /* * Copyright 1996-2013,2016 Ian Jackson * Copyright 1998 David Damerell * Copyright 1999,2003 * Chancellor Masters and Scholars of the University of Cambridge * Copyright 2010 Tony Finch * Copyright 2013,2016 Mark Wooding * * This 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 userv-utils; if not, see http://www.gnu.org/licenses/. */ #ifndef UCGI_H #define UCGI_H #include #ifdef DEBUG # define D(x) x #else # define D(x) #endif #define MAX_ARGS 1024 #define MAX_USERNAME_LEN 1024 #define MAX_SCRIPTPATH_LEN 1024 #define MAX_ENVVAR_NAME 128 #define MAX_ENVVAR_VALUE (1024*1024) #define MAX_ENVVARS 256 void syserror(const char *m); void error(const char *m, int st); void *xmalloc(size_t sz); void xsetenv(const char *en, const char *ev, int overwrite); void *xrealloc(void *ptr, size_t sz); const char **load_filters(unsigned flags, const char *first, ...); #define LOADF_MUST 1u #define LF_END ((const char *)0) void filter_environment(unsigned flags, const char *prefix_in, const char *const *patv, const char *const *defaults, void (*foundone)(const char *fulln, const char *en, const char *ev, void *p), void *p); #define FILTF_WILDCARD 1u extern int debugmode; #endif work/ucgi/ucgicommon.c0000644000000000000000000001347014141560754012175 0ustar /* * Copyright 1996-2013,2016 Ian Jackson * Copyright 1998 David Damerell * Copyright 1999,2003 * Chancellor Masters and Scholars of the University of Cambridge * Copyright 2010 Tony Finch * Copyright 2013,2016 Mark Wooding * * This 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 userv-utils; if not, see http://www.gnu.org/licenses/. */ #include #include #include #include #include #include #include #include "ucgi.h" int debugmode= 0; static void outerror(void) { perror("stdout"); exit(debugmode ? 0 : -1); } void syserror(const char *m) { if (printf("Content-Type: text/plain\n" "Status: 500\n\n" "ucgi: system call error:\n" "%s: %s\n", m,strerror(errno))==EOF || fflush(stdout)) outerror(); exit(0); } void error(const char *m, int st) { if (printf("Content-Type: text/plain\n" "Status: %d\n\n" "ucgi: error:\n" "%s\n", st, m)==EOF || fflush(stdout)) outerror(); exit(0); } void *xmalloc(size_t sz) { void *r; r= malloc(sz); if (!r) syserror("malloc failed"); return r; } void *xrealloc(void *ptr, size_t sz) { void *r; r= realloc(ptr,sz); if (!r) syserror("realloc failed"); return r; } void xsetenv(const char *en, const char *ev, int overwrite) { if (setenv(en,ev,overwrite)) syserror("setenv"); } const char **load_filters(unsigned flags, const char *first, ...) { va_list ap; const char *name, *p, *q, **v; char *pp; size_t l, n, sz; FILE *fp; char buf[MAX_ENVVAR_NAME]; D( if (debugmode) printf(";; load_filters...\n"); ) va_start(ap, first); for (name= first; name; name= va_arg(ap, const char *)) { fp= fopen(name, "r"); if (fp) goto opened; D( if (debugmode) printf(";; file `%s': %s\n", name, strerror(errno)); ) if (errno != ENOENT) syserror("failed to open environment filters"); } va_end(ap); if (flags & LOADF_MUST) syserror("failed to open environment filters"); D( if (debugmode) printf(";; using default filters\n"); ) return 0; opened: va_end(ap); D( if (debugmode) printf(";; file `%s': OK\n", name); ) n= 0; sz= 128; v= xmalloc(sz * sizeof(*v)); for (;;) { if (!fgets(buf, sizeof(buf), fp)) break; l= strlen(buf); if (buf[l - 1] == '\n') buf[--l]= 0; if (l + 1 == sizeof(buf)) error("line too long in environment filter file", 500); p= buf; q= p + l; while (isspace((unsigned char)*p)) p++; while (q > p && isspace((unsigned char)q[-1])) q--; if (*p == '#' || p == q) continue; l= q - p; pp= xmalloc(l + 1); memcpy(pp, p, l); pp[l]= 0; v[n++]= pp; D( if (debugmode) printf(";; filter: `%s'\n", pp); ) if (n >= sz) { sz *= 2; v= xrealloc(v, sz * sizeof(*v)); } } if (ferror(fp)) syserror("failed to read environment filters"); fclose(fp); return v; } static int envvar_match(unsigned flags, const char *en, const char *const *patv, const char *const *defaults, const char **ev) { const char *const *patp; const char *q, *pat; int acceptp; int rc; if (!patv) { patv= defaults; defaults= 0; } for (patp= patv; (pat= *patp); patp++) { q= en; acceptp= 1; if (*pat == '!' && (flags & FILTF_WILDCARD)) { acceptp= 0; pat++; } else if (*pat == '?') { if (strcmp(pat + 1, "DEFAULTS") == 0) { assert(defaults); rc= envvar_match(flags, en, defaults, 0, ev); if (rc) return rc; } else error("unknown pattern directive", 500); continue; } for (;;) { if (!*pat) { if (*q != '=') { D( if (debugmode) printf(";; mismatch `%s' (prefix)\n", *patp); ) break; } D( if (debugmode) printf(";; matched pattern `%s'\n", *patp); ) goto match; } else if (*pat == '*' && (flags & FILTF_WILDCARD)) { q = strchr(q, '='); if (!q) { D( if (debugmode) printf(";; mismatch `%s' (discard: no `=')\n", *patp); ) return -1; } D( if (debugmode) printf(";; wildcard match for `%s'\n", *patp); ) goto match; } else { if (*pat++ != *q++) { D( if (debugmode) printf(";; mismatch `%s'\n", *patp); ) break; } } } } return 0; match: if (!acceptp) return -1; *ev= q + 1; return +1; } void filter_environment(unsigned flags, const char *prefix_in, const char *const *patv, const char *const *defaults, void (*foundone)(const char *fulln, const char *en, const char *ev, void *p), void *p) { char *const *ep; const char *en, *ev; char enbuf[MAX_ENVVAR_NAME]; size_t n, pn = strlen(prefix_in); D( if (debugmode) printf(";; filter_environment...\n"); ) for (ep= environ; (en= *ep); ep++) { D( if (debugmode) printf(";; consider env-var `%s'\n", en); ) if (strncmp(en, prefix_in, pn) != 0 || !en[pn]) { D( if (debugmode) printf(";; doesn't match prefix\n"); ) continue; } if (envvar_match(flags, en + pn, patv, defaults, &ev) > 0) { n= strcspn(en, "="); if (n >= sizeof(enbuf)) error("environment variable name too long", 500); memcpy(enbuf, en, n); enbuf[n]= 0; D( if (debugmode) printf(";; full = `%s'; tail = `%s'; value = `%s'\n", enbuf, enbuf + pn, ev); ) foundone(enbuf, enbuf + pn, ev, p); } } } work/ucgi/ucgitarget.c0000644000000000000000000001412414141560754012170 0ustar /* * Usage: as CGI script, but called by userv * environment variables are USERV_U_E_... */ /* * Copyright 1996-2013,2016 Ian Jackson * Copyright 1998 David Damerell * Copyright 1999,2003 * Chancellor Masters and Scholars of the University of Cambridge * Copyright 2010 Tony Finch * Copyright 2013,2016 Mark Wooding * * This 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 userv-utils; if not, see http://www.gnu.org/licenses/. */ #include #include #include #include #include #include #include #include #include "ucgi.h" static const char *const default_envok[]= { "AUTH_TYPE", "CONTENT_LENGTH", "CONTENT_TYPE", "DOCUMENT_ROOT", "GATEWAY_INTERFACE", "HTTP_ACCEPT", "HTTP_ACCEPT_CHARSET", "HTTP_ACCEPT_ENCODING", "HTTP_ACCEPT_LANGUAGE", "HTTP_CACHE_CONTROL", "HTTP_CONNECTION", "HTTP_CONTENT_ENCODING", "HTTP_COOKIE", "HTTP_DNT", "HTTP_HOST", "HTTP_KEEP_ALIVE", "HTTP_NEGOTIATE", "HTTP_PRAGMA", "HTTP_REFERER", "HTTP_USER_AGENT", "HTTP_VIA", "HTTP_X_FORWARDED_FOR", "HTTPS", "PATH_INFO", "PATH_TRANSLATED", "QUERY_STRING", "REDIRECT_HANDLER", "REDIRECT_SCRIPT_URI", "REDIRECT_SCRIPT_URL", "REDIRECT_STATUS", "REDIRECT_URL", "REMOTE_ADDR", "REMOTE_HOST", "REMOTE_USER", "REMOTE_IDENT", "REQUEST_METHOD", "REQUEST_URI", "SCRIPT_FILENAME", "SCRIPT_NAME", "SCRIPT_URI", "SCRIPT_URL", "SERVER_ADDR", "SERVER_ADMIN", "SERVER_NAME", "SERVER_PORT", "SERVER_PROTOCOL", "SERVER_SIGNATURE", "SERVER_SOFTWARE", "SSL_CIPHER", "SSL_CLIENT_S_DN", "SSL_CLIENT_VERIFY", "SSL_PROTOCOL", 0 }; static void setenvar(const char *fulln, const char *en, const char *ep, void *p) { xsetenv(en, ep, 1); unsetenv(fulln); } int main(int argc, char **argv) { char *scriptpath, *newvar; const char *nextslash, *lastslash, *pathi, *ev, *ev2, *scriptdir, *av; const char *const *envok; const char **arguments; size_t scriptdirlen, scriptpathlen, l; struct stat stab; int i, r, nargs; const char *filters= 0; ev= getenv("USERV_U_DEBUG"); if (ev && *ev) debugmode= 1; D( if (debugmode) printf(";;; UCGITARGET\n"); ) if (argc > MAX_ARGS) error("too many arguments", 500); for (;;) { i= getopt(argc, argv, "+e:"); if (i < 0) break; switch (i) { case 'e': filters= optarg; break; default: error("bad command line", 500); break; } } argc -= optind; argv += optind; if (!*argv) error("no script directory argument", 500); ev= getenv("HOME"); if (!ev) error("no HOME env. var", 500); l= strlen(*argv)+strlen(ev); newvar= xmalloc(l+2); sprintf(newvar,"%s/%s",ev,*argv); scriptdir= newvar; scriptdirlen= strlen(scriptdir); if (filters) envok= load_filters(LOADF_MUST, filters, LF_END); else { envok= load_filters(0, ".userv/ucgitarget.env-filter", "/etc/userv/ucgitarget.env-filter", LF_END); } filter_environment(0, "USERV_U_E_", envok, default_envok, setenvar, 0); scriptpath= 0; pathi= getenv("PATH_INFO"); if (!pathi) error("PATH_INFO not found", 500); lastslash= pathi; D( if (debugmode) { printf(";; find script name...\n" ";; PATH_INFO = `%s'\n", pathi); } ) for (;;) { if (*lastslash != '/') error("PATH_INFO expected slash not found", 400); if (lastslash[1]=='.' || lastslash[1]=='#' || !lastslash[1]) error("bad char begin", 400); nextslash= strchr(lastslash+1,'/'); if (!nextslash) nextslash= lastslash+1+strlen(lastslash+1); if (!nextslash) error("insufficient elements in PATH_INFO", 400); if (nextslash==lastslash+1) error("empty component in PATH_INFO", 400); if (nextslash-pathi > MAX_SCRIPTPATH_LEN) error("PATH_INFO script path too long", 400); scriptpathlen= scriptdirlen+(nextslash-pathi); scriptpath= xrealloc(scriptpath,scriptpathlen+1); strcpy(scriptpath,scriptdir); memcpy(scriptpath+scriptdirlen,pathi,nextslash-pathi); scriptpath[scriptpathlen]= 0; if (scriptpath[scriptpathlen-1]=='~') error("bad char end", 400); D( if (debugmode) printf(";; try `%s'\n", scriptpath); ) r= stat(scriptpath,&stab); if (r) syserror("stat script"); if (S_ISREG(stab.st_mode)) break; if (!S_ISDIR(stab.st_mode)) error("script not directory or file", 500); lastslash= nextslash; } D( if (debugmode) printf(";; found script: tail = `%s'\n", nextslash); ) if (*nextslash) xsetenv("PATH_INFO",nextslash,1); else unsetenv("PATH_INFO"); newvar= xmalloc(scriptpathlen+strlen(nextslash)+3); sprintf(newvar,"%s%s",scriptpath,nextslash); xsetenv("PATH_TRANSLATED",newvar,1); xsetenv("SCRIPT_FILENAME",scriptpath,1); ev= getenv("SCRIPT_NAME"); if (ev) { ev2= getenv("USER"); if (!ev2) error("no USER variable", 500); newvar= xmalloc(strlen(ev)+2+strlen(ev2)+scriptpathlen-scriptdirlen+2); sprintf(newvar,"%s/~%s%s",ev,ev2,scriptpath+scriptdirlen); xsetenv("SCRIPT_NAME",newvar,1); } arguments= xmalloc(sizeof(const char*)*(argc+5)); nargs= 0; arguments[nargs++]= scriptpath; while ((av= (*++argv))) arguments[nargs++]= av; arguments[nargs++]= 0; D( if (debugmode) { int i; printf(";; final environment...\n"); for (i = 0; environ[i]; i++) printf(";; %s\n", environ[i]); printf(";; final command line...\n"); for (i = 0; arguments[i]; i++) printf(";; %s\n", arguments[i]); fflush(stdout); } ) execvp(scriptpath,(char*const*)arguments); syserror("exec script"); return -1; } work/ucgi/user-cgi.text0000644000000000000000000001126714141560754012317 0ustar Users can arrange to have CGI scripts run by the webserver. This is achieved using userv (see ). Before you write such scripts you should be aware of the security issues involved. Paths in the http space of the form /ucgi/~//... will be taken to refer to the CGI script ~/public-cgi/ and / will be used as the PATH_INFO (as is conventional). For example, http://www.example.com/ucgi/~ijackson/spong/foo?bar=baz will run ~ijackson/public-cgi/spong with PATH_INFO set to `/foo' and QUERY_STRING set to `bar=baz'. You can debug your scripts by using /ucgi-debug/~/... which will return a text/plain document consisting of the standard output and standard error of your script and a line at the bottom with the high and low bytes of the script's exit status. Also, /usr/local/lib/user-cgi/cgi/check is a script which will dump its arguments and environment as a text/plain output file. This can be used to see what input your CGI program ought to expect. The default configuration does not enable userv's `set-environment' feature, so the environment your scripts in will be rather minimal. You can change this it if you want by saying something like if glob service www-cgi set-environment fi in your ~/.userv/rc file. This will cause your scripts to be run by a shell which has sourced your ~/.environment file, if it exists. See the userv documentation for details, and look in /etc/environment. CGI programs will be run in your account. They will be able to access files exactly as if you had run them yourself directly. Their PATH and other similar variables will be set correctly (see below) and can and should be trusted. However, their arguments, input and webserver-provided environment variables (the full list is in ucgicommon.c) will have come from the client WWW browser and are highly untrustworthy. This means you must be very careful when writing such programs. Beware particularly of * buffer overruns in C * trusting data not to have metacharacters. You should generally not pass client-provided data to - eval (Perl or shell) - system (Perl or C) and exec (Perl) - open (Perl) and popen (C) - anything similar. Safely using untrusted client-provided data in shell scripts is very difficult. I would recommend against programming CGI scripts in shell. If you must, make sure you use appropriate quoting and argument unparsing everywhere (and don't do it if you don't know what I mean by argument unparsing). The invocation of user-provided CGI scripts is achieved by using userv to invoke the `www-cgi' service. The webserver-provided environment variables will be passed as userv parameters using -DE_=. The E_PATH_INFO parameter contains the portion of the path beyond the username. The default configuration (/etc/userv/system.default) arranges for www-cgi to run /usr/local/lib/user-cgi/target, which removes the USERV_E_ from the start of the webserver-provided environment variables and adjusts some of them for the script's actual location and the calls the actual script. `target' takes one parameter, the location of the user's public CGI directory relative to their home directory (`public-cgi' in the default configuration). It must be a relative path. You can run your own scripts from the command line by saying userv -DE_PATH_INFO=/