work/0000775000000000000000000000000014163725562006743 5ustar work/.gitignore0000664000000000000000000000040114163725562010726 0ustar *~ *.o tmp daemon client pcsum.h version.h *.sasp* *.lout* *.li autom4te.cache config.cache config.log config.h config.status Makefile *.new vd dist_tmp tilde slash-etc shipcheck userv-*.tar.gz build build-arch spec.dbk spec.tex spec.html spec.pdf work/COPYING0000664000000000000000000010451314163725562010002 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/INSTALL0000664000000000000000000001647614163725562010012 0ustar INSTALLATION INSTRUCTIONS: $ ./configure $ make # make install This will not install the documentation, which is shipped as pre-prepared HTML and PostScript as well as debiandoc-sgml source. Put that (spec.html/ and spec.ps) where you will. SYSTEM REQUIREMENTS: Programs: * md5sum (GNU textutils; alternatively, Colin Plumb's, as shipped with Debian in the `dpkg' package) - used during build only * GNU make * GCC is preferred but other compilers ought to work (though no portability testing has yet been done). ANSI C only. ints must be at least 32 bits. * A sensible `cat' which notices write errors (ie not SunOS4, BSD 4.3, or many others. GNU textutils has one. NB that this `cat' is used at runtime and must be first on the system default PATH, so probably in /bin.) * GNU m4 } if you don't want to change those bits of source * GNU flex } you can do without these C Library: * [v]snprintf - a real version, not just [v]sprintf with a wrapper that throws the argument away. * strsignal; * fnmatch; * BSD syslog(3); * strtoul; * memcpy, memset, memcpy; * realloc(0,size) must work and be equivalent to malloc(size). * free(0) must work and do nothing * (not varargs) and v[sf][n]printf. System interfaces: * setreuid(2), getreuid(2), getgroups(2), initgroups(3), with the ability for root to (a) swap euid and ruid and (b) give away all privilege by calling setreuid(ruid,ruid) twice. * wait3 and waitpid, with WNOHANG, WIFSIGNALED, WIFEXITEED, WTERMSIG, WEXITSTATUS and WCOREDUMP. * gid_t, uid_t, pid_t. * Unix-domain (AF_UNIX) stream sockets, for use with: * BSD sockets - socket(), bind(), listen(), accept(), connect(); * socketpair(2); * lstat(2) (though stat(2) will be safe on systems without symlinks, if you say -Dlstat=stat). * Pipes: * creating using pipe(2) and mkfifo(2); * proper interaction between open(O_RDWR), open(O_RDONLY), open(O_WRONLY), close(), dup2, EPIPE, SIGPIPE, &c. (ie, opening pipes with O_RDWR never blocks; EPIPE happens if you write with no readers; EOF happens if you read with no buffered data and writers); * POSIX signal handling - sigaction(2), sigprocmask(2), sigsuspend(2); * POSIX sessions - setsid(2) (for -daemon flag). To format the documentation: * debiandoc-sgml, and hence sp (aka nsgmls) and sgmlspm. * For PostScript output, dblatex and XeTeX. For debugging version (./configure --enable-debug): * initgroups(3) must use setgroups(2) and dynamic linking must allow overriding setgroups(2) for initgroups(3); EXIT STATUS CODES For information about uservd's exit status, see uservd(8). The daemon's per-request children will note the success level of its request in its exit status. This will not usually be logged unless it is higher than those listed below; they are presented here for completeness and as programming documentation. 2 - The connection was just an internal version check. 4 - The client requested that the service be disconnected. This includes normal termination, which is achieved by having the server tell the client that the service has completed and waiting for the client to tell it to disconnect. 8 - The client closed its end of the socket when this would not usually have been expected, causing an EPIPE or unexpected EOF in the server. This is not an error condition - it can happen, for example, if the client receives a fatal signal of some kind from its execution environment (eg its controlling terminal). 10 - The per-request child wishes the server to check whether it is still the uservd. 12 - The service failed onm the service side in an expected and controlled manner, for example because it was rejected in the configuration files. 16 - A fatal system call failure or other general error occurred, which ought not to have happened at all, barring system resource shortages. 20 - The client sent invalid data to the server, after the client dropped all its system privilege. On some systems this can be caused by a malicious calling user. SIGABRT/SIGIOT - The client sent invalid data to the server before it dropped all its system privileges, or some other unexpected internal error occurred. This can also occur if an attempt to block signals using sigprocmask fails. 0-3,5-7,9,11,13-15,17-19 are not currently used by normal children. REENTRANCY IN THE LIBC: We assume, both in the client and server, that it is safe to use one stdio stream in a signal handler which interrupts use of a _different_ stdio stream in another. We make sure using setvbuf that we have pre-allocated buffers so that stdio doesn't need to use malloc() when we actually read or write. stdio had better not do anything else weird. Furthermore, we assume that it is safe to use syslog in a signal handler which has interrupted a stdio operation (but we don't require that it be safe to invoke when the signal has interrupted a call to malloc, unless stdio makes gratuitous mallocs). openlog will already have been called (but syslog will not necessarily have been called). We assume that strerror is completely reentrant. PROBLEMS * `function declaration isn't a prototype' One some systems (at least some versions of NetBSD, for example), the SIG_IGN and SIG_DFL macros contain function declarations (as part of a typecast, presumably) which are not prototypes. The warning options that are used by default if the configure script detects that you're using a good GCC then cause the compilation to fail. You must use make CFLAGS=-O2 instead of just `make', thus suppressing warnings. The bug is actually in your system header files, for not specifying the number and types of arguments to signal handler functions when they cast in the SIG_IGN and SIG_DFL macros. DEBUGGING VERSION If you run configure with --enable-debug, a debugging version will be built. This will look in the current directory (the build directory) for the base of various things, including the IPC area (which you must therefore construct yourself). The debugging version will produce extra output at various points. It will not attempt to call setgroups(), instead just checking that the groups list is right, so it will work non-setuid if the daemon is invoked as the service user. The daemon won't fork for each request; instead, it will handle a single request and exit. There may be other changes. Consult the code for details. Making the debugging version of the client or daemon setuid root is probably a bad idea. They may not work if they are run as different users. COPYRIGHT This file, INSTALL, contains installation instructions and other details for userv. userv is copyright Ian Jackson and other contributors. See README for full authorship information. userv 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 . work/Makefile.in0000664000000000000000000001305414163725562011013 0ustar # userv - Makefile.in # # userv is copyright Ian Jackson and other contributors. # See README for full authorship information. # # 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 this program. If not, see . VERSION=@VERSION@ VEREXT=std CC=@CC@ CFLAGS=@CFLAGS@ $(XCFLAGS) -DVERSION='"$(VERSION)"' -DVEREXT='"$(VEREXT)"' $(WERROR) $(XCFLAGS) OPTIMISE=@OPTIMISE@ CPPFLAGS=@DEBUGDEFS@ $(XCPPFLAGS) LDLIBS=@DEBUGLIBS@ @LIBS@ $(XLDLIBS) M4=m4 M4FLAGS= LEX=flex MD5SUM=@MD5SUM_SIMPLE@ CWD=$(shell pwd) INSTALL_GROUP=0 # root or wheel INSTALL_FLAGS=-o root -g $(INSTALL_GROUP) INSTALL=@INSTALL@ INSTALL_PROGRAM=@INSTALL_PROGRAM@ $(INSTALL_FLAGS) INSTALL_DATA=@INSTALL_DATA@ $(INSTALL_FLAGS) INSTALL_DIR=$(INSTALL) -d INSTALL_DIR_ETC=$(INSTALL_DIR) prefix=@prefix@ exec_prefix=$(prefix) share_prefix=$(prefix)/share bindir=$(exec_prefix)/bin mandir=$(share_prefix)/man man1dir=$(mandir)/man1 man8dir=$(mandir)/man8 sbindir=$(exec_prefix)/sbin etcdir=/etc etcsubdir=$(etcdir)/userv docdir=$(share_prefix)/doc/userv TARGETS= daemon client TARGETS_DOC_PS= spec.pdf overview.pdf TARGETS_DOC_RM= $(TARGETS_DOC_PS) spec.html TARGETS_DOC= $(TARGETS_DOC_PS) spec.html/index.html MAN1PAGES= userv.1 MAN8PAGES= uservd.8 SOURCES= Makefile.in configure.in acconfig.h \ client.c common.h \ overlord.c process.c servexec.c \ daemon.h debug.c parser.c lib.c lib.h \ language.i4 lexer.l.m4 tokens.h.m4 CONFIG_RESULTS= config.status config.log config.h config.cache \ Makefile pcsum.h GENSHIP_CLEAN= lexer.l lexer.c tokens.h config.h.in spec.sgml $(TARGETS_DOC) GENSHIP= $(GENSHIP_CLEAN) configure all: $(TARGETS) docs: $(TARGETS_DOC) install: all $(INSTALL_DIR) $(addprefix $(DESTDIR), $(bindir) $(sbindir)) $(INSTALL_PROGRAM) -m 755 daemon $(DESTDIR)$(sbindir)/uservd $(INSTALL_PROGRAM) -m 4755 client $(DESTDIR)$(bindir)/userv set -e; for f in '' /default.d /services.d /override.d; do \ $(INSTALL_DIR_ETC) $(DESTDIR)$(etcsubdir)$$f; \ done set -e; for f in system.default system.override; do \ if test ! -f $(DESTDIR)$(etcsubdir)/$$f; then \ $(INSTALL_DATA) $$f $(DESTDIR)$(etcsubdir); \ fi; \ done install-strip: $(MAKE) INSTALL_PROGRAM='$(INSTALL_PROGRAM) -s' install install-doc install-docs: $(TARGETS_DOC) $(INSTALL_DIR) $(addprefix $(DESTDIR), \ $(docdir) $(docdir)/spec.html $(docdir)/examples \ $(mandir) $(man1dir) $(man8dir) \ ) $(INSTALL_DATA) -m 644 $(TARGETS_DOC_PS) $(DESTDIR)$(docdir)/. $(INSTALL_DATA) -m 644 spec.html/*.html \ $(DESTDIR)$(docdir)/spec.html/. $(INSTALL_DATA) -m 644 system.default system.override \ $(DESTDIR)$(docdir)/examples/. $(INSTALL_DATA) -m 644 $(MAN1PAGES) $(DESTDIR)$(man1dir) $(INSTALL_DATA) -m 644 $(MAN8PAGES) $(DESTDIR)$(man8dir) uninstall: rm -f $(bindir)/userv $(sbindir)/uservd uninstall-doc uninstall-docs: cd $docdir && rm -rf $(TARGETS_DOC_RM) check: @echo There is no validation suite for this package. daemon: overlord.o process.o servexec.o parserlexer.o debug.o lib.o both.o $(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS) client: client.o both.o $(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS) lexer.l: language.i4 spec.sgml: spec.sgml.in Makefile sed -e '/<\/version>/ s/>/&$(VERSION)/' \ spec.sgml.in >$@.new && mv -f $@.new $@ client.o: config.h common.h pcsum.h both.h version.h process.o: config.h common.h pcsum.h both.h daemon.h lib.h tokens.h overlord.o: config.h common.h pcsum.h daemon.h servexec.o: config.h common.h pcsum.h daemon.h lib.h version.h lib.o: config.h common.h lib.h debug.o: config.h common.h pcsum.h daemon.h lib.h tokens.h parserlexer.o: lexer.c parser.c config.h common.h pcsum.h daemon.h lib.h tokens.h # lexer.c #include's parser.c at the end. Blame flex. $(CC) -c $(CPPFLAGS) $(CFLAGS) lexer.c -o $@ pcsum.h: common.h config.h config.status Makefile cat $^ | $(MD5SUM) \ | sed -e 's/ -$$//; s/../0x&,/g; s/,$$//;' \ >pcsum.h.new cmp pcsum.h.new pcsum.h || mv -f pcsum.h.new pcsum.h @rm -f pcsum.h.new version.h: Makefile echo '#define VERSION "$(VERSION)"' >$@.new && mv -f $@.new $@ tokens.h: language.i4 autoconf configure: autoheader autoconf clean: find -name '*.orig' -o -name '*~' -o -name '.*~' \ -o -name '*#' -o -name '.#*' -o -name '*.bak' \ | xargs -r rm rm -rf $(TARGETS) *.o core version.h rm -f overview.eps rm -f spec.lout* spec.text* spec.ps* spec.sgml.new spec.tex rm -f lout.li *.ld *.lix *.ldx rm -f userv-*.tar.gz vd/* distclean mostlyclean: clean rm -f $(CONFIG_RESULTS) maintainer-clean: distclean rm -rf $(GENSHIP_CLEAN) spec.html/*.html linecount: $(SOURCES) wc -l $^ %.dbk: %.sgml debiandoc2dbk -1 $< %.html/index.html: %.sgml debiandoc2html $< %.pdf: %.dbk dblatex -b xetex $< mv -f $<.pdf $@ overview.pdf: overview.fig SOURCE_DATE_EPOCH=$$(stat -c %Y overview.fig) \ fig2dev -L pdf -c -F -l dummy_arg -z A4 $< >$@.new mv $@.new $@ %.l: %.l.m4 $(M4) $(M4FLAGS) -- $< >$@.new && mv $@.new $@ %.h: %.h.m4 $(M4) $(M4FLAGS) -- $< >$@.new && mv $@.new $@ %: %.m4 $(M4) $(M4FLAGS) -- $< >$@.new && mv $@.new $@ work/README0000664000000000000000000000340114163725562007621 0ustar This is userv, a trust boundary management service for Unix. Using userv, one program can call another without either of them having to trust the other completely. This enables applications such as mail delivery, cron, user-provided CGI scripts and so forth to operate without needing to be given root privilege. For installation requirements and instructions please see INSTALL. For usage documentation and discussion see the manual in spec.* (various formats via Debiandoc-SGML in spec.sgml). The WWW page is . There are two mailing lists: userv-discuss and userv-announce; both are managed by majordomo@chiark.greenend.org.uk. Send majordomo the word `help' for instructions on how to subscribe and unsubscribe. Please send bug reports and suggestions to userv-maint@chiark.greenend.org.uk, or to the userv-discuss mailing list if you are subscribed to it. userv is Copyright 1996-2021 Ian Jackson . Copyright 2021 Genome Research Limited apropos work by Matthew Vernon Copyright 2000 Ben Harris Copyright 2016-2017 Peter Benie userv 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 . work/acconfig.h0000664000000000000000000000603314163725562010667 0ustar /* * userv - acconfig.h * extra stuff for config.h.in (autoconf) * * userv is copyright Ian Jackson and other contributors. * See README for full authorship information. * * 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; if not, see . */ /* Define if EPROTO exists. */ #undef HAVE_EPROTO /* Define if LOG_AUTHPRIV exists. */ #undef HAVE_LOG_AUTHPRIV /* Define if WCOREDUMP exists. */ #undef HAVE_WCOREDUMP /* Define if function attributes a la GCC 2.5 and higher are available. */ #undef HAVE_GNUC25_ATTRIB /* Define if unused functions a la GCC 2.5 and higher are available. */ #undef HAVE_GNUC25_UNUSED /* Define if nonreturning functions a la GCC 2.5 and higher are available. */ #undef HAVE_GNUC25_NORETURN /* Define if printf-format argument lists a la GCC are available. */ #undef HAVE_GNUC25_PRINTFFORMAT @BOTTOM@ /* STRSIGNAL */ #ifndef HAVE_STRSIGNAL #define STRSIGNAL(x) "[platform has no strsignal!]" #endif /* VSNPRINTF */ #ifndef HAVE_VSNPRINTF # error "You must have vsnprintf! Without vsnprintf it is very hard to write secure programs. If you don't have it then your system libc is probably full of hideous buffer overrun security bugs. But, if you don't want to fix your system a portable snprintf can be found at http://www.ijs.si/software/snprintf/" #endif /* EPROTO */ #ifndef HAVE_EPROTO #define EPROTO 0 #endif /* LOG_AUTHPRIV */ #ifndef HAVE_LOG_AUTHPRIV #define LOG_AUTHPRIV LOG_AUTH #endif /* WCOREDUMP */ #ifndef HAVE_WCOREDUMP #define WCOREDUMP(x) 0 #endif /* GNU C attributes. */ #ifndef FUNCATTR #ifdef HAVE_GNUC25_ATTRIB #define FUNCATTR(x) __attribute__(x) #else #define FUNCATTR(x) #endif #endif /* GNU C printf formats, or null. */ #ifndef ATTRPRINTF #ifdef HAVE_GNUC25_PRINTFFORMAT #define ATTRPRINTF(si,tc) format(printf,si,tc) #else #define ATTRPRINTF(si,tc) #endif #endif #ifndef PRINTFFORMAT #define PRINTFFORMAT(si,tc) FUNCATTR((ATTRPRINTF(si,tc))) #endif /* GNU C nonreturning functions, or null. */ #ifndef ATTRNORETURN #ifdef HAVE_GNUC25_NORETURN #define ATTRNORETURN noreturn #else #define ATTRNORETURN #endif #endif #ifndef NONRETURNING #define NONRETURNING FUNCATTR((ATTRNORETURN)) #endif /* Combination of both the above. */ #ifndef NONRETURNPRINTFFORMAT #define NONRETURNPRINTFFORMAT(si,tc) FUNCATTR((ATTRPRINTF(si,tc),ATTRNORETURN)) #endif /* GNU C unused functions, or null. */ #ifndef ATTRUNUSED #ifdef HAVE_GNUC25_UNUSED #define ATTRUNUSED unused #else #define ATTRUNUSED #endif #endif #ifndef UNUSED #define UNUSED FUNCATTR((ATTRUNUSED)) #endif work/autogen.sh0000775000000000000000000000004514163725562010743 0ustar #!/bin/sh set -e autoheader autoconf work/both.c0000664000000000000000000000400614163725562010043 0ustar /* * userv - both.c * Useful very-low-level utility routines, used in both client and daemon. * These do not (and cannot) depend on infrastructure eg syscallerror, * because these are not the same. * * userv is copyright Ian Jackson and other contributors. * See README for full authorship information. * * 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; if not, see . */ /* Some nasty people can return 0/EOF + EINTR from stdio ! * These functions attempt to work around this braindamage by retrying * the call after clearerr. If this doesn't work then clearly your * libc is _completely_ fubar rather than just somewhat fubar. */ #include #include #include #include #include "config.h" #include "both.h" void *xmalloc(size_t s) { void *p; p= malloc(s?s:1); if (!p) syscallerror("malloc"); return p; } void *xrealloc(void *p, size_t s) { p= realloc(p,s); if (!p) syscallerror("realloc"); return p; } char *xstrsave(const char *s) { char *r; r= xmalloc(strlen(s)+1); strcpy(r,s); return r; } int working_getc(FILE *file) { int c; for (;;) { c= getc(file); if (c != EOF || errno != EINTR) return c; clearerr(file); } } size_t working_fread(void *ptr, size_t sz, FILE *file) { size_t done, nr; done= 0; for (;;) { nr= fread((char*)ptr + done, 1, sz-done, file); done += nr; if (done == sz || !ferror(file) || errno != EINTR) return done; clearerr(file); } } work/both.h0000664000000000000000000000235514163725562010055 0ustar /* * userv - both.h * Useful very-low-level utility routines' declarations, * for both client and daemon. * * userv is copyright Ian Jackson and other contributors. * See README for full authorship information. * * 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; if not, see . */ #ifndef BOTH_H #define BOTH_H /* provided by both.c */ void *xmalloc(size_t s); void *xrealloc(void *p, size_t s); char *xstrsave(const char *s); int working_getc(FILE *file); size_t working_fread(void *ptr, size_t sz, FILE *file); /* used by both.c, so must be present */ void syscallerror(const char *what) NONRETURNING; #define ISCHAR(iswotsit,ch) (iswotsit((unsigned char)(ch))) /*Feh!*/ #endif work/client.c0000664000000000000000000012547414163725562010402 0ustar /* * userv - client.c * client code * * userv is copyright Ian Jackson and other contributors. * See README for full authorship information. * * 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; if not, see . */ /* * Here too, we do some horrible asynchronous stuff with signals. * * The following objects &c. are used in signal handlers and so * must be protected by calls to blocksignals if they are used in * the main program: * stderr * swfile * * The following objects are used in the main program unprotected * and so must not be used in signal handlers: * srfile * fdsetup[].copyfd * fdsetup[].pipefd * * The following objects/functions are not modified/called after the * asynchronicity starts: * malloc * fdsetupsize * fdsetup[].mods * fdsetup[].filename * fdsetup[].oflags * results of argument parsing * * systemerror, swfile, fdsetup[].catpid and fdsetup[].killed are used * for communication between the main thread and the signal handlers. * * All the signal handlers save errno so that is OK too. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "config.h" #include "common.h" #include "both.h" #include "version.h" enum fdmodifiervalues { fdm_read= 00001, fdm_write= 00002, fdm_create= 00004, fdm_exclusive= 00010, fdm_truncate= 00020, fdm_append= 00040, fdm_sync= 00100, fdm_fd= 00200, fdm_wait= 01000, fdm_nowait= 02000, fdm_close= 04000, }; struct fdmodifierinfo { const char *string; int implies; int conflicts; int oflags; }; struct fdsetupstate { const char *filename; /* non-null iff this fd has been specified */ int copyfd; /* fd to copy, -1 unless mods & fdm_fd */ int mods, oflags, pipefd, killed; /* 0,0,-1,0 unless otherwise set */ pid_t catpid; /* -1 indicates no cat process */ }; enum signalsexitspecials { se_number=-100, se_numbernocore, se_highbit, se_stdout }; enum overridetypes { ot_none, ot_string, ot_file, ot_builtin }; struct constkeyvaluepair { const char *key, *value; }; /* Variables from command-line arguments */ static const char *serviceuser; static uid_t serviceuid; static struct fdsetupstate *fdsetup; static int fdsetupsize; static struct constkeyvaluepair *defvararray; static int defvaravail, defvarused; static unsigned long timeout; static int signalsexit=254; static int sigpipeok, hidecwd; static int overridetype= ot_none; static const char *overridevalue, *spoofuser=0; /* Other state variables */ static FILE *srfile, *swfile; static pid_t mypid; static uid_t myuid, spoofuid; static gid_t mygid, spoofgid, *gidarray; static int ngids; static struct opening_msg opening_mbuf; static const char *loginname; static char *cwdbuf; static size_t cwdbufsize; static char *ovbuf; static int ovused, systemerror, socketfd; static void blocksignals(int how) { sigset_t set; static const char blockerrmsg[]= "userv: failed to [un]block signals: "; const char *str; int unused; sigemptyset(&set); sigaddset(&set,SIGCHLD); sigaddset(&set,SIGALRM); if (sigprocmask(how,&set,0)) { str= strerror(errno); unused= write(2,blockerrmsg,sizeof(blockerrmsg)-1); unused= write(2,str,strlen(str)); unused= write(2,"\n",1); (void)unused; exit(-1); } } /* Functions which may be called either from signal handlers or from * the main thread. They block signals in case they are on the main * thread, and may only use signal handler objects. None of them * return. If they did they'd have to restore the signal mask. */ static void NONRETURNPRINTFFORMAT(1,2) miscerror(const char *fmt, ...) { va_list al; blocksignals(SIG_BLOCK); va_start(al,fmt); fprintf(stderr,"userv: failure: "); vfprintf(stderr,fmt,al); fprintf(stderr,"\n"); exit(-1); } static void NONRETURNPRINTFFORMAT(1,2) fsyscallerror(const char *fmt, ...) { va_list al; int e; e= errno; blocksignals(SIG_BLOCK); va_start(al,fmt); fprintf(stderr,"userv: system call failure: "); vfprintf(stderr,fmt,al); fprintf(stderr,": %s\n",strerror(e)); exit(-1); } void syscallerror(const char *what) { fsyscallerror("%s",what); } static void NONRETURNING protoreaderror(FILE *file, const char *where) { int e; e= errno; blocksignals(SIG_BLOCK); if (ferror(file)) { fprintf(stderr,"userv: failure: read error %s: %s\n",where,strerror(e)); } else { assert(feof(file)); fprintf(stderr,"userv: internal failure: EOF from server %s\n",where); } exit(-1); } static void NONRETURNPRINTFFORMAT(1,2) protoerror(const char *fmt, ...) { va_list al; blocksignals(SIG_BLOCK); va_start(al,fmt); fprintf(stderr,"userv: internal failure: protocol error: "); vfprintf(stderr,fmt,al); fprintf(stderr,"\n"); exit(-1); } /* * General-purpose functions; these do nothing special about signals, * except that they can call error-handlers which may block them * to print error messages. */ static void xfread(void *p, size_t sz, FILE *file) { size_t nr; nr= working_fread(p,sz,file); if (nr != sz) protoreaderror(file,"in data"); } static void xfwrite(const void *p, size_t sz, FILE *file) { size_t nr; nr= fwrite(p,1,sz,file); if (nr == sz) return; syscallerror("writing to server"); } static void xfflush(FILE *file) { if (fflush(file)) syscallerror("flush server socket"); } /* Functions which may be called only from the main thread. These may * use main-thread objects and must block signals before using signal * handler objects. */ #ifdef DEBUG static void priv_suspend(void) { } static void priv_resume(void) { } static void priv_permanentlyrevokesuspended(void) { } #else static void priv_suspend(void) { if (setreuid(0,myuid) != 0) syscallerror("suspend root setreuid(0,myuid)"); } static void priv_resume(void) { if (setreuid(myuid,0) != 0) syscallerror("resume root setreuid(myuid,0)"); } static void priv_permanentlyrevokesuspended(void) { if (setreuid(myuid,myuid) != 0) syscallerror("revoke root setreuid(myuid,myuid)"); if (setreuid(myuid,myuid) != 0) syscallerror("rerevoke root setreuid(myuid,myuid)"); if (myuid) { if (!setreuid(myuid,0)) miscerror("revoked root but setreuid(0,0) succeeded !"); if (errno != EPERM) syscallerror("revoked and setreuid(myuid,0) unexpected error"); } } #endif static void checkmagic(unsigned long was, unsigned long should, const char *when) { if (was != should) protoerror("magic number %s was %08lx, expected %08lx",when,was,should); } static void getprogress(struct progress_msg *progress_r, FILE *file) { int i, c; unsigned long ul; for (;;) { xfread(progress_r,sizeof(struct progress_msg),file); checkmagic(progress_r->magic,PROGRESS_MAGIC,"in progress message"); switch (progress_r->type) { case pt_failed: blocksignals(SIG_BLOCK); fputs("userv: uservd reports that service failed\n",stderr); exit(-1); case pt_errmsg: blocksignals(SIG_BLOCK); fputs("uservd: ",stderr); if (progress_r->data.errmsg.messagelen>MAX_ERRMSG_STRING) protoerror("stderr message length %d is far too long", progress_r->data.errmsg.messagelen); for (i=0; idata.errmsg.messagelen; i++) { c= working_getc(file); if (c==EOF) protoreaderror(file,"in error message"); if (ISCHAR(isprint,c)) putc(c,stderr); else fprintf(stderr,"\\x%02x",(unsigned char)c); } putc('\n',stderr); if (ferror(stderr)) syscallerror("printing error message"); xfread(&ul,sizeof(ul),file); checkmagic(ul,PROGRESS_ERRMSG_END_MAGIC,"after error message"); blocksignals(SIG_UNBLOCK); break; default: return; } } } /* * Functions which are called only during setup, before * the signal asynchronicity starts. They can do anything they like. */ /* This includes xmalloc and xrealloc from both.c */ static void xfwritestring(const char *s, FILE *file) { int l; l= strlen(s); assert(l<=MAX_GENERAL_STRING); xfwrite(&l,sizeof(l),file); xfwrite(s,sizeof(*s)*l,file); } static void xfwritefds(int modifier, int expected, FILE *file) { int i, fdcount; for (i=0, fdcount=0; i=fdsetupsize) continue; /* perhaps the caller gave us children */ if ((WIFEXITED(status) && WEXITSTATUS(status)==0) || (WIFSIGNALED(status) && WTERMSIG(status)==SIGPIPE) || (fdsetup[fd].killed && WIFSIGNALED(status) && WTERMSIG(status)==SIGKILL)) { if (swfile && fdsetup[fd].mods & fdm_read) { memset(&event_mbuf,0,sizeof(event_mbuf)); event_mbuf.magic= EVENT_MAGIC; event_mbuf.type= et_closereadfd; event_mbuf.data.closereadfd.fd= fd; r= fwrite(&event_mbuf,1,sizeof(event_mbuf),swfile); if (r != sizeof(event_mbuf) || fflush(swfile)) if (errno != EPIPE) syscallerror("inform service of closed read fd"); } } else { if (WIFEXITED(status)) fprintf(stderr,"userv: cat for fd %d exited with error exit status %d\n", fd,WEXITSTATUS(status)); else if (WIFSIGNALED(status)) if (WCOREDUMP(status)) fprintf(stderr,"userv: cat for fd %d dumped core due to signal %s (%d)\n", fd,strsignal(WTERMSIG(status)),WTERMSIG(status)); else fprintf(stderr,"userv: cat for fd %d terminated by signal %s (%d)\n", fd,strsignal(WTERMSIG(status)),WTERMSIG(status)); else fprintf(stderr,"userv: cat for fd %d gave unknown wait status %d\n", fd,status); disconnect(); } fdsetup[fd].catpid= -1; } errno= es; } /* * Argument parsing. These functions which are called only during * setup, before the signal asynchronicity starts. */ struct optioninfo; typedef void optionfunction(const struct optioninfo*, const char *value, char *key); struct optioninfo { int abbrev; const char *full; int values; /* 0: no value; 1: single value; 2: key and value */ optionfunction *fn; }; static void usage(FILE *stream) { if (fputs( "usage: userv [--] [ ...]\n" "usage: userv -B|--builtin [--] [ ...]\n" "options: -f|--file []=\n" " -D|--defvar =\n" " -t|--timeout \n" " -S|--signals |number|number-nocore|highbit|stdout\n" " -w|--fdwait =wait|nowait|close\n" " -P|--sigpipe -H|--hidecwd -h|--help|--version --copyright\n" " --override } available only\n" " --override-file } to root\n" " --spoof-user } or same user\n" "fdmodifiers: read write overwrite trunc[ate]\n" "(separate with commas) append sync excl[usive] creat[e] fd\n" "userv -B 'X' ... is same as userv --override 'execute-builtin X' - 'X' ...\n" " for help, type `userv -B help'; remember to quote multi-word X\n" "userv and uservd version " VERSION VEREXT ".\n" COPYRIGHT("","\n"), stream) < 0) syscallerror("write usage message"); } static void NONRETURNPRINTFFORMAT(1,2) usageerror(const char *fmt, ...) { va_list al; va_start(al,fmt); fputs("userv: ",stderr); vfprintf(stderr,fmt,al); fputs("\n\n",stderr); usage(stderr); exit(-1); } static const struct fdmodifierinfo fdmodifierinfos[]= { { "read", fdm_read, fdm_write, O_RDONLY }, { "write", fdm_write, fdm_read, O_WRONLY }, { "overwrite", fdm_write|fdm_create|fdm_truncate, fdm_read|fdm_fd|fdm_exclusive, O_WRONLY|O_CREAT|O_TRUNC }, { "create", fdm_write|fdm_create, fdm_read|fdm_fd, O_WRONLY|O_CREAT }, { "creat", fdm_write|fdm_create, fdm_read|fdm_fd, O_WRONLY|O_CREAT }, { "exclusive", fdm_write|fdm_create|fdm_exclusive, fdm_read|fdm_fd|fdm_truncate, O_WRONLY|O_CREAT|O_EXCL }, { "excl", fdm_write|fdm_create|fdm_exclusive, fdm_read|fdm_fd|fdm_truncate, O_WRONLY|O_CREAT|O_EXCL }, { "truncate", fdm_write|fdm_truncate, fdm_read|fdm_fd|fdm_exclusive, O_WRONLY|O_CREAT|O_EXCL }, { "trunc", fdm_write|fdm_truncate, fdm_read|fdm_fd|fdm_exclusive, O_WRONLY|O_CREAT|O_EXCL }, { "append", fdm_write|fdm_append, fdm_read|fdm_fd, O_WRONLY|O_CREAT|O_APPEND }, { "sync", fdm_write|fdm_sync, fdm_read|fdm_fd, O_WRONLY|O_CREAT|O_SYNC }, { "wait", fdm_wait, fdm_nowait|fdm_close, 0 }, { "nowait", fdm_nowait, fdm_wait|fdm_close, 0 }, { "close", fdm_close, fdm_wait|fdm_nowait, 0 }, { "fd", fdm_fd, fdm_create|fdm_exclusive|fdm_truncate|fdm_append|fdm_sync, 0 }, { 0 } }; static void addfdmodifier(int fd, const char *key, size_t key_len) { const struct fdmodifierinfo *fdmip; if (!*key) return; for (fdmip= fdmodifierinfos; fdmip->string && !(strlen(fdmip->string) == key_len && !memcmp(fdmip->string,key,key_len)); fdmip++); if (!fdmip->string) usageerror("unknown fdmodifer `%.*s' for fd %d", (int)key_len,key,fd); if (fdmip->conflicts & fdsetup[fd].mods) usageerror("fdmodifier `%.*s' conflicts with another for fd %d", (int)key_len,key,fd); fdsetup[fd].mods |= fdmip->implies; fdsetup[fd].oflags |= fdmip->oflags; } static void addfdmodifier_fixed(int fd, const char *key) { addfdmodifier(fd, key, strlen(key)); } static int fdstdnumber(const char *string, const char **delim_r) { #define FN(v,s) do{ \ if (!memcmp(string,s,sizeof(s)-1)) { \ *delim_r= string+sizeof(s)-1; \ return v; \ } \ }while(0) FN(0,"stdin"); FN(1,"stdout"); FN(2,"stderr"); return -1; } static int strtofd(const char *string, const char **mods_r /* 0: no modifiers, must go to end */, const char *what) { int fd; unsigned long ul; char *delim_v; const char *mods; fd= fdstdnumber(string,&mods); if (fd>=0) { if (*mods && *mods != ',') usageerror("%s, when it is `stdin', `stdout' or `stderr'," " must be delimited with a comma from any following" " modifiers - `%s' is not permitted", what, mods); goto parsed; } errno= 0; ul= strtoul(string,&delim_v,10); if (errno || delim_v == string || ul > INT_MAX) usageerror("%s must be must be numeric file descriptor" " or `stdin', `stdout' or `stderr'" " - `%s' is not recognized", what, string); mods= delim_v; fd= ul; parsed: if (*mods==',') mods++; if (mods_r) *mods_r= mods; else if (*mods) usageerror("%s must be must be only file descriptor" " - trailing portion or modifiers `%s' not permitted", what, mods); if (fd > MAX_ALLOW_FD) usageerror("%s file descriptor specified (%d)" " is larger than maximum allowed (%d)", what, fd, MAX_ALLOW_FD); return fd; } static void of_file(const struct optioninfo *oip, const char *value, char *key) { unsigned long fd, copyfd; struct stat stab; int oldarraysize, r; size_t mod_len; const char *mods, *delim; fd= strtofd(key,&mods,"first part of argument to -f or --file"); if (fd >= fdsetupsize) { oldarraysize= fdsetupsize; fdsetupsize+=2; fdsetupsize<<=1; fdsetup= xrealloc(fdsetup,sizeof(struct fdsetupstate)*fdsetupsize); while (oldarraysize < fdsetupsize) { fdsetup[oldarraysize].filename= 0; fdsetup[oldarraysize].pipefd= -1; fdsetup[oldarraysize].copyfd= -1; fdsetup[oldarraysize].mods= 0; fdsetup[oldarraysize].oflags= 0; fdsetup[oldarraysize].catpid= -1; fdsetup[oldarraysize].killed= 0; fdsetup[oldarraysize].filename= 0; oldarraysize++; } } fdsetup[fd].filename= value; fdsetup[fd].oflags= 0; fdsetup[fd].mods= 0; fdsetup[fd].copyfd= -1; while (mods && *mods) { delim= strchr(mods,','); mod_len= delim ? delim-mods : strlen(mods); addfdmodifier(fd,mods,mod_len); mods= delim ? delim+1 : 0; } if (!(fdsetup[fd].mods & (fdm_read|fdm_write))) { if (fd == 0) { addfdmodifier_fixed(fd,"read"); } else if (fdsetup[fd].mods & fdm_fd) { addfdmodifier_fixed(fd,"write"); } else { addfdmodifier_fixed(fd,"overwrite"); } } if (fdsetup[fd].mods & fdm_fd) { copyfd= strtofd(value,0, "value part of argument to --file with fd modifier"); r= fstat(copyfd,&stab); if (r) { if (oip) fsyscallerror("check filedescriptor %lu (named as target of file " "descriptor redirection for %lu)",copyfd,fd); else fsyscallerror("check basic filedescriptor %lu at program start",copyfd); } fdsetup[fd].copyfd= copyfd; } } static void of_fdwait(const struct optioninfo *oip, const char *value, char *key) { const struct fdmodifierinfo *fdmip; int fd; fd= strtofd(key,0,"first part of argument to --fdwait"); if (fd >= fdsetupsize || !fdsetup[fd].filename) usageerror("file descriptor %d specified in --fdwait option is not open",fd); for (fdmip= fdmodifierinfos; fdmip->string && strcmp(fdmip->string,value); fdmip++); if (!fdmip->string || !(fdmip->implies & (fdm_wait|fdm_nowait|fdm_close))) usageerror("value for --fdwait must be `wait', `nowait' or `close', not `%s'",value); fdsetup[fd].mods &= ~(fdm_wait|fdm_nowait|fdm_close); fdsetup[fd].mods |= fdmip->implies; } static void of_defvar(const struct optioninfo *oip, const char *value, char *key) { int i; if (!key[0]) usageerror("empty string not allowed as variable name"); if (strlen(key)>MAX_GENERAL_STRING) usageerror("variable name `%s' is far too long",key); if (strlen(value)>MAX_GENERAL_STRING) usageerror("variable `%s' has value `%s' which is far too long",key,value); for (i=0; i= MAX_ARGSDEFVAR) usageerror("far too many --defvar or -D options"); if (i>=defvaravail) { defvaravail+=10; defvaravail<<=1; defvararray= xrealloc(defvararray,sizeof(struct constkeyvaluepair)*defvaravail); } if (i==defvarused) defvarused++; defvararray[i].key= key; defvararray[i].value= value; } static void of_timeout(const struct optioninfo *oip, const char *value, char *key) { char *endp; unsigned long ul; errno= 0; ul= strtoul(value,&endp,10); if (errno || *endp) usageerror("timeout value `%s' must be a plain decimal string",value); if (ul>INT_MAX) usageerror("timeout value %lu too large",ul); timeout= ul; } static void of_signals(const struct optioninfo *oip, const char *value, char *key) { unsigned long numvalue; char *endp; errno= 0; numvalue= strtoul(value,&endp,10); if (errno || *endp) { if (!strcmp(value,"number")) signalsexit= se_number; else if (!strcmp(value,"number-nocore")) signalsexit= se_numbernocore; else if (!strcmp(value,"highbit")) signalsexit= se_highbit; else if (!strcmp(value,"stdout")) signalsexit= se_stdout; else usageerror("value `%s' for --signals not understood",value); } else { if (numvalue<0 || numvalue>255) usageerror("value %lu for --signals not 0...255",numvalue); signalsexit= numvalue; } } static void of_sigpipe(const struct optioninfo *oip, const char *value, char *key) { sigpipeok=1; } static void of_hidecwd(const struct optioninfo *oip, const char *value, char *key) { hidecwd=1; } static void of_help(const struct optioninfo *oip, const char *value, char *key) { usage(stdout); if (fclose(stdout)) syscallerror("fclose stdout after writing usage message"); exit(0); } static void of_version(const struct optioninfo *oip, const char *value, char *key) { if (puts(VERSION VEREXT) == EOF || fclose(stdout)) syscallerror("write version number"); exit(0); } static void of_copyright(const struct optioninfo *oip, const char *value, char *key) { if (fputs( " userv - user service daemon and client\n\n" COPYRIGHT(" ","\n") "\n" " This is free software; you can redistribute it and/or modify it under the\n" " terms of the GNU General Public License as published by the Free Software\n" " Foundation; either version 3 of the License, or (at your option) any\n" " later version.\n\n" " This program is distributed in the hope that it will be useful, but\n" " WITHOUT ANY WARRANTY; without even the implied warranty of\n" " MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General\n" " Public License for more details.\n\n" " You should have received a copy of the GNU General Public License along\n" " with userv; if not, see .\n", stdout) < 0) syscallerror("write usage to stderr"); exit(0); } static void of_builtin(const struct optioninfo *oip, const char *value, char *key) { overridetype= ot_builtin; } static void of_override(const struct optioninfo *oip, const char *value, char *key) { overridetype= ot_string; overridevalue= value; } static void of_overridefile(const struct optioninfo *oip, const char *value, char *key) { overridetype= ot_file; overridevalue= value; } static void of_spoofuser(const struct optioninfo *oip, const char *value, char *key) { spoofuser= value; } const struct optioninfo optioninfos[]= { { 'f', "file", 2, of_file }, { 'w', "fdwait", 2, of_fdwait }, { 'D', "defvar", 2, of_defvar }, { 't', "timeout", 1, of_timeout }, { 'S', "signals", 1, of_signals }, { 'P', "sigpipe", 0, of_sigpipe }, { 'H', "hidecwd", 0, of_hidecwd }, { 'B', "builtin", 0, of_builtin }, { 'h', "help", 0, of_help }, { 0, "version", 0, of_version }, { 0, "copyright", 0, of_copyright }, { 0, "override", 1, of_override }, { 0, "override-file", 1, of_overridefile }, { 0, "spoof-user", 1, of_spoofuser }, { 0, 0 } }; static void callvalueoption(const struct optioninfo *oip, char *arg) { char *equals; if (oip->values == 2) { equals= strchr(arg,'='); if (!equals) { if (oip->abbrev) usageerror("option --%s (-%c) passed argument `%s' with no `='", oip->full,oip->abbrev,arg); else usageerror("option --%s passed argument `%s' with no `='", oip->full,arg); } *equals++= 0; (oip->fn)(oip,equals,arg); } else { (oip->fn)(oip,arg,0); } } /* * Main thread main processing functions - in order of execution. */ static void security_init(void) { /* May not open any file descriptors. */ mypid= getpid(); if (mypid == (pid_t)-1) syscallerror("getpid"); myuid= getuid(); if (myuid == (uid_t)-1) syscallerror("getuid"); mygid= getgid(); if (mygid == (gid_t)-1) syscallerror("getgid"); ngids= getgroups(0,0); if (ngids == -1) syscallerror("getgroups(0,0)"); gidarray= xmalloc(sizeof(gid_t)*ngids); if (getgroups(ngids,gidarray) != ngids) syscallerror("getgroups(ngids,)"); priv_suspend(); if (ngids > MAX_GIDS) miscerror("caller is in far too many gids"); } static void parse_arguments(int *argcp, char *const **argvp) { static char fd0key[]= "stdin,fd,read"; static char fd1key[]= "stdout,fd,write"; static char fd2key[]= "stderr,fd,write"; char *const *argpp; char *argp; const struct optioninfo *oip; int fd; assert((*argvp)[0]); of_file(0,"stdin",fd0key); of_file(0,"stdout",fd1key); of_file(0,"stderr",fd2key); for (argpp= *argvp+1; (argp= *argpp) && *argp == '-' && argp[1]; argpp++) { if (!*++argp) usageerror("unknown option/argument `%s'",*argpp); if (*argp == '-') { /* Two hyphens */ if (!*++argp) { argpp++; break; /* End of options. */ } for (oip= optioninfos; oip->full && strcmp(oip->full,argp); oip++); if (!oip->full) usageerror("unknown long option `%s'",*argpp); if (oip->values) { if (!argpp[1]) usageerror("long option `%s' needs a value",*argpp); callvalueoption(oip,*++argpp); } else { (oip->fn)(oip,0,0); } } else { for (; *argp; argp++) { for (oip= optioninfos; oip->full && oip->abbrev != *argp; oip++); if (!oip->full) usageerror("unknown short option `-%c' in argument `%s'", *argp, *argpp); if (oip->values) { if (argp[1]) { argp++; } else { if (!argpp[1]) usageerror("short option `-%c' in argument `%s' needs" " a value",*argp,*argpp); argp= *++argpp; } callvalueoption(oip,argp); break; /* No more options in this argument, go on to the next one. */ } else { (oip->fn)(oip,0,0); } } } } if (overridetype == ot_builtin) { serviceuser= "-"; } else { if (!*argpp) usageerror("no service user given after options"); serviceuser= *argpp++; } if (!*argpp) usageerror(overridetype == ot_builtin ? "no service name given after options and service user" : "no builtin service given after options"); *argcp-= (argpp-*argvp); *argvp= argpp; if (*argcp > MAX_ARGSDEFVAR) usageerror("far too many arguments"); for (fd=0; fdpw_uid != myuid) loginname= 0; } if (!loginname) { pw= getpwuid(myuid); if (!pw) miscerror("cannot determine your login name"); loginname= xstrsave(pw->pw_name); } if (!strcmp(serviceuser,"-")) serviceuser= loginname; pw= getpwnam(serviceuser); if (!pw) miscerror("requested service user `%s' is not a user",serviceuser); serviceuid= pw->pw_uid; if ((overridetype != ot_none || spoofuser) && myuid != 0 && myuid != serviceuid) miscerror("--override and --spoof options only available to root or to" " the user who will be providing the service"); if (spoofuser) { loginname= spoofuser; pw= getpwnam(loginname); if (!pw) miscerror("spoofed login name `%s' is not valid",loginname); spoofuid= pw->pw_uid; spoofgid= pw->pw_gid; ngidssize= ngids; ngids= 0; if (ngidssize<5) { ngidssize= 5; gidarray= xrealloc(gidarray,sizeof(gid_t)*ngidssize); } gidarray[ngids++]= spoofgid; while ((gr= getgrent())) { /* ouch! getgrent has no error behaviour! */ for (mem= gr->gr_mem; *mem && strcmp(*mem,loginname); mem++); if (!*mem) continue; if (ngids>=ngidssize) { if (ngids>=MAX_GIDS) miscerror("spoofed user is member of too many groups"); ngidssize= (ngids+5)<<1; gidarray= xrealloc(gidarray,sizeof(gid_t)*ngidssize); } gidarray[ngids++]= gr->gr_gid; } } } static void determine_cwd(void) { cwdbufsize= 0; cwdbuf= 0; if (hidecwd) return; for (;;) { if (cwdbufsize > MAX_GENERAL_STRING) { cwdbufsize= 0; free(cwdbuf); break; } cwdbufsize <<= 1; cwdbufsize+= 100; cwdbuf= xrealloc(cwdbuf,cwdbufsize); cwdbuf[cwdbufsize-1]= 0; if (getcwd(cwdbuf,cwdbufsize-1)) { cwdbufsize= strlen(cwdbuf); break; } if (errno != ERANGE) { cwdbufsize= 0; free(cwdbuf); break; } } } static void process_override(const char *servicename) { FILE *ovfile; int ovavail, l, c; switch (overridetype) { case ot_none: ovused= -1; ovbuf= 0; break; case ot_builtin: l= strlen(servicename); if (l >= MAX_OVERRIDE_LEN-20) miscerror("builtin service string is too long (%d, max is %d)", l,MAX_OVERRIDE_LEN-21); l+= 20; ovbuf= xmalloc(l); snprintf(ovbuf,l,"execute-builtin %s\n",servicename); ovused= strlen(ovbuf); break; case ot_string: l= strlen(overridevalue); if (l >= MAX_OVERRIDE_LEN) miscerror("override string is too long (%d, max is %d)",l,MAX_OVERRIDE_LEN-1); ovbuf= xmalloc(l+2); snprintf(ovbuf,l+2,"%s\n",overridevalue); ovused= l+1; break; case ot_file: ovfile= fopen(overridevalue,"r"); if (!ovfile) fsyscallerror("open overriding configuration file `%s'",overridevalue); ovbuf= 0; ovavail= ovused= 0; while ((c= getc(ovfile)) != EOF) { if (!c) miscerror("overriding config file `%s' contains null(s)",overridevalue); if (ovused >= MAX_OVERRIDE_LEN) miscerror("override file is too long (max is %d)",MAX_OVERRIDE_LEN); if (ovused >= ovavail) { ovavail+=80; ovavail<<=2; ovbuf= xrealloc(ovbuf,ovavail); } ovbuf[ovused++]= c; } if (ferror(ovfile) || fclose(ovfile)) fsyscallerror("read overriding configuration file `%s'",overridevalue); ovbuf= xrealloc(ovbuf,ovused+1); ovbuf[ovused]= 0; break; default: abort(); } } static int server_connect(void) { struct sockaddr_un ssockname; int sfd; struct sigaction sig; sigset_t sset; sigemptyset(&sset); sigaddset(&sset,SIGCHLD); sigaddset(&sset,SIGALRM); sigaddset(&sset,SIGPIPE); if (sigprocmask(SIG_UNBLOCK,&sset,0)) syscallerror("preliminarily unblock signals"); sig.sa_handler= SIG_IGN; sigemptyset(&sig.sa_mask); sig.sa_flags= 0; if (sigaction(SIGPIPE,&sig,0)) syscallerror("ignore sigpipe"); sfd= socket(AF_UNIX,SOCK_STREAM,0); if (!sfd) syscallerror("create client socket"); assert(sizeof(ssockname.sun_path) > sizeof(RENDEZVOUSPATH)); ssockname.sun_family= AF_UNIX; strcpy(ssockname.sun_path,RENDEZVOUSPATH); priv_resume(); while (connect(sfd,(struct sockaddr*)&ssockname,sizeof(ssockname))) { if (errno == ECONNREFUSED || errno == ENOENT) syscallerror("uservd daemon is not running - service not available"); if (errno != EINTR) fsyscallerror("unable to connect to uservd daemon: %m"); } return sfd; } static void server_handshake(int sfd) { srfile= fdopen(sfd,"r"); if (!srfile) syscallerror("turn socket fd into FILE* for read"); if (setvbuf(srfile,0,_IOFBF,BUFSIZ)) syscallerror("set buffering on socket reads"); swfile= fdopen(sfd,"w"); if (!swfile) syscallerror("turn socket fd into FILE* for write"); if (setvbuf(swfile,0,_IOFBF,BUFSIZ)) syscallerror("set buffering on socket writes"); xfread(&opening_mbuf,sizeof(opening_mbuf),srfile); checkmagic(opening_mbuf.magic,OPENING_MAGIC,"in opening message"); if (memcmp(protocolchecksumversion,opening_mbuf.protocolchecksumversion,PCSUMSIZE)) protoerror("protocol version checksum mismatch - server not same as client"); } static void server_preparepipes(void) { char pipepathbuf[PIPEPATHMAXLEN+2]; int fd, tempfd; for (fd=0; fd=0) xfwrite(ovbuf,sizeof(*ovbuf)*ovused,swfile); xfwrite(&spoofgid,sizeof(gid_t),swfile); xfwrite(gidarray,sizeof(gid_t)*ngids,swfile); xfwritefds(fdm_read,request_mbuf.nreadfds,swfile); xfwritefds(fdm_write,request_mbuf.nwritefds,swfile); for (i=1; i2) if (close(fdsetup[fd].copyfd)) if (errno != EBADF) /* EBADF can be induced if cmd line specifies same fd twice */ fsyscallerror("close real fd for %d",fd); } } static void catdup(const char *which, int from, int to) { if (dup2(from,to)<0) { blocksignals(SIG_BLOCK); fprintf(stderr,"userv: %s: cannot dup for %s: %s\n",which, to?"stdout":"stdin", strerror(errno)); exit(-1); } } static void connect_pipes(void) { struct sigaction sig; char catnamebuf[sizeof(int)*3+30]; int fd, reading; pid_t child; for (fd=0; fd=fdsetupsize) break; sigemptyset(&sset); r= sigsuspend(&sset); if (r && errno != EINTR) syscallerror("sigsuspend failed in unexpected way"); blocksignals(SIG_UNBLOCK); } } static void NONRETURNING process_exitstatus(int status) { blocksignals(SIG_BLOCK); if (systemerror) _exit(255); if (sigpipeok && signalsexit != se_stdout && WIFSIGNALED(status) && WTERMSIG(status)==SIGPIPE && !WCOREDUMP(status)) status= 0; switch (signalsexit) { case se_number: case se_numbernocore: if (WIFEXITED(status)) _exit(WEXITSTATUS(status)); else if (WIFSIGNALED(status)) _exit(WTERMSIG(status) + (signalsexit==se_number && WCOREDUMP(status) ? 128 : 0)); break; case se_highbit: if (WIFEXITED(status)) _exit(WEXITSTATUS(status)<=127 ? WEXITSTATUS(status) : 127); else if (WIFSIGNALED(status) && WTERMSIG(status)<=126) _exit(WTERMSIG(status)+128); break; case se_stdout: printf("\n%d %d ",(status>>8)&0x0ff,status&0x0ff); if (WIFEXITED(status)) printf("exited with code %d",WEXITSTATUS(status)); else if (WIFSIGNALED(status)) printf("killed by %s (signal %d)%s", strsignal(WTERMSIG(status)),WTERMSIG(status), WCOREDUMP(status) ? ", core dumped " : ""); else printf("unknown wait status"); putchar('\n'); if (ferror(stdout) || fflush(stdout)) syscallerror("write exit status to stdout"); _exit(0); default: if (WIFEXITED(status)) _exit(WEXITSTATUS(status)); else if (WIFSIGNALED(status)) _exit(signalsexit); break; } fprintf(stderr,"userv: unknown wait status %d\n",status); _exit(-1); } int main(int argc, char *const *argv) { int status; #ifdef NDEBUG # error Do not disable assertions in this security-critical code ! #endif security_init(); parse_arguments(&argc,&argv); determine_users(); determine_cwd(); process_override(argv[0]); socketfd= server_connect(); priv_suspend(); server_handshake(socketfd); server_preparepipes(); server_sendrequest(argc,argv); priv_permanentlyrevokesuspended(); server_awaitconfirm(); prepare_asynchsignals(); connect_pipes(); server_sendconfirm(); status= server_awaitcompletion(); dispose_remaining_pipes(); process_exitstatus(status); } work/common.h0000664000000000000000000001030514163725562010403 0ustar /* * userv - common.h * definitions shared between client and daemon * * userv is copyright Ian Jackson and other contributors. * See README for full authorship information. * * 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; if not, see . */ #ifndef COMMON_H #define COMMON_H #define COPYRIGHT(indent,nl) \ indent "Copyright 1996-2021 Ian Jackson; copyright 2000 Ben Harris;" nl \ indent "Copyright 2021 Genome Research Limited apropos work by" nl \ indent "Matthew Vernon." nl \ indent "there is NO WARRANTY; type `userv --copyright' for details." nl #define PCSUMSIZE 16 static const unsigned char protocolchecksumversion[PCSUMSIZE]= { #include "pcsum.h" }; #ifndef VARDIR # define VARDIR "/var/run/userv" #endif #ifndef RENDEZVOUS # define RENDEZVOUS "socket" #endif #ifndef RENDEZVOUSPATH # define RENDEZVOUSPATH VARDIR "/" RENDEZVOUS #endif #ifndef PIPEFORMAT # define PIPEFORMAT "%lx.%lx.%x" # define PIPEPATTERN "[0-9a-f]*.[0-9a-f]*.*[0-9a-f]" # define PIPEFORMATEXTEND ((int)(sizeof(unsigned long)*2*2+(int)sizeof(int)*2+3)) # define PIPEMAXLEN ((int)(sizeof(PIPEFORMAT)+PIPEFORMATEXTEND)) #endif #ifndef PIPEPATHFORMAT # define PIPEPATHFORMAT VARDIR "/" PIPEFORMAT # define PIPEPATHMAXLEN ((int)(sizeof(PIPEPATHFORMAT)+PIPEFORMATEXTEND)) #endif #define MAX_ALLOW_FD 1024 #define MAX_GENERAL_STRING (1024*1024) #define MAX_OVERRIDE_LEN MAX_GENERAL_STRING #define MAX_ERRMSG_STRING 4096 #define MAX_ARGSDEFVAR 4096 #define MAX_GIDS 1024 #ifdef DEBUG # define BASE_MAGIC 0x5deb7567UL /* "\x5d\xebug" */ #else # define BASE_MAGIC 0x755e7276UL /* "u\x5erv" */ #endif enum { OPENING_MAGIC= BASE_MAGIC+1, REQUEST_MAGIC, REQUEST_END_MAGIC, PROGRESS_MAGIC, PROGRESS_ERRMSG_END_MAGIC, EVENT_MAGIC }; struct opening_msg { unsigned long magic; unsigned char protocolchecksumversion[PCSUMSIZE]; pid_t overlordpid, serverpid; }; struct request_msg { unsigned long magic; pid_t clientpid; /* or -1 if no service is required and this was a version check */ int serviceuserlen; int servicelen; int loginnamelen, spoofed; /* spoofed is 0 or 1 */ int cwdlen, overridelen; uid_t callinguid; int ngids, nreadfds, nwritefds, nargs, nvars; /* Followed by: * serviceuserlen bytes for the service user (unterminated) * servicelen bytes for the service (unterminated) * loginnamelen bytes for the login name (unterminated) * cwdlen bytes for the cwd (unterminated) * overridelen bytes for the override data (with extra \n but unterminated), * or nothing if overridelen==-1 * ngids gid_ts for the primary group and supplementary groups * nreadfds and then nwritefds ints for the file descriptors * for each of the nargs arguments * an int for the string length * that many characters (unterminated) * for each for the nvars variable keys * an int for the key length * that many characters (unterminated) * an int for the value length * that many characters (unterminated) * one unsigned long, endmagic; */ }; struct progress_msg { unsigned long magic; enum { pt_ok, pt_errmsg, pt_failed, pt_terminated } type; union { struct { int messagelen; } errmsg; struct { int status; } terminated; } data; /* follwed by variable-length part: * for ok, failed, terminated: nothing * for errmsg: messagelen bytes for the error message (unterminated, no \n) * unsigned long PROGRESS_ERRMSG_END_MAGIC */ }; struct event_msg { unsigned long magic; enum { et_confirm, et_closereadfd, et_disconnect } type; union { struct { int fd; } closereadfd; } data; }; #endif work/config.h.in0000664000000000000000000000755214163725562010777 0ustar /* config.h.in. Generated from configure.in by autoheader. */ /* * userv - acconfig.h * extra stuff for config.h.in (autoconf) * * userv is copyright Ian Jackson and other contributors. * See README for full authorship information. * * 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; if not, see . */ /* Define if EPROTO exists. */ #undef HAVE_EPROTO /* Define if LOG_AUTHPRIV exists. */ #undef HAVE_LOG_AUTHPRIV /* Define if WCOREDUMP exists. */ #undef HAVE_WCOREDUMP /* Define if function attributes a la GCC 2.5 and higher are available. */ #undef HAVE_GNUC25_ATTRIB /* Define if unused functions a la GCC 2.5 and higher are available. */ #undef HAVE_GNUC25_UNUSED /* Define if nonreturning functions a la GCC 2.5 and higher are available. */ #undef HAVE_GNUC25_NORETURN /* Define if printf-format argument lists a la GCC are available. */ #undef HAVE_GNUC25_PRINTFFORMAT /* Define to 1 if you have the `socket' library (-lsocket). */ #undef HAVE_LIBSOCKET /* Define to 1 if you have the `setenv' function. */ #undef HAVE_SETENV /* Define to 1 if you have the `strsignal' function. */ #undef HAVE_STRSIGNAL /* Define to 1 if you have the `vsnprintf' function. */ #undef HAVE_VSNPRINTF /* Define to the address where bug reports for this package should be sent. */ #undef PACKAGE_BUGREPORT /* Define to the full name of this package. */ #undef PACKAGE_NAME /* Define to the full name and version of this package. */ #undef PACKAGE_STRING /* Define to the one symbol short name of this package. */ #undef PACKAGE_TARNAME /* Define to the home page for this package. */ #undef PACKAGE_URL /* Define to the version of this package. */ #undef PACKAGE_VERSION /* STRSIGNAL */ #ifndef HAVE_STRSIGNAL #define STRSIGNAL(x) "[platform has no strsignal!]" #endif /* VSNPRINTF */ #ifndef HAVE_VSNPRINTF # error "You must have vsnprintf! Without vsnprintf it is very hard to write secure programs. If you don't have it then your system libc is probably full of hideous buffer overrun security bugs. But, if you don't want to fix your system a portable snprintf can be found at http://www.ijs.si/software/snprintf/" #endif /* EPROTO */ #ifndef HAVE_EPROTO #define EPROTO 0 #endif /* LOG_AUTHPRIV */ #ifndef HAVE_LOG_AUTHPRIV #define LOG_AUTHPRIV LOG_AUTH #endif /* WCOREDUMP */ #ifndef HAVE_WCOREDUMP #define WCOREDUMP(x) 0 #endif /* GNU C attributes. */ #ifndef FUNCATTR #ifdef HAVE_GNUC25_ATTRIB #define FUNCATTR(x) __attribute__(x) #else #define FUNCATTR(x) #endif #endif /* GNU C printf formats, or null. */ #ifndef ATTRPRINTF #ifdef HAVE_GNUC25_PRINTFFORMAT #define ATTRPRINTF(si,tc) format(printf,si,tc) #else #define ATTRPRINTF(si,tc) #endif #endif #ifndef PRINTFFORMAT #define PRINTFFORMAT(si,tc) FUNCATTR((ATTRPRINTF(si,tc))) #endif /* GNU C nonreturning functions, or null. */ #ifndef ATTRNORETURN #ifdef HAVE_GNUC25_NORETURN #define ATTRNORETURN noreturn #else #define ATTRNORETURN #endif #endif #ifndef NONRETURNING #define NONRETURNING FUNCATTR((ATTRNORETURN)) #endif /* Combination of both the above. */ #ifndef NONRETURNPRINTFFORMAT #define NONRETURNPRINTFFORMAT(si,tc) FUNCATTR((ATTRPRINTF(si,tc),ATTRNORETURN)) #endif /* GNU C unused functions, or null. */ #ifndef ATTRUNUSED #ifdef HAVE_GNUC25_UNUSED #define ATTRUNUSED unused #else #define ATTRUNUSED #endif #endif #ifndef UNUSED #define UNUSED FUNCATTR((ATTRUNUSED)) #endif work/configure0000775000000000000000000043077414163725562010671 0ustar #! /bin/sh # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.69. # # # Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. # # # This configure script is free software; the Free Software Foundation # gives unlimited permission to copy, distribute and modify it. ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo # Prefer a ksh shell builtin over an external printf program on Solaris, # but without wasting forks for bash or zsh. if test -z "$BASH_VERSION$ZSH_VERSION" \ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='print -r --' as_echo_n='print -rn --' elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Unset variables that we do not need and which cause bugs (e.g. in # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" # suppresses any "Segmentation fault" message there. '((' could # trigger a bug in pdksh 5.2.14. for as_var in BASH_ENV ENV MAIL MAILPATH do eval test x\${$as_var+set} = xset \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH # Use a proper internal environment variable to ensure we don't fall # into an infinite loop, continuously re-executing ourselves. if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then _as_can_reexec=no; export _as_can_reexec; # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. $as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 as_fn_exit 255 fi # We don't want this to propagate to other subprocesses. { _as_can_reexec=; unset _as_can_reexec;} if test "x$CONFIG_SHELL" = x; then as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which # is contrary to our usage. Disable this feature. alias -g '\${1+\"\$@\"}'='\"\$@\"' setopt NO_GLOB_SUBST else case \`(set -o) 2>/dev/null\` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi " as_required="as_fn_return () { (exit \$1); } as_fn_success () { as_fn_return 0; } as_fn_failure () { as_fn_return 1; } as_fn_ret_success () { return 0; } as_fn_ret_failure () { return 1; } exitcode=0 as_fn_success || { exitcode=1; echo as_fn_success failed.; } as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : else exitcode=1; echo positional parameters were not saved. fi test x\$exitcode = x0 || exit 1 test -x / || exit 1" as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 test \$(( 1 + 1 )) = 2 || exit 1" if (eval "$as_required") 2>/dev/null; then : as_have_required=yes else as_have_required=no fi if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR as_found=false for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. as_found=: case $as_dir in #( /*) for as_base in sh bash ksh sh5; do # Try only shells that exist, to save several forks. as_shell=$as_dir/$as_base if { test -f "$as_shell" || test -f "$as_shell.exe"; } && { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : CONFIG_SHELL=$as_shell as_have_required=yes if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : break 2 fi fi done;; esac as_found=false done $as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : CONFIG_SHELL=$SHELL as_have_required=yes fi; } IFS=$as_save_IFS if test "x$CONFIG_SHELL" != x; then : export CONFIG_SHELL # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. $as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 exit 255 fi if test x$as_have_required = xno; then : $as_echo "$0: This script requires a shell more modern than all" $as_echo "$0: the shells that I found on your system." if test x${ZSH_VERSION+set} = xset ; then $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" $as_echo "$0: be upgraded to zsh 4.3.4 or later." else $as_echo "$0: Please tell bug-autoconf@gnu.org about your system, $0: including any error possibly output before this $0: message. Then install a modern shell, or manually run $0: the script under such a shell if you do have one." fi exit 1 fi fi fi SHELL=${CONFIG_SHELL-/bin/sh} export SHELL # Unset more variables known to interfere with behavior of common tools. CLICOLOR_FORCE= GREP_OPTIONS= unset CLICOLOR_FORCE GREP_OPTIONS ## --------------------- ## ## M4sh Shell Functions. ## ## --------------------- ## # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p # as_fn_executable_p FILE # ----------------------- # Test if FILE is an executable regular file. as_fn_executable_p () { test -f "$1" && test -x "$1" } # as_fn_executable_p # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : eval 'as_fn_append () { eval $1+=\$2 }' else as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : eval 'as_fn_arith () { as_val=$(( $* )) }' else as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits as_lineno_1=$LINENO as_lineno_1a=$LINENO as_lineno_2=$LINENO as_lineno_2a=$LINENO eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) sed -n ' p /[$]LINENO/= ' <$as_myself | sed ' s/[$]LINENO.*/&-/ t lineno b :lineno N :loop s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ t loop s/-\n.*// ' >$as_me.lineno && chmod +x "$as_me.lineno" || { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } # If we had to re-execute with $CONFIG_SHELL, we're ensured to have # already done that, so ensure we don't try to do so again and fall # in an infinite loop. This has already happened in practice. _as_can_reexec=no; export _as_can_reexec # Don't try to exec as it changes $[0], causing all sort of problems # (the dirname of $[0] is not the place where we might find the # original and so on. Autoconf is especially sensitive to this). . "./$as_me.lineno" # Exit status is that of the last command. exit } ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -pR' fi else as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" test -n "$DJDIR" || exec 7<&0 &1 # Name of the host. # hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, # so uname gets run too. ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` # # Initializations. # ac_default_prefix=/usr/local ac_clean_files= ac_config_libobj_dir=. LIBOBJS= cross_compiling=no subdirs= MFLAGS= MAKEFLAGS= # Identity of this package. PACKAGE_NAME= PACKAGE_TARNAME= PACKAGE_VERSION= PACKAGE_STRING= PACKAGE_BUGREPORT= PACKAGE_URL= ac_unique_file="language.i4" ac_default_prefix=/usr/local ac_subst_vars='LTLIBOBJS LIBOBJS VERSION CWARNS OPTIMISE EGREP GREP MD5SUM_SIMPLE INSTALL_DATA INSTALL_SCRIPT INSTALL_PROGRAM CPP OBJEXT EXEEXT ac_ct_CC CPPFLAGS LDFLAGS CFLAGS CC DEBUGLIBS DEBUGDEFS target_alias host_alias build_alias LIBS ECHO_T ECHO_N ECHO_C DEFS mandir localedir libdir psdir pdfdir dvidir htmldir infodir docdir oldincludedir includedir runstatedir localstatedir sharedstatedir sysconfdir datadir datarootdir libexecdir sbindir bindir program_transform_name prefix exec_prefix PACKAGE_URL PACKAGE_BUGREPORT PACKAGE_STRING PACKAGE_VERSION PACKAGE_TARNAME PACKAGE_NAME PATH_SEPARATOR SHELL' ac_subst_files='' ac_user_opts=' enable_option_checking enable_debug ' ac_precious_vars='build_alias host_alias target_alias CC CFLAGS LDFLAGS LIBS CPPFLAGS CPP' # Initialize some variables set by options. ac_init_help= ac_init_version=false ac_unrecognized_opts= ac_unrecognized_sep= # The variables have the same names as the options, with # dashes changed to underlines. cache_file=/dev/null exec_prefix=NONE no_create= no_recursion= prefix=NONE program_prefix=NONE program_suffix=NONE program_transform_name=s,x,x, silent= site= srcdir= verbose= x_includes=NONE x_libraries=NONE # Installation directory options. # These are left unexpanded so users can "make install exec_prefix=/foo" # and all the variables that are supposed to be based on exec_prefix # by default will actually change. # Use braces instead of parens because sh, perl, etc. also accept them. # (The list follows the same order as the GNU Coding Standards.) bindir='${exec_prefix}/bin' sbindir='${exec_prefix}/sbin' libexecdir='${exec_prefix}/libexec' datarootdir='${prefix}/share' datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' runstatedir='${localstatedir}/run' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE}' infodir='${datarootdir}/info' htmldir='${docdir}' dvidir='${docdir}' pdfdir='${docdir}' psdir='${docdir}' libdir='${exec_prefix}/lib' localedir='${datarootdir}/locale' mandir='${datarootdir}/man' ac_prev= ac_dashdash= for ac_option do # If the previous option needs an argument, assign it. if test -n "$ac_prev"; then eval $ac_prev=\$ac_option ac_prev= continue fi case $ac_option in *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; *=) ac_optarg= ;; *) ac_optarg=yes ;; esac # Accept the important Cygnus configure options, so we can diagnose typos. case $ac_dashdash$ac_option in --) ac_dashdash=yes ;; -bindir | --bindir | --bindi | --bind | --bin | --bi) ac_prev=bindir ;; -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) bindir=$ac_optarg ;; -build | --build | --buil | --bui | --bu) ac_prev=build_alias ;; -build=* | --build=* | --buil=* | --bui=* | --bu=*) build_alias=$ac_optarg ;; -cache-file | --cache-file | --cache-fil | --cache-fi \ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) ac_prev=cache_file ;; -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) cache_file=$ac_optarg ;; --config-cache | -C) cache_file=config.cache ;; -datadir | --datadir | --datadi | --datad) ac_prev=datadir ;; -datadir=* | --datadir=* | --datadi=* | --datad=*) datadir=$ac_optarg ;; -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ | --dataroo | --dataro | --datar) ac_prev=datarootdir ;; -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) datarootdir=$ac_optarg ;; -disable-* | --disable-*) ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=no ;; -docdir | --docdir | --docdi | --doc | --do) ac_prev=docdir ;; -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) docdir=$ac_optarg ;; -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) ac_prev=dvidir ;; -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) dvidir=$ac_optarg ;; -enable-* | --enable-*) ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=\$ac_optarg ;; -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ | --exec | --exe | --ex) ac_prev=exec_prefix ;; -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ | --exec=* | --exe=* | --ex=*) exec_prefix=$ac_optarg ;; -gas | --gas | --ga | --g) # Obsolete; use --with-gas. with_gas=yes ;; -help | --help | --hel | --he | -h) ac_init_help=long ;; -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) ac_init_help=recursive ;; -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) ac_init_help=short ;; -host | --host | --hos | --ho) ac_prev=host_alias ;; -host=* | --host=* | --hos=* | --ho=*) host_alias=$ac_optarg ;; -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) ac_prev=htmldir ;; -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ | --ht=*) htmldir=$ac_optarg ;; -includedir | --includedir | --includedi | --included | --include \ | --includ | --inclu | --incl | --inc) ac_prev=includedir ;; -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ | --includ=* | --inclu=* | --incl=* | --inc=*) includedir=$ac_optarg ;; -infodir | --infodir | --infodi | --infod | --info | --inf) ac_prev=infodir ;; -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) infodir=$ac_optarg ;; -libdir | --libdir | --libdi | --libd) ac_prev=libdir ;; -libdir=* | --libdir=* | --libdi=* | --libd=*) libdir=$ac_optarg ;; -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ | --libexe | --libex | --libe) ac_prev=libexecdir ;; -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ | --libexe=* | --libex=* | --libe=*) libexecdir=$ac_optarg ;; -localedir | --localedir | --localedi | --localed | --locale) ac_prev=localedir ;; -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) localedir=$ac_optarg ;; -localstatedir | --localstatedir | --localstatedi | --localstated \ | --localstate | --localstat | --localsta | --localst | --locals) ac_prev=localstatedir ;; -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) localstatedir=$ac_optarg ;; -mandir | --mandir | --mandi | --mand | --man | --ma | --m) ac_prev=mandir ;; -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) mandir=$ac_optarg ;; -nfp | --nfp | --nf) # Obsolete; use --without-fp. with_fp=no ;; -no-create | --no-create | --no-creat | --no-crea | --no-cre \ | --no-cr | --no-c | -n) no_create=yes ;; -no-recursion | --no-recursion | --no-recursio | --no-recursi \ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) no_recursion=yes ;; -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ | --oldin | --oldi | --old | --ol | --o) ac_prev=oldincludedir ;; -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) oldincludedir=$ac_optarg ;; -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) ac_prev=prefix ;; -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) prefix=$ac_optarg ;; -program-prefix | --program-prefix | --program-prefi | --program-pref \ | --program-pre | --program-pr | --program-p) ac_prev=program_prefix ;; -program-prefix=* | --program-prefix=* | --program-prefi=* \ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) program_prefix=$ac_optarg ;; -program-suffix | --program-suffix | --program-suffi | --program-suff \ | --program-suf | --program-su | --program-s) ac_prev=program_suffix ;; -program-suffix=* | --program-suffix=* | --program-suffi=* \ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) program_suffix=$ac_optarg ;; -program-transform-name | --program-transform-name \ | --program-transform-nam | --program-transform-na \ | --program-transform-n | --program-transform- \ | --program-transform | --program-transfor \ | --program-transfo | --program-transf \ | --program-trans | --program-tran \ | --progr-tra | --program-tr | --program-t) ac_prev=program_transform_name ;; -program-transform-name=* | --program-transform-name=* \ | --program-transform-nam=* | --program-transform-na=* \ | --program-transform-n=* | --program-transform-=* \ | --program-transform=* | --program-transfor=* \ | --program-transfo=* | --program-transf=* \ | --program-trans=* | --program-tran=* \ | --progr-tra=* | --program-tr=* | --program-t=*) program_transform_name=$ac_optarg ;; -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) ac_prev=pdfdir ;; -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) pdfdir=$ac_optarg ;; -psdir | --psdir | --psdi | --psd | --ps) ac_prev=psdir ;; -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) psdir=$ac_optarg ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) silent=yes ;; -runstatedir | --runstatedir | --runstatedi | --runstated \ | --runstate | --runstat | --runsta | --runst | --runs \ | --run | --ru | --r) ac_prev=runstatedir ;; -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \ | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \ | --run=* | --ru=* | --r=*) runstatedir=$ac_optarg ;; -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ | --sbi=* | --sb=*) sbindir=$ac_optarg ;; -sharedstatedir | --sharedstatedir | --sharedstatedi \ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ | --sharedst | --shareds | --shared | --share | --shar \ | --sha | --sh) ac_prev=sharedstatedir ;; -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ | --sha=* | --sh=*) sharedstatedir=$ac_optarg ;; -site | --site | --sit) ac_prev=site ;; -site=* | --site=* | --sit=*) site=$ac_optarg ;; -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) ac_prev=srcdir ;; -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) srcdir=$ac_optarg ;; -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ | --syscon | --sysco | --sysc | --sys | --sy) ac_prev=sysconfdir ;; -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) sysconfdir=$ac_optarg ;; -target | --target | --targe | --targ | --tar | --ta | --t) ac_prev=target_alias ;; -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) target_alias=$ac_optarg ;; -v | -verbose | --verbose | --verbos | --verbo | --verb) verbose=yes ;; -version | --version | --versio | --versi | --vers | -V) ac_init_version=: ;; -with-* | --with-*) ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=\$ac_optarg ;; -without-* | --without-*) ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=no ;; --x) # Obsolete; use --with-x. with_x=yes ;; -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ | --x-incl | --x-inc | --x-in | --x-i) ac_prev=x_includes ;; -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) x_includes=$ac_optarg ;; -x-libraries | --x-libraries | --x-librarie | --x-librari \ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) ac_prev=x_libraries ;; -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) x_libraries=$ac_optarg ;; -*) as_fn_error $? "unrecognized option: \`$ac_option' Try \`$0 --help' for more information" ;; *=*) ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` # Reject names that are not valid shell variable names. case $ac_envvar in #( '' | [0-9]* | *[!_$as_cr_alnum]* ) as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; esac eval $ac_envvar=\$ac_optarg export $ac_envvar ;; *) # FIXME: should be removed in autoconf 3.0. $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" ;; esac done if test -n "$ac_prev"; then ac_option=--`echo $ac_prev | sed 's/_/-/g'` as_fn_error $? "missing argument to $ac_option" fi if test -n "$ac_unrecognized_opts"; then case $enable_option_checking in no) ;; fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; esac fi # Check all directory arguments for consistency. for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ libdir localedir mandir runstatedir do eval ac_val=\$$ac_var # Remove trailing slashes. case $ac_val in */ ) ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` eval $ac_var=\$ac_val;; esac # Be sure to have absolute directory names. case $ac_val in [\\/$]* | ?:[\\/]* ) continue;; NONE | '' ) case $ac_var in *prefix ) continue;; esac;; esac as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" done # There might be people who depend on the old broken behavior: `$host' # used to hold the argument of --host etc. # FIXME: To remove some day. build=$build_alias host=$host_alias target=$target_alias # FIXME: To remove some day. if test "x$host_alias" != x; then if test "x$build_alias" = x; then cross_compiling=maybe elif test "x$build_alias" != "x$host_alias"; then cross_compiling=yes fi fi ac_tool_prefix= test -n "$host_alias" && ac_tool_prefix=$host_alias- test "$silent" = yes && exec 6>/dev/null ac_pwd=`pwd` && test -n "$ac_pwd" && ac_ls_di=`ls -di .` && ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || as_fn_error $? "working directory cannot be determined" test "X$ac_ls_di" = "X$ac_pwd_ls_di" || as_fn_error $? "pwd does not report name of working directory" # Find the source files, if location was not specified. if test -z "$srcdir"; then ac_srcdir_defaulted=yes # Try the directory containing this script, then the parent directory. ac_confdir=`$as_dirname -- "$as_myself" || $as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_myself" : 'X\(//\)[^/]' \| \ X"$as_myself" : 'X\(//\)$' \| \ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_myself" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` srcdir=$ac_confdir if test ! -r "$srcdir/$ac_unique_file"; then srcdir=.. fi else ac_srcdir_defaulted=no fi if test ! -r "$srcdir/$ac_unique_file"; then test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" fi ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" ac_abs_confdir=`( cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" pwd)` # When building in place, set srcdir=. if test "$ac_abs_confdir" = "$ac_pwd"; then srcdir=. fi # Remove unnecessary trailing slashes from srcdir. # Double slashes in file names in object file debugging info # mess up M-x gdb in Emacs. case $srcdir in */) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; esac for ac_var in $ac_precious_vars; do eval ac_env_${ac_var}_set=\${${ac_var}+set} eval ac_env_${ac_var}_value=\$${ac_var} eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} eval ac_cv_env_${ac_var}_value=\$${ac_var} done # # Report the --help message. # if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF \`configure' configures this package to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... To assign environment variables (e.g., CC, CFLAGS...), specify them as VAR=VALUE. See below for descriptions of some of the useful variables. Defaults for the options are specified in brackets. Configuration: -h, --help display this help and exit --help=short display options specific to this package --help=recursive display the short help of all the included packages -V, --version display version information and exit -q, --quiet, --silent do not print \`checking ...' messages --cache-file=FILE cache test results in FILE [disabled] -C, --config-cache alias for \`--cache-file=config.cache' -n, --no-create do not create output files --srcdir=DIR find the sources in DIR [configure dir or \`..'] Installation directories: --prefix=PREFIX install architecture-independent files in PREFIX [$ac_default_prefix] --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX [PREFIX] By default, \`make install' will install all the files in \`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify an installation prefix other than \`$ac_default_prefix' using \`--prefix', for instance \`--prefix=\$HOME'. For better control, use the options below. Fine tuning of the installation directories: --bindir=DIR user executables [EPREFIX/bin] --sbindir=DIR system admin executables [EPREFIX/sbin] --libexecdir=DIR program executables [EPREFIX/libexec] --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] --datadir=DIR read-only architecture-independent data [DATAROOTDIR] --infodir=DIR info documentation [DATAROOTDIR/info] --localedir=DIR locale-dependent data [DATAROOTDIR/locale] --mandir=DIR man documentation [DATAROOTDIR/man] --docdir=DIR documentation root [DATAROOTDIR/doc/PACKAGE] --htmldir=DIR html documentation [DOCDIR] --dvidir=DIR dvi documentation [DOCDIR] --pdfdir=DIR pdf documentation [DOCDIR] --psdir=DIR ps documentation [DOCDIR] _ACEOF cat <<\_ACEOF _ACEOF fi if test -n "$ac_init_help"; then cat <<\_ACEOF Optional Features: --disable-option-checking ignore unrecognized --enable/--with options --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) --enable-FEATURE[=ARG] include FEATURE [ARG=yes] --enable-debug build debugging version Some influential environment variables: CC C compiler command CFLAGS C compiler flags LDFLAGS linker flags, e.g. -L if you have libraries in a nonstandard directory LIBS libraries to pass to the linker, e.g. -l CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if you have headers in a nonstandard directory CPP C preprocessor Use these variables to override the choices made by `configure' or to help it to find libraries and programs with nonstandard names/locations. Report bugs to the package provider. _ACEOF ac_status=$? fi if test "$ac_init_help" = "recursive"; then # If there are subdirs, report their specific --help. for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue test -d "$ac_dir" || { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || continue ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix cd "$ac_dir" || { ac_status=$?; continue; } # Check for guested configure. if test -f "$ac_srcdir/configure.gnu"; then echo && $SHELL "$ac_srcdir/configure.gnu" --help=recursive elif test -f "$ac_srcdir/configure"; then echo && $SHELL "$ac_srcdir/configure" --help=recursive else $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 fi || ac_status=$? cd "$ac_pwd" || { ac_status=$?; break; } done fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF configure generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. _ACEOF exit fi ## ------------------------ ## ## Autoconf initialization. ## ## ------------------------ ## # ac_fn_c_try_compile LINENO # -------------------------- # Try to compile conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_compile # ac_fn_c_try_cpp LINENO # ---------------------- # Try to preprocess conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_cpp () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_cpp conftest.$ac_ext" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } > conftest.i && { test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || test ! -s conftest.err }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_cpp # ac_fn_c_try_link LINENO # ----------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_link () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext conftest$ac_exeext if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || test -x conftest$ac_exeext }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would # interfere with the next link command; also delete a directory that is # left behind by Apple's compiler. We do this before executing the actions. rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_link # ac_fn_c_check_func LINENO FUNC VAR # ---------------------------------- # Tests whether FUNC exists, setting the cache variable VAR accordingly ac_fn_c_check_func () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Define $2 to an innocuous variant, in case declares $2. For example, HP-UX 11i declares gettimeofday. */ #define $2 innocuous_$2 /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $2 (); below. Prefer to if __STDC__ is defined, since exists even on freestanding compilers. */ #ifdef __STDC__ # include #else # include #endif #undef $2 /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char $2 (); /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined __stub_$2 || defined __stub___$2 choke me #endif int main () { return $2 (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : eval "$3=yes" else eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_func cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. It was created by $as_me, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ _ACEOF exec 5>>config.log { cat <<_ASUNAME ## --------- ## ## Platform. ## ## --------- ## hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` /bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` /bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` /usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` /bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` /bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` _ASUNAME as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. $as_echo "PATH: $as_dir" done IFS=$as_save_IFS } >&5 cat >&5 <<_ACEOF ## ----------- ## ## Core tests. ## ## ----------- ## _ACEOF # Keep a trace of the command line. # Strip out --no-create and --no-recursion so they do not pile up. # Strip out --silent because we don't want to record it for future runs. # Also quote any args containing shell meta-characters. # Make two passes to allow for proper duplicate-argument suppression. ac_configure_args= ac_configure_args0= ac_configure_args1= ac_must_keep_next=false for ac_pass in 1 2 do for ac_arg do case $ac_arg in -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) continue ;; *\'*) ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac case $ac_pass in 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; 2) as_fn_append ac_configure_args1 " '$ac_arg'" if test $ac_must_keep_next = true; then ac_must_keep_next=false # Got value, back to normal. else case $ac_arg in *=* | --config-cache | -C | -disable-* | --disable-* \ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ | -with-* | --with-* | -without-* | --without-* | --x) case "$ac_configure_args0 " in "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; esac ;; -* ) ac_must_keep_next=true ;; esac fi as_fn_append ac_configure_args " '$ac_arg'" ;; esac done done { ac_configure_args0=; unset ac_configure_args0;} { ac_configure_args1=; unset ac_configure_args1;} # When interrupted or exit'd, cleanup temporary files, and complete # config.log. We remove comments because anyway the quotes in there # would cause problems or look ugly. # WARNING: Use '\'' to represent an apostrophe within the trap. # WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. trap 'exit_status=$? # Save into config.log some information that might help in debugging. { echo $as_echo "## ---------------- ## ## Cache variables. ## ## ---------------- ##" echo # The following way of writing the cache mishandles newlines in values, ( for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( *${as_nl}ac_space=\ *) sed -n \ "s/'\''/'\''\\\\'\'''\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" ;; #( *) sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) echo $as_echo "## ----------------- ## ## Output variables. ## ## ----------------- ##" echo for ac_var in $ac_subst_vars do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo if test -n "$ac_subst_files"; then $as_echo "## ------------------- ## ## File substitutions. ## ## ------------------- ##" echo for ac_var in $ac_subst_files do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo fi if test -s confdefs.h; then $as_echo "## ----------- ## ## confdefs.h. ## ## ----------- ##" echo cat confdefs.h echo fi test "$ac_signal" != 0 && $as_echo "$as_me: caught signal $ac_signal" $as_echo "$as_me: exit $exit_status" } >&5 rm -f core *.core core.conftest.* && rm -f -r conftest* confdefs* conf$$* $ac_clean_files && exit $exit_status ' 0 for ac_signal in 1 2 13 15; do trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal done ac_signal=0 # confdefs.h avoids OS command line length limits that DEFS can exceed. rm -f -r conftest* confdefs.h $as_echo "/* confdefs.h */" > confdefs.h # Predefined preprocessor variables. cat >>confdefs.h <<_ACEOF #define PACKAGE_NAME "$PACKAGE_NAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_TARNAME "$PACKAGE_TARNAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_VERSION "$PACKAGE_VERSION" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_STRING "$PACKAGE_STRING" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_URL "$PACKAGE_URL" _ACEOF # Let the site file select an alternate cache file if it wants to. # Prefer an explicitly selected file to automatically selected ones. ac_site_file1=NONE ac_site_file2=NONE if test -n "$CONFIG_SITE"; then # We do not want a PATH search for config.site. case $CONFIG_SITE in #(( -*) ac_site_file1=./$CONFIG_SITE;; */*) ac_site_file1=$CONFIG_SITE;; *) ac_site_file1=./$CONFIG_SITE;; esac elif test "x$prefix" != xNONE; then ac_site_file1=$prefix/share/config.site ac_site_file2=$prefix/etc/config.site else ac_site_file1=$ac_default_prefix/share/config.site ac_site_file2=$ac_default_prefix/etc/config.site fi for ac_site_file in "$ac_site_file1" "$ac_site_file2" do test "x$ac_site_file" = xNONE && continue if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 $as_echo "$as_me: loading site script $ac_site_file" >&6;} sed 's/^/| /' "$ac_site_file" >&5 . "$ac_site_file" \ || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "failed to load site script $ac_site_file See \`config.log' for more details" "$LINENO" 5; } fi done if test -r "$cache_file"; then # Some versions of bash will fail to source /dev/null (special files # actually), so we avoid doing that. DJGPP emulates it as a regular file. if test /dev/null != "$cache_file" && test -f "$cache_file"; then { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 $as_echo "$as_me: loading cache $cache_file" >&6;} case $cache_file in [\\/]* | ?:[\\/]* ) . "$cache_file";; *) . "./$cache_file";; esac fi else { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 $as_echo "$as_me: creating cache $cache_file" >&6;} >$cache_file fi # Check that the precious variables saved in the cache have kept the same # value. ac_cache_corrupted=false for ac_var in $ac_precious_vars; do eval ac_old_set=\$ac_cv_env_${ac_var}_set eval ac_new_set=\$ac_env_${ac_var}_set eval ac_old_val=\$ac_cv_env_${ac_var}_value eval ac_new_val=\$ac_env_${ac_var}_value case $ac_old_set,$ac_new_set in set,) { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} ac_cache_corrupted=: ;; ,set) { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} ac_cache_corrupted=: ;; ,);; *) if test "x$ac_old_val" != "x$ac_new_val"; then # differences in whitespace do not lead to failure. ac_old_val_w=`echo x $ac_old_val` ac_new_val_w=`echo x $ac_new_val` if test "$ac_old_val_w" != "$ac_new_val_w"; then { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 $as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} ac_cache_corrupted=: else { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 $as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} eval $ac_var=\$ac_old_val fi { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 $as_echo "$as_me: former value: \`$ac_old_val'" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 $as_echo "$as_me: current value: \`$ac_new_val'" >&2;} fi;; esac # Pass precious variables to config.status. if test "$ac_new_set" = set; then case $ac_new_val in *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; *) ac_arg=$ac_var=$ac_new_val ;; esac case " $ac_configure_args " in *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. *) as_fn_append ac_configure_args " '$ac_arg'" ;; esac fi done if $ac_cache_corrupted; then { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 $as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 fi ## -------------------- ## ## Main body of script. ## ## -------------------- ## ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_config_headers="$ac_config_headers config.h" crdir="`pwd`" DEBUGDEFS='' DEBUGLIBS='' # Check whether --enable-debug was given. if test "${enable_debug+set}" = set; then : enableval=$enable_debug; if test "x$enable_debug" = xyes; then DEBUGDEFS="-DDEBUG -DVARDIR='\"$crdir/vd\"' -DSYSTEMCONFIGDIR='\"$crdir/slash-etc\"' -DSERVICEUSERDIR='\"$crdir/tilde\"'" DEBUGLIBS=-lefence echo will build debugging version elif test "x$enable_debug" != xno; then as_fn_error $? "--enable-debug does not allow any arguments except 'yes' and 'no'" "$LINENO" 5 fi fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. set dummy ${ac_tool_prefix}gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi else CC="$ac_cv_prog_CC" fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. set dummy ${ac_tool_prefix}cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi fi if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else ac_prog_rejected=no as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then ac_prog_rejected=yes continue fi ac_cv_prog_CC="cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS if test $ac_prog_rejected = yes; then # We found a bogon in the path, so make sure we never use it. set dummy $ac_cv_prog_CC shift if test $# != 0; then # We chose a different compiler from the bogus one. # However, it has the same basename, so the bogon will be chosen # first if we set CC to just the basename; use the full file name. shift ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" fi fi fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then for ac_prog in cl.exe do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$CC" && break done fi if test -z "$CC"; then ac_ct_CC=$CC for ac_prog in cl.exe do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_CC" && break done if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi fi fi test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "no acceptable C compiler found in \$PATH See \`config.log' for more details" "$LINENO" 5; } # Provide some information about the compiler. $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then sed '10a\ ... rest of stderr output deleted ... 10q' conftest.err >conftest.er1 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" # Try to create an executable without -o first, disregard a.out. # It will help us diagnose broken compilers, and finding out an intuition # of exeext. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 $as_echo_n "checking whether the C compiler works... " >&6; } ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` # The possible output files: ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" ac_rmfiles= for ac_file in $ac_files do case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; * ) ac_rmfiles="$ac_rmfiles $ac_file";; esac done rm -f $ac_rmfiles if { { ac_try="$ac_link_default" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link_default") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. # So ignore a value of `no', otherwise this would lead to `EXEEXT = no' # in a Makefile. We should not override ac_cv_exeext if it was cached, # so that the user can short-circuit this test for compilers unknown to # Autoconf. for ac_file in $ac_files '' do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; [ab].out ) # We found the default executable, but exeext='' is most # certainly right. break;; *.* ) if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; then :; else ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` fi # We set ac_cv_exeext here because the later test for it is not # safe: cross compilers may not add the suffix if given an `-o' # argument, so we may need to know it at that point already. # Even if this section looks crufty: it has the advantage of # actually working. break;; * ) break;; esac done test "$ac_cv_exeext" = no && ac_cv_exeext= else ac_file='' fi if test -z "$ac_file"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "C compiler cannot create executables See \`config.log' for more details" "$LINENO" 5; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 $as_echo_n "checking for C compiler default output file name... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 $as_echo "$ac_file" >&6; } ac_exeext=$ac_cv_exeext rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 $as_echo_n "checking for suffix of executables... " >&6; } if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : # If both `conftest.exe' and `conftest' are `present' (well, observable) # catch `conftest.exe'. For instance with Cygwin, `ls conftest' will # work properly (i.e., refer to `conftest.exe'), while it won't with # `rm'. for ac_file in conftest.exe conftest conftest.*; do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` break;; * ) break;; esac done else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of executables: cannot compile and link See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest conftest$ac_cv_exeext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 $as_echo "$ac_cv_exeext" >&6; } rm -f conftest.$ac_ext EXEEXT=$ac_cv_exeext ac_exeext=$EXEEXT cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { FILE *f = fopen ("conftest.out", "w"); return ferror (f) || fclose (f) != 0; ; return 0; } _ACEOF ac_clean_files="$ac_clean_files conftest.out" # Check that the compiler produces executables we can run. If not, either # the compiler is broken, or we cross compile. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 $as_echo_n "checking whether we are cross compiling... " >&6; } if test "$cross_compiling" != yes; then { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if { ac_try='./conftest$ac_cv_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then cross_compiling=no else if test "$cross_compiling" = maybe; then cross_compiling=yes else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot run C compiled programs. If you meant to cross compile, use \`--host'. See \`config.log' for more details" "$LINENO" 5; } fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 $as_echo "$cross_compiling" >&6; } rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 $as_echo_n "checking for suffix of object files... " >&6; } if ${ac_cv_objext+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF rm -f conftest.o conftest.obj if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : for ac_file in conftest.o conftest.obj conftest.*; do test -f "$ac_file" || continue; case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` break;; esac done else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of object files: cannot compile See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest.$ac_cv_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 $as_echo "$ac_cv_objext" >&6; } OBJEXT=$ac_cv_objext ac_objext=$OBJEXT { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 $as_echo_n "checking whether we are using the GNU C compiler... " >&6; } if ${ac_cv_c_compiler_gnu+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_compiler_gnu=yes else ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 $as_echo "$ac_cv_c_compiler_gnu" >&6; } if test $ac_compiler_gnu = yes; then GCC=yes else GCC= fi ac_test_CFLAGS=${CFLAGS+set} ac_save_CFLAGS=$CFLAGS { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 $as_echo_n "checking whether $CC accepts -g... " >&6; } if ${ac_cv_prog_cc_g+:} false; then : $as_echo_n "(cached) " >&6 else ac_save_c_werror_flag=$ac_c_werror_flag ac_c_werror_flag=yes ac_cv_prog_cc_g=no CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes else CFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : else ac_c_werror_flag=$ac_save_c_werror_flag CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_c_werror_flag=$ac_save_c_werror_flag fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 $as_echo "$ac_cv_prog_cc_g" >&6; } if test "$ac_test_CFLAGS" = set; then CFLAGS=$ac_save_CFLAGS elif test $ac_cv_prog_cc_g = yes; then if test "$GCC" = yes; then CFLAGS="-g -O2" else CFLAGS="-g" fi else if test "$GCC" = yes; then CFLAGS="-O2" else CFLAGS= fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 $as_echo_n "checking for $CC option to accept ISO C89... " >&6; } if ${ac_cv_prog_cc_c89+:} false; then : $as_echo_n "(cached) " >&6 else ac_cv_prog_cc_c89=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include struct stat; /* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ struct buf { int x; }; FILE * (*rcsopen) (struct buf *, struct stat *, int); static char *e (p, i) char **p; int i; { return p[i]; } static char *f (char * (*g) (char **, int), char **p, ...) { char *s; va_list v; va_start (v,p); s = g (p, va_arg (v,int)); va_end (v); return s; } /* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has function prototypes and stuff, but not '\xHH' hex character constants. These don't provoke an error unfortunately, instead are silently treated as 'x'. The following induces an error, until -std is added to get proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an array size at least. It's necessary to write '\x00'==0 to get something that's true only with -std. */ int osf4_cc_array ['\x00' == 0 ? 1 : -1]; /* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters inside strings and character constants. */ #define FOO(x) 'x' int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; int test (int i, double x); struct s1 {int (*f) (int a);}; struct s2 {int (*f) (double a);}; int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); int argc; char **argv; int main () { return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; ; return 0; } _ACEOF for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_c89=$ac_arg fi rm -f core conftest.err conftest.$ac_objext test "x$ac_cv_prog_cc_c89" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi # AC_CACHE_VAL case "x$ac_cv_prog_cc_c89" in x) { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 $as_echo "none needed" >&6; } ;; xno) { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 $as_echo "unsupported" >&6; } ;; *) CC="$CC $ac_cv_prog_cc_c89" { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 $as_echo "$ac_cv_prog_cc_c89" >&6; } ;; esac if test "x$ac_cv_prog_cc_c89" != xno; then : fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 $as_echo_n "checking how to run the C preprocessor... " >&6; } # On Suns, sometimes $CPP names a directory. if test -n "$CPP" && test -d "$CPP"; then CPP= fi if test -z "$CPP"; then if ${ac_cv_prog_CPP+:} false; then : $as_echo_n "(cached) " >&6 else # Double quotes because CPP needs to be expanded for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" do ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : break fi done ac_cv_prog_CPP=$CPP fi CPP=$ac_cv_prog_CPP else ac_cv_prog_CPP=$CPP fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 $as_echo "$CPP" >&6; } ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "C preprocessor \"$CPP\" fails sanity check See \`config.log' for more details" "$LINENO" 5; } fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_aux_dir= for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do if test -f "$ac_dir/install-sh"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install-sh -c" break elif test -f "$ac_dir/install.sh"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install.sh -c" break elif test -f "$ac_dir/shtool"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/shtool install -c" break fi done if test -z "$ac_aux_dir"; then as_fn_error $? "cannot find install-sh, install.sh, or shtool in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" "$LINENO" 5 fi # These three variables are undocumented and unsupported, # and are intended to be withdrawn in a future Autoconf release. # They can cause serious problems if a builder's source tree is in a directory # whose full name contains unusual characters. ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. # Find a good install program. We prefer a C program (faster), # so one script is as good as another. But avoid the broken or # incompatible versions: # SysV /etc/install, /usr/sbin/install # SunOS /usr/etc/install # IRIX /sbin/install # AIX /bin/install # AmigaOS /C/install, which installs bootblocks on floppy discs # AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag # AFS /usr/afsws/bin/install, which mishandles nonexistent args # SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" # OS/2's system install, which has a completely different semantic # ./install, which can be erroneously created by make from ./install.sh. # Reject install programs that cannot install multiple files. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 $as_echo_n "checking for a BSD-compatible install... " >&6; } if test -z "$INSTALL"; then if ${ac_cv_path_install+:} false; then : $as_echo_n "(cached) " >&6 else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. # Account for people who put trailing slashes in PATH elements. case $as_dir/ in #(( ./ | .// | /[cC]/* | \ /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \ /usr/ucb/* ) ;; *) # OSF1 and SCO ODT 3.0 have their own names for install. # Don't use installbsd from OSF since it installs stuff as root # by default. for ac_prog in ginstall scoinst install; do for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then if test $ac_prog = install && grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # AIX install. It has an incompatible calling convention. : elif test $ac_prog = install && grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # program-specific install script used by HP pwplus--don't use. : else rm -rf conftest.one conftest.two conftest.dir echo one > conftest.one echo two > conftest.two mkdir conftest.dir if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" && test -s conftest.one && test -s conftest.two && test -s conftest.dir/conftest.one && test -s conftest.dir/conftest.two then ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" break 3 fi fi fi done done ;; esac done IFS=$as_save_IFS rm -rf conftest.one conftest.two conftest.dir fi if test "${ac_cv_path_install+set}" = set; then INSTALL=$ac_cv_path_install else # As a last resort, use the slow shell script. Don't cache a # value for INSTALL within a source directory, because that will # break other packages using the cache if that directory is # removed, or if the value is a relative name. INSTALL=$ac_install_sh fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 $as_echo "$INSTALL" >&6; } # Use test -z because SunOS4 sh mishandles braces in ${var-val}. # It thinks the first close brace ends the variable substitution. test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' for ac_prog in md5sum md5 gmd5sum do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_MD5SUM_SIMPLE+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$MD5SUM_SIMPLE"; then ac_cv_prog_MD5SUM_SIMPLE="$MD5SUM_SIMPLE" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_MD5SUM_SIMPLE="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi MD5SUM_SIMPLE=$ac_cv_prog_MD5SUM_SIMPLE if test -n "$MD5SUM_SIMPLE"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MD5SUM_SIMPLE" >&5 $as_echo "$MD5SUM_SIMPLE" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$MD5SUM_SIMPLE" && break done CFLAGS="$CFLAGS -D_GNU_SOURCE" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for socket in -lsocket" >&5 $as_echo_n "checking for socket in -lsocket... " >&6; } if ${ac_cv_lib_socket_socket+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lsocket $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char socket (); int main () { return socket (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_socket_socket=yes else ac_cv_lib_socket_socket=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_socket_socket" >&5 $as_echo "$ac_cv_lib_socket_socket" >&6; } if test "x$ac_cv_lib_socket_socket" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBSOCKET 1 _ACEOF LIBS="-lsocket $LIBS" fi for ac_func in setenv strsignal vsnprintf do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF fi done { $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 $as_echo_n "checking for grep that handles long lines and -e... " >&6; } if ${ac_cv_path_GREP+:} false; then : $as_echo_n "(cached) " >&6 else if test -z "$GREP"; then ac_path_GREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in grep ggrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_GREP" || continue # Check for GNU ac_path_GREP and select it if it is found. # Check for GNU $ac_path_GREP case `"$ac_path_GREP" --version 2>&1` in *GNU*) ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'GREP' >> "conftest.nl" "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_GREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_GREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_GREP"; then as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_GREP=$GREP fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 $as_echo "$ac_cv_path_GREP" >&6; } GREP="$ac_cv_path_GREP" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 $as_echo_n "checking for egrep... " >&6; } if ${ac_cv_path_EGREP+:} false; then : $as_echo_n "(cached) " >&6 else if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 then ac_cv_path_EGREP="$GREP -E" else if test -z "$EGREP"; then ac_path_EGREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in egrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_EGREP" || continue # Check for GNU ac_path_EGREP and select it if it is found. # Check for GNU $ac_path_EGREP case `"$ac_path_EGREP" --version 2>&1` in *GNU*) ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'EGREP' >> "conftest.nl" "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_EGREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_EGREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_EGREP"; then as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_EGREP=$EGREP fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 $as_echo "$ac_cv_path_EGREP" >&6; } EGREP="$ac_cv_path_EGREP" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for EPROTO" >&5 $as_echo_n "checking for EPROTO... " >&6; } if ${userv_cv_hdr_eproto+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #ifdef EPROTO yes #endif _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "yes" >/dev/null 2>&1; then : userv_cv_hdr_eproto=yes else userv_cv_hdr_eproto=no fi rm -f conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $userv_cv_hdr_eproto" >&5 $as_echo "$userv_cv_hdr_eproto" >&6; } if test $userv_cv_hdr_eproto = yes then $as_echo "#define HAVE_EPROTO 1" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for LOG_AUTHPRIV" >&5 $as_echo_n "checking for LOG_AUTHPRIV... " >&6; } if ${userv_cv_hdr_logauthpriv+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #ifdef LOG_AUTHPRIV yes #endif _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "yes" >/dev/null 2>&1; then : userv_cv_hdr_logauthpriv=yes else userv_cv_hdr_logauthpriv=no fi rm -f conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $userv_cv_hdr_logauthpriv" >&5 $as_echo "$userv_cv_hdr_logauthpriv" >&6; } if test $userv_cv_hdr_logauthpriv = yes then $as_echo "#define HAVE_LOG_AUTHPRIV 1" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for WCOREDUMP" >&5 $as_echo_n "checking for WCOREDUMP... " >&6; } if ${userv_cv_hdr_wcoredump+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #ifdef WCOREDUMP yes #endif _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "yes" >/dev/null 2>&1; then : userv_cv_hdr_wcoredump=yes else userv_cv_hdr_wcoredump=no fi rm -f conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $userv_cv_hdr_wcoredump" >&5 $as_echo "$userv_cv_hdr_wcoredump" >&6; } if test $userv_cv_hdr_wcoredump = yes then $as_echo "#define HAVE_WCOREDUMP 1" >>confdefs.h fi if test "${GCC-no}" = yes; then OPTIMISE=-O2 else OPTIMISE=-O fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking your C compiler" >&5 $as_echo_n "checking your C compiler... " >&6; } if ${dpkg_cv_c_works+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { strcmp("a","b") ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : dpkg_cv_c_works=yes else dpkg_cv_c_works=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi if test "x$dpkg_cv_c_works" = xyes; then true { $as_echo "$as_me:${as_lineno-$LINENO}: result: works" >&5 $as_echo "works" >&6; } else true { $as_echo "$as_me:${as_lineno-$LINENO}: result: broken" >&5 $as_echo "broken" >&6; } as_fn_error $? "C compiler is broken" "$LINENO" 5 fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking __attribute__((,,))" >&5 $as_echo_n "checking __attribute__((,,))... " >&6; } if ${dpkg_cv_c_attribute_supported+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { extern int testfunction(int x) __attribute__((,,)) ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : dpkg_cv_c_attribute_supported=yes else dpkg_cv_c_attribute_supported=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi if test "x$dpkg_cv_c_attribute_supported" = xyes; then true { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } $as_echo "#define HAVE_GNUC25_ATTRIB 1" >>confdefs.h { $as_echo "$as_me:${as_lineno-$LINENO}: checking __attribute__((noreturn))" >&5 $as_echo_n "checking __attribute__((noreturn))... " >&6; } if ${dpkg_cv_c_attribute_noreturn+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { extern int testfunction(int x) __attribute__((noreturn)) ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : dpkg_cv_c_attribute_noreturn=yes else dpkg_cv_c_attribute_noreturn=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi if test "x$dpkg_cv_c_attribute_noreturn" = xyes; then true { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } $as_echo "#define HAVE_GNUC25_NORETURN 1" >>confdefs.h else true { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking __attribute__((unused))" >&5 $as_echo_n "checking __attribute__((unused))... " >&6; } if ${dpkg_cv_c_attribute_unused+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { extern int testfunction(int x) __attribute__((unused)) ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : dpkg_cv_c_attribute_unused=yes else dpkg_cv_c_attribute_unused=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi if test "x$dpkg_cv_c_attribute_unused" = xyes; then true { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } $as_echo "#define HAVE_GNUC25_UNUSED 1" >>confdefs.h else true { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking __attribute__((format...))" >&5 $as_echo_n "checking __attribute__((format...))... " >&6; } if ${dpkg_cv_attribute_format+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { extern int testfunction(char *y, ...) __attribute__((format(printf,1,2))) ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : dpkg_cv_attribute_format=yes else dpkg_cv_attribute_format=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi if test "x$dpkg_cv_attribute_format" = xyes; then true { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } $as_echo "#define HAVE_GNUC25_PRINTFFORMAT 1" >>confdefs.h else true { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi else true { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi CWARNS="" { $as_echo "$as_me:${as_lineno-$LINENO}: checking GCC warning flag(s) -Wall -Wno-implicit" >&5 $as_echo_n "checking GCC warning flag(s) -Wall -Wno-implicit... " >&6; } if test "${GCC-no}" = yes then if ${dpkg_cv_c_gcc_warn_all+:} false; then : $as_echo_n "(cached) " >&6 else oldcflags="${CFLAGS-}" CFLAGS="${CFLAGS-} ${CWARNS} -Wall -Wno-implicit -Werror" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include int main () { strcmp("a","b"); fprintf(stdout,"test ok\n"); ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : dpkg_cv_c_gcc_warn_all=yes else dpkg_cv_c_gcc_warn_all=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext CFLAGS="${oldcflags}" fi if test "x$dpkg_cv_c_gcc_warn_all" = xyes; then CWARNS="${CWARNS} -Wall -Wno-implicit" { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok" >&5 $as_echo "ok" >&6; } else dpkg_cv_c_gcc_warn_all='' { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking GCC warning flag(s) -Wwrite-strings" >&5 $as_echo_n "checking GCC warning flag(s) -Wwrite-strings... " >&6; } if test "${GCC-no}" = yes then if ${dpkg_cv_c_gcc_warn_writestrings+:} false; then : $as_echo_n "(cached) " >&6 else oldcflags="${CFLAGS-}" CFLAGS="${CFLAGS-} ${CWARNS} -Wwrite-strings -Werror" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include int main () { strcmp("a","b"); fprintf(stdout,"test ok\n"); ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : dpkg_cv_c_gcc_warn_writestrings=yes else dpkg_cv_c_gcc_warn_writestrings=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext CFLAGS="${oldcflags}" fi if test "x$dpkg_cv_c_gcc_warn_writestrings" = xyes; then CWARNS="${CWARNS} -Wwrite-strings" { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok" >&5 $as_echo "ok" >&6; } else dpkg_cv_c_gcc_warn_writestrings='' { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking GCC warning flag(s) -Wpointer-arith" >&5 $as_echo_n "checking GCC warning flag(s) -Wpointer-arith... " >&6; } if test "${GCC-no}" = yes then if ${dpkg_cv_c_gcc_warn_pointerarith+:} false; then : $as_echo_n "(cached) " >&6 else oldcflags="${CFLAGS-}" CFLAGS="${CFLAGS-} ${CWARNS} -Wpointer-arith -Werror" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include int main () { strcmp("a","b"); fprintf(stdout,"test ok\n"); ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : dpkg_cv_c_gcc_warn_pointerarith=yes else dpkg_cv_c_gcc_warn_pointerarith=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext CFLAGS="${oldcflags}" fi if test "x$dpkg_cv_c_gcc_warn_pointerarith" = xyes; then CWARNS="${CWARNS} -Wpointer-arith" { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok" >&5 $as_echo "ok" >&6; } else dpkg_cv_c_gcc_warn_pointerarith='' { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking GCC warning flag(s) -Wimplicit -Wnested-externs" >&5 $as_echo_n "checking GCC warning flag(s) -Wimplicit -Wnested-externs... " >&6; } if test "${GCC-no}" = yes then if ${dpkg_cv_c_gcc_warn_implicit+:} false; then : $as_echo_n "(cached) " >&6 else oldcflags="${CFLAGS-}" CFLAGS="${CFLAGS-} ${CWARNS} -Wimplicit -Wnested-externs -Werror" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include int main () { strcmp("a","b"); fprintf(stdout,"test ok\n"); ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : dpkg_cv_c_gcc_warn_implicit=yes else dpkg_cv_c_gcc_warn_implicit=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext CFLAGS="${oldcflags}" fi if test "x$dpkg_cv_c_gcc_warn_implicit" = xyes; then CWARNS="${CWARNS} -Wimplicit -Wnested-externs" { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok" >&5 $as_echo "ok" >&6; } else dpkg_cv_c_gcc_warn_implicit='' { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "${GCC-no}" = yes; then CWARNS="${CWARNS} -Wmissing-prototypes -Wstrict-prototypes" fi CFLAGS="`echo $CFLAGS $CWARNS | sed -e 's/-O[0-9]*/$(OPTIMISE)/'`" VERSION="`sed -n '/^userv (.*)/!d; s/^userv (//; s/).*//; p; q' debian/changelog`" echo will build version $VERSION ac_config_files="$ac_config_files Makefile" cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure # scripts and configure runs, see configure's option --config-cache. # It is not useful on other systems. If it contains results you don't # want to keep, you may remove or edit it. # # config.status only pays attention to the cache file if you give it # the --recheck option to rerun configure. # # `ac_cv_env_foo' variables (set or unset) will be overridden when # loading this file, other *unset* `ac_cv_foo' will be assigned the # following values. _ACEOF # The following way of writing the cache mishandles newlines in values, # but we know of no workaround that is simple, portable, and efficient. # So, we kill variables containing newlines. # Ultrix sh set writes to stderr and can't be redirected directly, # and sets the high bit in the cache file unless we assign to the vars. ( for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space=' '; set) 2>&1` in #( *${as_nl}ac_space=\ *) # `set' does not quote correctly, so add quotes: double-quote # substitution turns \\\\ into \\, and sed turns \\ into \. sed -n \ "s/'/'\\\\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" ;; #( *) # `set' quotes correctly as required by POSIX, so do not add quotes. sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) | sed ' /^ac_cv_env_/b end t clear :clear s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ t end s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ :end' >>confcache if diff "$cache_file" confcache >/dev/null 2>&1; then :; else if test -w "$cache_file"; then if test "x$cache_file" != "x/dev/null"; then { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 $as_echo "$as_me: updating cache $cache_file" >&6;} if test ! -f "$cache_file" || test -h "$cache_file"; then cat confcache >"$cache_file" else case $cache_file in #( */* | ?:*) mv -f confcache "$cache_file"$$ && mv -f "$cache_file"$$ "$cache_file" ;; #( *) mv -f confcache "$cache_file" ;; esac fi fi else { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 $as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} fi fi rm -f confcache test "x$prefix" = xNONE && prefix=$ac_default_prefix # Let make expand exec_prefix. test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' DEFS=-DHAVE_CONFIG_H ac_libobjs= ac_ltlibobjs= U= for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue # 1. Remove the extension, and $U if already installed. ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' ac_i=`$as_echo "$ac_i" | sed "$ac_script"` # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR # will be set to the directory where LIBOBJS objects are built. as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' done LIBOBJS=$ac_libobjs LTLIBOBJS=$ac_ltlibobjs : "${CONFIG_STATUS=./config.status}" ac_write_fail=0 ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files $CONFIG_STATUS" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 $as_echo "$as_me: creating $CONFIG_STATUS" >&6;} as_write_fail=0 cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 #! $SHELL # Generated by $as_me. # Run this file to recreate the current configuration. # Compiler output produced by configure, useful for debugging # configure, is in config.log if it exists. debug=false ac_cs_recheck=false ac_cs_silent=false SHELL=\${CONFIG_SHELL-$SHELL} export SHELL _ASEOF cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo # Prefer a ksh shell builtin over an external printf program on Solaris, # but without wasting forks for bash or zsh. if test -z "$BASH_VERSION$ZSH_VERSION" \ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='print -r --' as_echo_n='print -rn --' elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Unset variables that we do not need and which cause bugs (e.g. in # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" # suppresses any "Segmentation fault" message there. '((' could # trigger a bug in pdksh 5.2.14. for as_var in BASH_ENV ENV MAIL MAILPATH do eval test x\${$as_var+set} = xset \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : eval 'as_fn_append () { eval $1+=\$2 }' else as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : eval 'as_fn_arith () { as_val=$(( $* )) }' else as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -pR' fi else as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi # as_fn_executable_p FILE # ----------------------- # Test if FILE is an executable regular file. as_fn_executable_p () { test -f "$1" && test -x "$1" } # as_fn_executable_p as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" exec 6>&1 ## ----------------------------------- ## ## Main body of $CONFIG_STATUS script. ## ## ----------------------------------- ## _ASEOF test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Save the log message, to keep $0 and so on meaningful, and to # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" This file was extended by $as_me, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS CONFIG_LINKS = $CONFIG_LINKS CONFIG_COMMANDS = $CONFIG_COMMANDS $ $0 $@ on `(hostname || uname -n) 2>/dev/null | sed 1q` " _ACEOF case $ac_config_files in *" "*) set x $ac_config_files; shift; ac_config_files=$*;; esac case $ac_config_headers in *" "*) set x $ac_config_headers; shift; ac_config_headers=$*;; esac cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # Files that config.status was made for. config_files="$ac_config_files" config_headers="$ac_config_headers" _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 ac_cs_usage="\ \`$as_me' instantiates files and other configuration actions from templates according to the current configuration. Unless the files and actions are specified as TAGs, all are instantiated by default. Usage: $0 [OPTION]... [TAG]... -h, --help print this help, then exit -V, --version print version number and configuration settings, then exit --config print configuration, then exit -q, --quiet, --silent do not print progress messages -d, --debug don't remove temporary files --recheck update $as_me by reconfiguring in the same conditions --file=FILE[:TEMPLATE] instantiate the configuration file FILE --header=FILE[:TEMPLATE] instantiate the configuration header FILE Configuration files: $config_files Configuration headers: $config_headers Report bugs to the package provider." _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ config.status configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" Copyright (C) 2012 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." ac_pwd='$ac_pwd' srcdir='$srcdir' INSTALL='$INSTALL' test -n "\$AWK" || AWK=awk _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # The default lists apply if the user does not specify any file. ac_need_defaults=: while test $# != 0 do case $1 in --*=?*) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` ac_shift=: ;; --*=) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg= ac_shift=: ;; *) ac_option=$1 ac_optarg=$2 ac_shift=shift ;; esac case $ac_option in # Handling of the options. -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) ac_cs_recheck=: ;; --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) $as_echo "$ac_cs_version"; exit ;; --config | --confi | --conf | --con | --co | --c ) $as_echo "$ac_cs_config"; exit ;; --debug | --debu | --deb | --de | --d | -d ) debug=: ;; --file | --fil | --fi | --f ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; '') as_fn_error $? "missing file argument" ;; esac as_fn_append CONFIG_FILES " '$ac_optarg'" ac_need_defaults=false;; --header | --heade | --head | --hea ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; esac as_fn_append CONFIG_HEADERS " '$ac_optarg'" ac_need_defaults=false;; --he | --h) # Conflict between --help and --header as_fn_error $? "ambiguous option: \`$1' Try \`$0 --help' for more information.";; --help | --hel | -h ) $as_echo "$ac_cs_usage"; exit ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil | --si | --s) ac_cs_silent=: ;; # This is an error. -*) as_fn_error $? "unrecognized option: \`$1' Try \`$0 --help' for more information." ;; *) as_fn_append ac_config_targets " $1" ac_need_defaults=false ;; esac shift done ac_configure_extra_args= if $ac_cs_silent; then exec 6>/dev/null ac_configure_extra_args="$ac_configure_extra_args --silent" fi _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 if \$ac_cs_recheck; then set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion shift \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 CONFIG_SHELL='$SHELL' export CONFIG_SHELL exec "\$@" fi _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 exec 5>>config.log { echo sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX ## Running $as_me. ## _ASBOX $as_echo "$ac_log" } >&5 _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Handling of arguments. for ac_config_target in $ac_config_targets do case $ac_config_target in "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;; "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; esac done # If the user did not use the arguments to specify the items to instantiate, # then the envvar interface is used. Set only those that are not. # We use the long form for the default assignment because of an extremely # bizarre bug on SunOS 4.1.3. if $ac_need_defaults; then test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers fi # Have a temporary directory for convenience. Make it in the build tree # simply because there is no reason against having it here, and in addition, # creating and moving files from /tmp can sometimes cause problems. # Hook for its removal unless debugging. # Note that there is a small window in which the directory will not be cleaned: # after its creation but before its name has been assigned to `$tmp'. $debug || { tmp= ac_tmp= trap 'exit_status=$? : "${ac_tmp:=$tmp}" { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status ' 0 trap 'as_fn_exit 1' 1 2 13 15 } # Create a (secure) tmp directory for tmp files. { tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && test -d "$tmp" } || { tmp=./conf$$-$RANDOM (umask 077 && mkdir "$tmp") } || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 ac_tmp=$tmp # Set up the scripts for CONFIG_FILES section. # No need to generate them if there are no CONFIG_FILES. # This happens for instance with `./config.status config.h'. if test -n "$CONFIG_FILES"; then ac_cr=`echo X | tr X '\015'` # On cygwin, bash can eat \r inside `` if the user requested igncr. # But we know of no other shell where ac_cr would be empty at this # point, so we can use a bashism as a fallback. if test "x$ac_cr" = x; then eval ac_cr=\$\'\\r\' fi ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then ac_cs_awk_cr='\\r' else ac_cs_awk_cr=$ac_cr fi echo 'BEGIN {' >"$ac_tmp/subs1.awk" && _ACEOF { echo "cat >conf$$subs.awk <<_ACEOF" && echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && echo "_ACEOF" } >conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` ac_delim='%!_!# ' for ac_last_try in false false false false false :; do . ./conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` if test $ac_delim_n = $ac_delim_num; then break elif $ac_last_try; then as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done rm -f conf$$subs.sh cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && _ACEOF sed -n ' h s/^/S["/; s/!.*/"]=/ p g s/^[^!]*!// :repl t repl s/'"$ac_delim"'$// t delim :nl h s/\(.\{148\}\)..*/\1/ t more1 s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ p n b repl :more1 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t nl :delim h s/\(.\{148\}\)..*/\1/ t more2 s/["\\]/\\&/g; s/^/"/; s/$/"/ p b :more2 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t delim ' >$CONFIG_STATUS || ac_write_fail=1 rm -f conf$$subs.awk cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACAWK cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && for (key in S) S_is_set[key] = 1 FS = "" } { line = $ 0 nfields = split(line, field, "@") substed = 0 len = length(field[1]) for (i = 2; i < nfields; i++) { key = field[i] keylen = length(key) if (S_is_set[key]) { value = S[key] line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) len += length(value) + length(field[++i]) substed = 1 } else len += 1 + keylen } print line } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" else cat fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 _ACEOF # VPATH may cause trouble with some makes, so we remove sole $(srcdir), # ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and # trailing colons and then remove the whole line if VPATH becomes empty # (actually we leave an empty line to preserve line numbers). if test "x$srcdir" = x.; then ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ h s/// s/^/:/ s/[ ]*$/:/ s/:\$(srcdir):/:/g s/:\${srcdir}:/:/g s/:@srcdir@:/:/g s/^:*// s/:*$// x s/\(=[ ]*\).*/\1/ G s/\n// s/^[^=]*=[ ]*$// }' fi cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 fi # test -n "$CONFIG_FILES" # Set up the scripts for CONFIG_HEADERS section. # No need to generate them if there are no CONFIG_HEADERS. # This happens for instance with `./config.status Makefile'. if test -n "$CONFIG_HEADERS"; then cat >"$ac_tmp/defines.awk" <<\_ACAWK || BEGIN { _ACEOF # Transform confdefs.h into an awk script `defines.awk', embedded as # here-document in config.status, that substitutes the proper values into # config.h.in to produce config.h. # Create a delimiter string that does not exist in confdefs.h, to ease # handling of long lines. ac_delim='%!_!# ' for ac_last_try in false false :; do ac_tt=`sed -n "/$ac_delim/p" confdefs.h` if test -z "$ac_tt"; then break elif $ac_last_try; then as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done # For the awk script, D is an array of macro values keyed by name, # likewise P contains macro parameters if any. Preserve backslash # newline sequences. ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]* sed -n ' s/.\{148\}/&'"$ac_delim"'/g t rset :rset s/^[ ]*#[ ]*define[ ][ ]*/ / t def d :def s/\\$// t bsnl s/["\\]/\\&/g s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ D["\1"]=" \3"/p s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p d :bsnl s/["\\]/\\&/g s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ D["\1"]=" \3\\\\\\n"\\/p t cont s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p t cont d :cont n s/.\{148\}/&'"$ac_delim"'/g t clear :clear s/\\$// t bsnlc s/["\\]/\\&/g; s/^/"/; s/$/"/p d :bsnlc s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p b cont ' >$CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 for (key in D) D_is_set[key] = 1 FS = "" } /^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ { line = \$ 0 split(line, arg, " ") if (arg[1] == "#") { defundef = arg[2] mac1 = arg[3] } else { defundef = substr(arg[1], 2) mac1 = arg[2] } split(mac1, mac2, "(") #) macro = mac2[1] prefix = substr(line, 1, index(line, defundef) - 1) if (D_is_set[macro]) { # Preserve the white space surrounding the "#". print prefix "define", macro P[macro] D[macro] next } else { # Replace #undef with comments. This is necessary, for example, # in the case of _POSIX_SOURCE, which is predefined and required # on some systems where configure will not decide to define it. if (defundef == "undef") { print "/*", prefix defundef, macro, "*/" next } } } { print } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 as_fn_error $? "could not setup config headers machinery" "$LINENO" 5 fi # test -n "$CONFIG_HEADERS" eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS " shift for ac_tag do case $ac_tag in :[FHLC]) ac_mode=$ac_tag; continue;; esac case $ac_mode$ac_tag in :[FHL]*:*);; :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; :[FH]-) ac_tag=-:-;; :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; esac ac_save_IFS=$IFS IFS=: set x $ac_tag IFS=$ac_save_IFS shift ac_file=$1 shift case $ac_mode in :L) ac_source=$1;; :[FH]) ac_file_inputs= for ac_f do case $ac_f in -) ac_f="$ac_tmp/stdin";; *) # Look for the file first in the build tree, then in the source tree # (if the path is not absolute). The absolute path cannot be DOS-style, # because $ac_f cannot contain `:'. test -f "$ac_f" || case $ac_f in [\\/$]*) false;; *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; esac || as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; esac case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac as_fn_append ac_file_inputs " '$ac_f'" done # Let's still pretend it is `configure' which instantiates (i.e., don't # use $as_me), people would be surprised to read: # /* config.h. Generated by config.status. */ configure_input='Generated from '` $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' `' by configure.' if test x"$ac_file" != x-; then configure_input="$ac_file. $configure_input" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 $as_echo "$as_me: creating $ac_file" >&6;} fi # Neutralize special characters interpreted by sed in replacement strings. case $configure_input in #( *\&* | *\|* | *\\* ) ac_sed_conf_input=`$as_echo "$configure_input" | sed 's/[\\\\&|]/\\\\&/g'`;; #( *) ac_sed_conf_input=$configure_input;; esac case $ac_tag in *:-:* | *:-) cat >"$ac_tmp/stdin" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; esac ;; esac ac_dir=`$as_dirname -- "$ac_file" || $as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$ac_file" : 'X\(//\)[^/]' \| \ X"$ac_file" : 'X\(//\)$' \| \ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$ac_file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` as_dir="$ac_dir"; as_fn_mkdir_p ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix case $ac_mode in :F) # # CONFIG_FILE # case $INSTALL in [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; esac _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # If the template does not know about datarootdir, expand it. # FIXME: This hack should be removed a few years after 2.60. ac_datarootdir_hack=; ac_datarootdir_seen= ac_sed_dataroot=' /datarootdir/ { p q } /@datadir@/p /@docdir@/p /@infodir@/p /@localedir@/p /@mandir@/p' case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in *datarootdir*) ac_datarootdir_seen=yes;; *@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 $as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_datarootdir_hack=' s&@datadir@&$datadir&g s&@docdir@&$docdir&g s&@infodir@&$infodir&g s&@localedir@&$localedir&g s&@mandir@&$mandir&g s&\\\${datarootdir}&$datarootdir&g' ;; esac _ACEOF # Neutralize VPATH when `$srcdir' = `.'. # Shell code in configure.ac might set extrasub. # FIXME: do we really want to maintain this feature? cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_sed_extra="$ac_vpsub $extrasub _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 :t /@[a-zA-Z_][a-zA-Z_0-9]*@/!b s|@configure_input@|$ac_sed_conf_input|;t t s&@top_builddir@&$ac_top_builddir_sub&;t t s&@top_build_prefix@&$ac_top_build_prefix&;t t s&@srcdir@&$ac_srcdir&;t t s&@abs_srcdir@&$ac_abs_srcdir&;t t s&@top_srcdir@&$ac_top_srcdir&;t t s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t s&@builddir@&$ac_builddir&;t t s&@abs_builddir@&$ac_abs_builddir&;t t s&@abs_top_builddir@&$ac_abs_top_builddir&;t t s&@INSTALL@&$ac_INSTALL&;t t $ac_datarootdir_hack " eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ "$ac_tmp/out"`; test -z "$ac_out"; } && { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&5 $as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&2;} rm -f "$ac_tmp/stdin" case $ac_file in -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; esac \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; :H) # # CONFIG_HEADER # if test x"$ac_file" != x-; then { $as_echo "/* $configure_input */" \ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" } >"$ac_tmp/config.h" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 $as_echo "$as_me: $ac_file is unchanged" >&6;} else rm -f "$ac_file" mv "$ac_tmp/config.h" "$ac_file" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 fi else $as_echo "/* $configure_input */" \ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \ || as_fn_error $? "could not create -" "$LINENO" 5 fi ;; esac done # for ac_tag as_fn_exit 0 _ACEOF ac_clean_files=$ac_clean_files_save test $ac_write_fail = 0 || as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 # configure is writing to config.log, and then calls config.status. # config.status does its own redirection, appending to config.log. # Unfortunately, on DOS this fails, as config.log is still kept open # by configure, so config.status won't be able to write to it; its # output is simply discarded. So we exec the FD to /dev/null, # effectively closing config.log, so it can be properly (re)opened and # appended to by config.status. When coming back to configure, we # need to make the FD available again. if test "$no_create" != yes; then ac_cs_success=: ac_config_status_args= test "$silent" = yes && ac_config_status_args="$ac_config_status_args --quiet" exec 5>/dev/null $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false exec 5>>config.log # Use ||, not &&, to avoid exiting from the if with $? = 1, which # would make configure fail if this is the last instruction. $ac_cs_success || as_fn_exit 1 fi if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} fi work/configure.in0000664000000000000000000001161214163725562011255 0ustar # userv - configure.in # # userv is copyright Ian Jackson and other contributors. # See README for full authorship information. # # 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 this program. If not, see . AC_INIT(language.i4) AC_CONFIG_HEADER(config.h) AC_PREFIX_DEFAULT(/usr/local) crdir="`pwd`" AC_SUBST(DEBUGDEFS) AC_SUBST(DEBUGLIBS) DEBUGDEFS='' DEBUGLIBS='' AC_ARG_ENABLE(debug, [ --enable-debug build debugging version], [ if test "x$enable_debug" = xyes; then DEBUGDEFS="-DDEBUG -DVARDIR='\"$crdir/vd\"' -DSYSTEMCONFIGDIR='\"$crdir/slash-etc\"' -DSERVICEUSERDIR='\"$crdir/tilde\"'" DEBUGLIBS=-lefence echo will build debugging version elif test "x$enable_debug" != xno; then AC_MSG_ERROR(--enable-debug does not allow any arguments except 'yes' and 'no') fi ]) AC_PROG_CC AC_PROG_CPP AC_PROG_INSTALL AC_CHECK_PROGS(MD5SUM_SIMPLE, md5sum md5 gmd5sum) CFLAGS="$CFLAGS -D_GNU_SOURCE" AC_CHECK_LIB(socket,socket) AC_CHECK_FUNCS(setenv strsignal vsnprintf) AC_CACHE_CHECK([for EPROTO],userv_cv_hdr_eproto,[ AC_EGREP_CPP(yes, [ #include #ifdef EPROTO yes #endif ],userv_cv_hdr_eproto=yes,userv_cv_hdr_eproto=no)]) if test $userv_cv_hdr_eproto = yes then AC_DEFINE(HAVE_EPROTO) fi AC_CACHE_CHECK([for LOG_AUTHPRIV],userv_cv_hdr_logauthpriv,[ AC_EGREP_CPP(yes, [ #include #ifdef LOG_AUTHPRIV yes #endif ],userv_cv_hdr_logauthpriv=yes,userv_cv_hdr_logauthpriv=no)]) if test $userv_cv_hdr_logauthpriv = yes then AC_DEFINE(HAVE_LOG_AUTHPRIV) fi AC_CACHE_CHECK([for WCOREDUMP],userv_cv_hdr_wcoredump,[ AC_EGREP_CPP(yes, [ #include #include #ifdef WCOREDUMP yes #endif ],userv_cv_hdr_wcoredump=yes,userv_cv_hdr_wcoredump=no)]) if test $userv_cv_hdr_wcoredump = yes then AC_DEFINE(HAVE_WCOREDUMP) fi AC_SUBST(OPTIMISE) if test "${GCC-no}" = yes; then OPTIMISE=-O2 else OPTIMISE=-O fi dnl DPKG_CACHED_TRY_COMPILE(,,,,,) define(DPKG_CACHED_TRY_COMPILE,[ AC_MSG_CHECKING($1) AC_CACHE_VAL($2,[ AC_TRY_COMPILE([$3],[$4],[$2=yes],[$2=no]) ]) if test "x$$2" = xyes; then true $5 else true $6 fi ]) DPKG_CACHED_TRY_COMPILE(your C compiler,dpkg_cv_c_works, [#include ], [strcmp("a","b")], AC_MSG_RESULT(works), AC_MSG_RESULT(broken) AC_MSG_ERROR(C compiler is broken)) DPKG_CACHED_TRY_COMPILE(__attribute__((,,)),dpkg_cv_c_attribute_supported,, [extern int testfunction(int x) __attribute__((,,))], AC_MSG_RESULT(yes) AC_DEFINE(HAVE_GNUC25_ATTRIB) DPKG_CACHED_TRY_COMPILE(__attribute__((noreturn)),dpkg_cv_c_attribute_noreturn,, [extern int testfunction(int x) __attribute__((noreturn))], AC_MSG_RESULT(yes) AC_DEFINE(HAVE_GNUC25_NORETURN), AC_MSG_RESULT(no)) DPKG_CACHED_TRY_COMPILE(__attribute__((unused)),dpkg_cv_c_attribute_unused,, [extern int testfunction(int x) __attribute__((unused))], AC_MSG_RESULT(yes) AC_DEFINE(HAVE_GNUC25_UNUSED), AC_MSG_RESULT(no)) DPKG_CACHED_TRY_COMPILE(__attribute__((format...)),dpkg_cv_attribute_format,, [extern int testfunction(char *y, ...) __attribute__((format(printf,1,2)))], AC_MSG_RESULT(yes) AC_DEFINE(HAVE_GNUC25_PRINTFFORMAT), AC_MSG_RESULT(no)), AC_MSG_RESULT(no)) AC_SUBST(CWARNS) CWARNS="" dnl DPKG_C_GCC_TRY_WARNS(,) define(DPKG_C_GCC_TRY_WARNS,[ AC_MSG_CHECKING([GCC warning flag(s) $1]) if test "${GCC-no}" = yes then AC_CACHE_VAL($2,[ oldcflags="${CFLAGS-}" CFLAGS="${CFLAGS-} ${CWARNS} $1 -Werror" AC_TRY_COMPILE([ #include #include ],[ strcmp("a","b"); fprintf(stdout,"test ok\n"); ], [$2=yes], [$2=no]) CFLAGS="${oldcflags}"]) if test "x$$2" = xyes; then CWARNS="${CWARNS} $1" AC_MSG_RESULT(ok) else $2='' AC_MSG_RESULT(no) fi else AC_MSG_RESULT(no, not using GCC) fi ]) DPKG_C_GCC_TRY_WARNS(-Wall -Wno-implicit, dpkg_cv_c_gcc_warn_all) DPKG_C_GCC_TRY_WARNS(-Wwrite-strings, dpkg_cv_c_gcc_warn_writestrings) DPKG_C_GCC_TRY_WARNS(-Wpointer-arith, dpkg_cv_c_gcc_warn_pointerarith) DPKG_C_GCC_TRY_WARNS(-Wimplicit -Wnested-externs, dpkg_cv_c_gcc_warn_implicit) if test "${GCC-no}" = yes; then CWARNS="${CWARNS} -Wmissing-prototypes -Wstrict-prototypes" fi [CFLAGS="`echo $CFLAGS $CWARNS | sed -e 's/-O[0-9]*/$(OPTIMISE)/'`"] AC_SUBST(VERSION) VERSION="`sed -n '/^userv (.*)/!d; s/^userv (//; s/).*//; p; q' debian/changelog`" echo will build version $VERSION AC_OUTPUT(Makefile) work/daemon.h0000664000000000000000000001460114163725562010361 0ustar /* * userv - daemon.h * definitions used in the daemon's source code * * userv is copyright Ian Jackson and other contributors. * See README for full authorship information. * * 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; if not, see . */ #ifndef DAEMON_H #define DAEMON_H #include #define RESET_CONFIGURATION " \n\ cd ~/ \n\ reject \n\ no-set-environment \n\ suppress-args \n\ allow-fd 0 read \n\ allow-fd 1-2 write \n\ reject-fd 3- \n\ disconnect-hup \n\ include-lookup-quote-new \n\ " #ifndef SYSTEMCONFIGDIR # ifdef DEBUG # define SYSTEMCONFIGDIR "slash-etc" # else # define SYSTEMCONFIGDIR "/etc" # endif #endif #ifndef DEFAULTPATH_USER # define DEFAULTPATH_USER "/usr/local/bin:/bin:/usr/bin" #endif #ifndef DEFAULTPATH_ROOT # define DEFAULTPATH_ROOT "/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin" #endif #ifndef SETENVIRONMENT # define SETENVIRONMENT "environment" #endif #define USERRCFILE "rc" #define SYSTEMUSERVCONFIGDIR "userv" #define SHELLLIST "shells" #define SYSTEMRCFILEDEFAULT "system.default" #define SYSTEMRCFILEOVERRIDE "system.override" #define NONEINCLUDELOOKUP ":none" #define DEFAULTINCLUDELOOKUP ":default" #define EMPTYINCLUDELOOKUP ":empty" #define USERCONFIGDIRBASE SYSTEMUSERVCONFIGDIR #define USERCONFIGDIR "." USERCONFIGDIRBASE #define USERUSERVCONFIGPATH "~/" USERCONFIGDIR #define USERRCFILEPATH USERUSERVCONFIGPATH "/" USERRCFILE #define SYSTEMUSERVCONFIGPATH SYSTEMCONFIGDIR "/" SYSTEMUSERVCONFIGDIR #define SYSTEMRCFILEDEFAULTPATH SYSTEMUSERVCONFIGPATH "/" SYSTEMRCFILEDEFAULT #define SYSTEMRCFILEOVERRIDEPATH SYSTEMUSERVCONFIGPATH "/" SYSTEMRCFILEOVERRIDE #define SHELLLISTPATH SYSTEMCONFIGDIR "/" SHELLLIST #define SETENVIRONMENTPATH SYSTEMCONFIGDIR "/" SETENVIRONMENT #define USERVD_LOGIDENT "uservd" #define USERVDCHECK_LOGIDENT "uservd/check" #define USERVD_LOGFACILITY LOG_DAEMON #define DEFUSERLOGFACILITY LOG_USER #define DEFUSERLOGLEVEL LOG_ERR #define TOPLEVEL_CONFIGURATION " \n\ reset \n\ user-rcfile " USERRCFILEPATH " \n\ errors-to-stderr \n\ _include-sysconfig " SYSTEMRCFILEDEFAULTPATH " \n\ if grep service-user-shell " SHELLLISTPATH " \n\ errors-push \n\ catch-quit \n\ _include-user-rcfile \n\ hctac \n\ srorre \n\ fi \n\ _include-sysconfig " SYSTEMRCFILEOVERRIDEPATH " \n\ quit \n\ " #define TOPLEVEL_OVERRIDDEN_CONFIGURATION " \n\ reset \n\ errors-to-stderr \n\ _include-client-config \n\ quit \n\ " #define USERVD_MYSELF_CHECK 3600 #define USERVD_MYSELF_TIMEOUT 60 #define USERVD_CHECKFORK_RETRY 60 #define MAX_INCLUDE_NEST 40 #define MAX_ERRMSG_LEN (MAX_ERRMSG_STRING-1024) #define ERRMSG_RESERVE_ERRNO 128 int parse_string(const char *string, const char *descrip, int isinternal); int parseerrprint(const char *fmt, ...) PRINTFFORMAT(1,2); void ensurelogopen(int wantfacility); void ensurefdarray(int fd); const char *printtoken(int token); void senderrmsgstderr(const char *errmsg); void disconnect(int exitstatus) NONRETURNING; void always_dumpparameter(const char *parm, char **values); void always_dumpexecsettings(void); void debug_dumprequest(pid_t mypid); void debug_dumpexecsettings(void); void debug_dumpparameter(const char *parm, char **values); pid_t nondebug_fork(void); const char *nondebug_serviceuserdir(const char *ifnondebug); typedef void builtinserviceexec_fnt(const char *const *args); builtinserviceexec_fnt NONRETURNING bisexec_environment, bisexec_parameter; builtinserviceexec_fnt NONRETURNING bisexec_version, bisexec_help; builtinserviceexec_fnt NONRETURNING bisexec_toplevel, bisexec_override, bisexec_reset; builtinserviceexec_fnt NONRETURNING bisexec_execute, bisexec_shutdown; extern const char *const builtinservicehelpstrings[]; void execservice(const int synchsocket[], int clientfd) NONRETURNING; void servicerequest(int sfd) NONRETURNING; int synchread(int fd, int ch); const char *defaultpath(void); struct fdstate { int iswrite; /* 0 or 1; -1 if not open */ int realfd, holdfd; /* -1 if not open */ int wantstate; /* tokv_word_requirefd, tokv_word_allowfd, tokv_nullfd, tokv_word_rejectfd * (all of which have tokt_wantfdstate set) */ int wantrw; /* tokv_word_read, tokv_word_write, 0 for either/both */ }; struct keyvaluepair { char *key, *value; }; extern pid_t overlordpid; extern struct request_msg request_mbuf; extern struct keyvaluepair *defvararray; extern struct fdstate *fdarray; /* indexed by nominal fd */ extern int fdarraysize, fdarrayused; extern int restfdwantstate, restfdwantrw; extern int service_ngids; extern char **argarray; extern char *serviceuser, *service, *loginname, *cwd; extern char *overridedata, *userrcfile; extern char *serviceuser_dir, *serviceuser_shell, *callinguser_shell; extern gid_t *calling_gids, *service_gids; extern uid_t serviceuser_uid; extern const char **calling_groups, **service_groups; extern char *execpath, **execargs; extern int execute; /* One of the execution modes tokt_execmode */ extern int setenvironment, suppressargs, disconnecthup; extern builtinserviceexec_fnt *execbuiltin; extern int syslogopenfacility; #endif work/debian/0000775000000000000000000000000014163725562010165 5ustar work/debian/.gitignore0000664000000000000000000000023214163725562012152 0ustar userv .debhelper substvars *.substvars files debhelper.log debhelper-build-stamp userv.debhelper.log userv.*.debhelper autoreconf.before autoreconf.after work/debian/changelog0000664000000000000000000005010514163725562012040 0ustar userv (1.2.1~beta4) unstable; urgency=medium * debian/control: Re-add missing build-dependency on fonts-dejavu. Fixes FTBFS, this time for sure! See also #1002919. -- Ian Jackson Sat, 01 Jan 2022 01:16:34 +0000 userv (1.2.1~beta3) unstable; urgency=medium * debian/control: Add missing build-dependency on flex. Fixes FTBFS. Report from Aurelien Jarno. Closes: #1002914. -- Ian Jackson Fri, 31 Dec 2021 22:24:40 +0000 userv (1.2.1~beta2) unstable; urgency=medium Documentation generation changes: * spec: Generate printable file as pdf via docbook. * spec: Correct information about userv's authorship. * spec: Update builtin version number. * overview diagram: Build as pdf, with a sensible page layout. Debian packaging changes: * Switch to dh auto sequencer. Many consequences: - Upstream README is /usr/share/doc/userv/README, not README.upstream. * Control file md5sums are provided. * New changelog symlink for changelog.Debian.gz. * We use the proper Debian debug information scheme. * We use different compiler flags, which will hopefully produce better hardening and better reproducibility. * debian: Use debhelper to generate maint scripts (daemon start/stop). * Add misisng build-dependency on "transfig" (previously masked by our TeX requirements). * Build everything from actual sources; don't reuse committed files. * init script: Source /lib/lsb/init-functions. * debian/control: Fix debhelper build-depends version. * debian/copyright: Mention /usr/share/common-licenses/GPL-3. * debian/control: Bump Standards-Version (no changes needed). Fixes to upstream "make install-docs" target: * Ship docs to /usr/share/doc/userv, not /usr/userv (!) * Ship manpages to /usr/share, not /usr, by default. * Install default config files as examples too. * Provide "[un]install-docs" target (not just anomalous "install-doc"). Inconsequential code changes: * Suppress some warnings about ignoring stderr write errors. * overlord: Explicitly ignore unwanted value from write. Upstream build system and packaging tidying: * regenerate lexer.c using flex 2.6.4-6.2. * regenerate rautoconf outputs with auatoconf 2.69-11. * Add autogen.sh. * Add some missing configure.in quoting (needed by modern autoconf). * "make install": Honour DESTDIR; create bindir and sbindir if needed. * "make install": Do not pass -m to install -d; introduce INSTALL_DIR. * overview diagram: Override non-reproducible date inserted by fig2dev. * copyright: Add missing dates and names. Simplify notices. * Update my own email address. * changelog: Add "Old Changelog:" note to help Debian's parsers. * gitignore: add missing entries, move debian stuff to debian/. * Makefile: Refactoring of installation targets. * Makefile: Remove obsolete dist target. -- Ian Jackson Wed, 29 Dec 2021 19:32:19 +0000 userv (1.2.1~beta1) unstable; urgency=medium Bugfixes: * Do not leak a harmless fd into the service program. Closes: #864876. * spec: Do not claim you can specify numeric service uid. Closes: #989048. Packaging: * Provide a systemd service file in the source tree, but (for now) do not install it. Re #939573. Service file provided by Matthew Vernon. * debian/compat: Bump to 12 (stretch-backports). Closes: #965858. * autopkgtests: Add some tests to check installation and operation. * debian/rules: Fix cross-building. Closes: #985998. [Helmut Grohne] -- Ian Jackson Sun, 26 Dec 2021 01:32:33 +0000 userv (1.2.0) unstable; urgency=medium Bugfixes: * Support `stdin', `stdout' and `stderr' in fd ranges, as promised by the spec. Closes:#813005. * Support `range' operator, as promised by the spec. Closes:#686449. Bug and analysis from Mark Wooding. * Do not ignore errors from readdir. Closes:#827408 [Peter Benie]. * Correct docs for errors-push, which takes no filename. Closes:#775852. * Correct quoting of include-lookup directory. Closes:#837391. (With new directives to somewhat ease backward-compatibility.) Packaging etc. * Honour XCFLAGS. * Use `%option nounput' rather than #define YY_NO_UNPUT. Patch from Peter Benie. * Specify #define YY_NO_INPUT, which avoids an unused function warning. Patch from Peter Benie. * Update copyright notices. * Upgrade licence to GPLv3+. Debian packaging: * Honour dpkg-buildflags. * Add some newer debian/ droppings to .gitignore. -- Ian Jackson Mon, 23 Jan 2017 17:17:54 +0000 userv (1.1.1) unstable; urgency=low * Include INIT INFO stanza in init script. * Draft support for `status' in init script, currently commented out pending inclusion into policy of firm specification. * Remove spec.ps on make clean. * Remove spec.ps and dh log on debian/rules clean. (Use dh_clean.) (To repro bug: dpkg-buildpackage, debian/rules clean, git-ls-files -o) * Fix up some copyright messages. -- Ian Jackson Fri, 08 Jun 2012 20:16:52 +0100 userv (1.1.0) unstable; urgency=medium Bugfix: * Do not reject comments and blank lines inside not-being-executed conditional clauses. (Closes: #613862.) Important Debian packaging fix: * Remove /var/run/userv from the .deb. (Along with the change in 1.0.6 this Closes: #630528.) General minor improvements (relevant outside Debian): * Introduce a use of socklen_t to avoid a compiler warning. * Remove spec.html and spec.ps from revision control. * Revision control switched from cvs to git. * Update my email address. Debian packaging minor improvements and bugfixes: * The new version will ensure a rebuild and therefore completely deal with the debiandoc-sgml missing documentation bug. (Closes: #413873.) * Use lintian for dh_fixperms; this ensures that the permissions of /etc/userv in the .deb are 755, not 2755. * Use `command -v' instead of `type' in maintainer scripts. * Do not ignore errors from commands in rules clean target. * Fix FSF address in copyright file. * Remove obsolete local variable section from debian/changelog. * Update Standards-Version. No changes required. -- Ian Jackson Sat, 02 Jun 2012 16:41:09 +0100 userv (1.0.6ubuntu1) lucid; urgency=low * Change tetex-bin with texlive and tetex-extra with texlive-latex-extra in Build-Depends for tetex transition. Cherry-picked from Debian, Thanks to Jari Aalto. -- James Westby Thu, 15 Apr 2010 12:03:52 +0100 userv (1.0.6) unstable; urgency=low Packaging fix: * Create /var/run/userv in the init script as well as shipping it in the .deb package. -- Ian Jackson Wed, 11 Jul 2007 17:54:36 +0100 userv (1.0.5) unstable; urgency=low Bugfixes (thanks to report from Nelson Beebe): * Do not call `assert' on expressions whose side-effects we need (!) Thanks to report from Nelson Beebe. * Correct an erroneous assert() argument so that it would actually detect failure of the assertion. * alarm(2) returns unsigned and can never fail. Packaging changes: * Reran flex (flex Debian 2.5.31-31). * Use install -g 0 instead of -g root. This is more portable, I hope. * Detect missing vsnprintf and mention URL from Nelson Beebe in err msg. * Remove obsolete `buildship' script from top level directory. We use cvs-buildpackage nowadays. -- Ian Jackson Sat, 8 Apr 2006 13:17:14 +0100 userv (1.0.4) unstable; urgency=low Bugfixes: * Close client socket fd in spawned cats (avoids some service-side hangs when client terminates). Thanks to report from Simon Tatham. Minor portability fixes: * Missing #include and } Thanks to report * getgroups returns int, not gid_t (!). } from Peter Benie. * Dummy `check' target in Makefile.in. } Thanks to * Bogus strsignal emulation for broken platforms. } report from * Bogus WCOREDUMP emulation for broken platforms. } Nelson Beebe Packaging improvements (including Debian packaging fixes): * Compress uservd(8) manpage. Closes: #244735. * spec.tex and spec.html are autogenerated: clean and .cvsignore them. * SHELL=/bin/bash in debian/rules; use of install(8). Closes: #263979. * Reran autoconf/autoheader (autoconf Debian 2.13-54). * Updated copyright notices. -- Ian Jackson Fri, 7 Apr 2006 20:04:29 +0100 userv (1.0.3-2) unstable; urgency=low Debian packaging improvements (only): * type -p invoke-rc.d changed to type, in postinst and prerm. -- Ian Jackson Sat, 1 Nov 2003 16:59:38 +0000 userv (1.0.3) unstable; urgency=medium Bugfixes: * Make require-fd work with reading fds ! (Thanks to Ben Harris for the bug report). * Close unwanted pipes in client-side cat subprocesses, to avoid wedging at termination. (Thanks to patchlet from Peter Benie.) * gid_t may be >int, so cast to long when putting in USERV_GIDS (Might conceivably make USERV_GIDS be wrong on some platforms.) * Do not pass char to ctype macros; they can't cope with -ve ! * Fix fd modifier, signal, and exit status parsing to be rigourous in their use of strtoul. (Thanks to report from Peter Benie.) Portability fixes: * #include , not (fixes some implicit decls). * Look for gmd5sum. (Thanks to Anton Altaparmakov for the report.) * install-sh updated to that from autoconf 2.53. * Use fcntl F_{GET,SET}FD with respect for as-yet-uninvented fd flags. (small patch from Ben Harris.) Documentation and help improvements: * userv(1) manpage: fixed broken definitions of fd excl and trunc. (Debian bug report: Closes: #79579.) * Specification's usage notes section improved. * --help and --version behaviour made to conform to GNU standards. * We do ship m4 and flex output now, so say so. * Some groff warnings in userv(1), and source version fixed. * New userv(8) manpage. (Debian: Closes: #33777.) * Update copyright dates everywhere. Debian packaging improvements: * Priority changed to optional as per override file. * Build-Depends: debiandoc-sgml, tetex-bin, tetex-extra. Closes #190615. * init.d reload is noop, restart now called restart. Closes #70783. * /etc/init.d/userv nicer output: colons, `.' printed after done. * Maintainer scripts use invoke-rc.d if it's available. * Maintainer scripts discard stdout from update-rc.d. * No more messing with /usr/doc, use only /usr/share/doc. Closes #91578. * Support unstripped binaries in the .deb, with DEB_BUILD_OPTIONS. * Fixed typo in debian/copyright. * /etc/init.d/userv restart doesn't mind if not already running. * debian/rules clean removes whole spec.html subdirectory. * Ship spec.ps (Closes: #210859) * Lintian override for suid /usr/bin/userv (Closes: #211055) * Standards-Version 3.6.1. * Corrected location of common licenses. * Added -isp to dpkg-gencontrol. (Thanks to Martin Pitt and Bas Zoetekouw's NMUs for many inspirations and one-liners.) -- Ian Jackson Sat, 1 Nov 2003 01:11:59 +0000 userv (1.0.1) stable frozen unstable; urgency=high IMPORTANT SECURITY FIX: * fd swapping algorithm would sometimes corrupt security-critical data used to generate the service program's USERV_ environment variables. For details see the 1.0.1 announcement in the userv-announce archives. Portability improvement: * Look for `md5' as well as `md5sum' - installs easier on BSDs. -- Ian Jackson Thu, 27 Jul 2000 01:06:30 +0100 userv (1.0.0) unstable; urgency=low * Manpage userv(1) from Ben Harris. (Debian bug #33777.) * Released out of beta (version number change). * Added a couple of things to .cvsignore. -- Ian Jackson Mon, 6 Mar 2000 18:13:49 +0000 userv (0.95.0) unstable; urgency=low * Count \-continued lines properly in error message line numbers. * Fix lexing bugs with "-quoted strings and \-continuation. * Fix interpretation of \n etc. in "-quoted strings. * Fix bug which ignored erroneous read/write after ignore-fd/reject-fd. -- Ian Jackson Tue, 9 Nov 1999 23:26:54 +0000 userv (0.65.2) unstable; urgency=high * In client, copy results from getpw* when necessary. This fixes what could be a security problem on some platforms. * Avoid accessing backup, auto-save files, etc, with include-lookup. Everything except a-z 0-9 - _ must now be prefixed by a colon. * Allow \ to continue lines (and do sensible things with whitespace in `message' and `error' directives). -- Ian Jackson Sun, 10 Oct 1999 12:48:47 +0100 userv (0.64.1) unstable; urgency=low * New "shutdown" builtin service for terminating uservd. * Spec. document shows subsections in TOC. * setenv emulation using putenv works properly (previously you would get wrong environment variable settings). (Thanks to Ben Harris.) * Makefile bug fixed (tokens.h would sometimes not be rebuilt). * Regenerated formatted documentation (spec.ps, spec.html). -- Ian Jackson Sun, 20 Jun 1999 19:13:42 +0100 userv (0.62) unstable; urgency=low * New builtin service `help' lists builtin services. INSTALL improvements: * Document locations of required programs. * Sort-of document debugging version. Portability fixes for: * md5sum with extra `-'. * -lsocket required for socket(). * missing `LOG_AUTHPRIV'. * `logname' name clash. * missing setenv() (synthesize using putenv). * various required #include's were omitted. * install rule in Makefile `if ! test ...' changed to `if test ! ...' Build arrangements changed (new GNU coding standards targets etc): * m4 and flex output now shipped. * `dist' target in Makefile. * Manuals in CVS and shipped pre-formatted. * Reran autoconf/autoheader, latest version. * Updated email address to ian@davenant.greenend.org.uk throughout. -- Ian Jackson Sun, 18 Apr 1999 20:08:12 +0100 userv (0.60.3) frozen unstable; urgency=medium * Fixed misdequoting of \ in "-quoted strings. * Removed -Werror by default. (Bug#32758, Bug#32747) -- Ian Jackson Wed, 3 Feb 1999 22:24:33 +0000 userv (0.60.2) frozen unstable; urgency=high * Fixed failure to save pathnames in a couple of places in parser.c. Without this, include-directory would often try to open a garbage filename. This could be a security problem in certain cases where user-owned config files were included from sysadmin-defined files, and the sysadmin wants to control how a user provides services. * Fix "-quoted strings, which previously never worked at all. * Fixed spurious failure with `Interrupted system call' on systems where fread can fail due to read giving EINTR (blech!) * Fixed race when fd closed at startup, which could cause `system call failure: kill cat for : No such process'. * Fixed spurious assertion failure if user's home directory not accessible. * Fixed a couple of memory and fd leaks in error exits from include-directory and include-lookup in parser.c. * Debian and `upstream' version integrated; Changelogs merged. * Provided `system.default' file checks /etc/userv/services.d and /etc/userv/default.d; system.override runs /etc/userv/override.d. * Add to servexec.c. * Add -D_GNU_SOURCE to CFLAGS in configure.in. * Braces added in client.c to prevent GCC `ambiguous else' warning. * Reran autoconf. * autoconf-generated files included in CVS. * Debian package description mentions use by system admin. -- Ian Jackson Sat, 30 Jan 1999 23:38:17 +0000 Old Changelog: *** Main changelog file included here - see far down this file for the *** pre-0.60 Debian-specific changes. userv (0.58); urgency=high * Fixed failure to set gid when invoking service !! * Fixed failure to set fd value in et_closereadfd messages from client. * Save filename string in parse_file for error reporting (in case it is overwritten by parsing code). * Fixed obscure race in process.c:getevent (et_closereadfd and hold fds). * `builtin version' service had error message and errno string reserve values exchanged. -- Ian Jackson Thu, 29 Jan 1998 00:00:22 +0000 userv (0.57); urgency=high * Services provided by root work ! * uservd can now go into background itself (-daemon option). * spec now has default syslog facility for rcfile messages as `user'. * Better prioritisation of syslog messages. * Startup error messages now go to stderr instead. * SIGTERM and SIGINT now produce a syslog message. * Version number has VEREXT component, settable via make args &c. * New sections in INSTALL about exit statuses and -daemon. -- Ian Jackson Tue, 14 Oct 1997 02:04:18 +0100 userv (0.56); urgency=medium * Server now checks itself every hour to see if its socket has been stolen, and exits if it has. * Client only retries connect(2) on EINTR (and does so silently). * All of even master server's syslog messages have pid. * Don't delete spec.sgml.in in clean targets. -- Ian Jackson Sat, 11 Oct 1997 14:38:25 +0100 userv (0.55.2); urgency=low * Added info about WWW page, mailing lists and bug reporting to README. * clean targets except realclean don't remove spec.html, spec.ps, lexer.[lc], tokens.h, overview.ps. New totalclean target for removing configure and config.h.in. * Added and to lexer.l.m4. * instead of ; %d instead of %ld for WEXITSTATUS in overlord.c; PIPEMAXLEN etc. #defines include cast to int to avoid problems with sizeof and size_t; EPROTO missing workaround. * Note about SIG_IGN and `function declaration isn't a prototype' added to INSTALL file in new PROBLEMS section. -- Ian Jackson Sun, 5 Oct 1997 17:55:32 +0100 userv (0.55.1); urgency=low * README file now shipped. * Added this Changelog, and configure gets version number from it. -- Ian Jackson Sun, 21 Sep 1997 23:58:32 +0100 userv (0.55) * Initial release -- Ian Jackson Sun, 21 Sep 1997 23:52:50 +0100 *** Old main changelog file ends here. *** Now come pre-0.59 Debian-specific changes. userv (0.58-1.2) unstable; urgency=low * Non maintainer upload. Fix for this error on the Arm. cc1: warnings being treated as errors client.c: In function callvalueoption': client.c:747: warning: suggest explicit braces to avoid ambiguous else' Braces inserted, to join the if statements together -- Turbo Fredriksson Thu, 20 Aug 1998 06:17:43 -0400 userv (0.58-1.1) frozen unstable; urgency=low * Non maintainer upload * Finally compiled against libc6 * To Brian White: Please either confirm this upload to go into frozen or remove userv from frozen. * Added external declaration for strsignal() to overlord.c and client.c -- Martin Schulze Sat, 18 Jul 1998 10:48:11 +0200 userv (0.58-1) unstable; urgency=low * Upgraded to new upstream version; major security fix, error handling fixes. -- Ian Jackson Thu, 29 Jan 1998 00:03:52 +0000 userv (0.57-1) unstable; urgency=high * Upgraded to new upstream version; fixed bug with root-provided services. * Uses new -daemon option in init.d script. * Sets VEREXT during build to set version number. -- Ian Jackson Tue, 14 Oct 1997 02:22:22 +0100 userv (0.56-1) experimental; urgency=low * Upgraded to new upstream version. -- Ian Jackson Sat, 11 Oct 1997 14:13:22 +0100 userv (0.55.1-1) experimental; urgency=low * Initial Debian release. -- Ian Jackson Mon, 22 Sep 1997 01:08:23 +0100 work/debian/compat0000664000000000000000000000000314163725562011364 0ustar 12 work/debian/control0000664000000000000000000000145714163725562011577 0ustar Source: userv Section: admin Priority: optional Maintainer: Ian Jackson Build-Depends: flex, debiandoc-sgml, transfig, dblatex, texlive-xetex, fonts-dejavu, debhelper (>= 12) Standards-Version: 4.6.0.1 Package: userv Architecture: any Depends: ${shlibs:Depends}, ${misc:Depends}, lsb-base Pre-Depends: ${misc:Pre-Depends} Description: `user services' - program call across trust boundaries userv allows one program to invoke another when only limited trust exists between them. It is a tool which can be used to avoid having to give other system services root privilege, and which allows users to more securely have programs provide services to others. . userv can be useful as `glue' for system administrators; there are not many full-blown userv-using applications yet. work/debian/copyright0000664000000000000000000000265014163725562012123 0ustar This is Debian GNU/Linux's prepackaged version of Ian Jackson's `userv' system utility. This package was put together from the upstream sources by the upstream author. If you have queries please contact Ian Jackson at ; use the Debian bug system for bugs if possible. The changes were to add support for the Debian package maintenance scheme, by adding various debian/* files and arranging for the uservd daemon to be started automatically. userv is Copyright 1996-2021 Ian Jackson . Copyright 2021 Genome Research Limited apropos work by Matthew Vernon Copyright 2000 Ben Harris Copyright 2016-2017 Peter Benie userv 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: A copy of this licence can be found on your Debian system in /usr/share/common-licenses/GPL-3. If not, see . work/debian/lintian-overrides0000664000000000000000000000006214163725562013544 0ustar userv: setuid-binary usr/bin/userv 4755 root/root work/debian/postinst0000664000000000000000000000003514163725562011771 0ustar #!/bin/sh set -e #DEBHELPER# work/debian/postrm0000664000000000000000000000003514163725562011432 0ustar #!/bin/sh set -e #DEBHELPER# work/debian/prerm0000664000000000000000000000003514163725562011233 0ustar #!/bin/sh set -e #DEBHELPER# work/debian/rules0000775000000000000000000000107714163725562011252 0ustar #!/usr/bin/make -f SHELL=/bin/bash package=userv makebuildargs := OPTIMISE= \ XCFLAGS="$(shell dpkg-buildflags --get CFLAGS)" \ XCPPFLAGS="$(shell dpkg-buildflags --get CPPFLAGS)" \ XLDFLAGS="$(shell dpkg-buildflags --get LDFLAGS)" %: dh "$@" override_dh_auto_configure: $(MAKE) -f Makefile.in maintainer-clean ./autogen.sh dh_auto_configure override_dh_auto_build: $(MAKE) $(makebuildargs) all docs override_dh_auto_install: $(MAKE) $(makebuildargs) install install-docs \ DESTDIR=$(CURDIR)/debian/userv override_dh_fixperms: dh_fixperms -X usr/bin/userv work/debian/tests/0000775000000000000000000000000014163725562011327 5ustar work/debian/tests/control0000664000000000000000000000102514163725562012730 0ustar Tests: t-basic Depends: @, bash Tests-Directory: tests Restrictions: isolation-container, allow-stderr, needs-root Tests: t-config Depends: @, bash, chiark-really Tests-Directory: tests Restrictions: isolation-container, allow-stderr, needs-root, breaks-testbed Tests: t-userconfig Depends: @, bash, chiark-really Tests-Directory: tests Restrictions: isolation-container, allow-stderr, needs-root, breaks-testbed Tests: t-persist Depends: @, bash Tests-Directory: tests Restrictions: isolation-container, allow-stderr, needs-root work/debian/userv.docs0000664000000000000000000000000714163725562012200 0ustar README work/debian/userv.init0000664000000000000000000000261114163725562012216 0ustar #!/bin/sh ### BEGIN INIT INFO # Provides: userv # Required-Start: $remote_fs $syslog # Required-Stop: $remote_fs $syslog # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Short-Description: userv services daemon uservd # Description: User services (security boundary) daemon ### END INIT INFO test -f /usr/sbin/uservd || exit 0 . /lib/lsb/init-functions ensure_var_dir () { var_dir=/var/run/userv test -d "$var_dir" || mkdir -m700 "$var_dir" } case "$1" in start) echo -n "Starting user services daemon: uservd" ensure_var_dir start-stop-daemon --start --quiet --exec /usr/sbin/uservd -- -daemon echo "." ;; stop) echo -n "Stopping user services daemon: uservd" start-stop-daemon --stop --quiet --user root --exec /usr/sbin/uservd echo "." ;; restart) echo -n "Restarting user services daemon: uservd" ensure_var_dir start-stop-daemon --stop --oknodo --quiet --user root \ --exec /usr/sbin/uservd sleep 1 start-stop-daemon --start --quiet --exec /usr/sbin/uservd -- -daemon echo "." ;; reload | force-reload) ;; # draft implementation of status support # commented out pending inclusion into policy of firm specification #status) # userv -B version >/dev/null 2>/dev/null # case $? in # 0) echo 'uservd running ok'; exit 0;; # *) echo 'uservd not running'; exit 3;; # esac # ;; *) echo "Usage: /etc/init.d/userv {start|stop|restart|reload|force-reload}" exit 1 esac exit 0 work/debug.c0000664000000000000000000001737414163725562010211 0ustar /* * userv - ddebug.c * routines which are different for -DDEBUG * * userv is copyright Ian Jackson and other contributors. * See README for full authorship information. * * 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; if not, see . */ #include #include #include #include #include #include #include #include #include "config.h" #include "common.h" #include "daemon.h" #include "lib.h" #include "tokens.h" static void fdwantdumprwhead(int *donehead, const char *whichstr, const char *rwstr) { if (*donehead) return; printf("fds %s%s%s:",whichstr,rwstr?" ":"",rwstr?rwstr:""); *donehead= 1; } static void fdwantdumprw(const char *whichstr, int whichval, int rw, const char *rwstr) { int donehead= 0; int fd; for (fd=0; fd\n"); fdwantdump("required",tokv_word_requirefd,"ERROR"); fdwantdump("allowed",tokv_word_allowfd,"either"); fdwantdump("ignored",tokv_word_ignorefd,0); fdwantdump("null",tokv_word_nullfd,"both"); fdwantdump("rejected",tokv_word_rejectfd,0); fputs("execute: ",stdout); switch (execute) { case tokv_word_reject: printf("reject"); break; case tokv_word_execute: printf("`%s'",execpath); break; case tokv_word_executefromdirectory: printf("from directory, `%s'",execpath); break; case tokv_word_executefrompath: printf("from path"); break; case tokv_word_executebuiltin: printf("builtin %s",execpath); break; default: abort(); } if (execargs) { fputs("\n" "no exec arguments\n",stdout); } else { fputs("\n" "exec arguments:",stdout); for (cpp= execargs; cpp; cpp++) printf(" `%s'",*cpp); putchar('\n'); } truefalsedump("set-environment",setenvironment); truefalsedump("suppress-args",suppressargs); truefalsedump("disconnect-hup",disconnecthup); truefalsedump("set-environment",setenvironment); } #ifdef DEBUG static const char *sl_ident= "UNSET"; static int sl_option=0, sl_facility=0; void openlog(const char *ident, int option, int facility) { sl_ident= ident; sl_option= option; sl_facility= facility; } void syslog(int priority, const char *fmt, ...) { va_list al; fprintf(stderr,"syslog: %s<%d.%d>(%d): ",sl_ident,sl_facility,priority,sl_option); va_start(al,fmt); vfprintf(stderr,fmt,al); va_end(al); fputc('\n',stderr); } void closelog(void) { sl_ident= "CLOSED"; sl_option= sl_facility= 0; } static void groupsdump(int ngids, const gid_t *gids, const char *const *groups) { int i; for (i=0; i=nb) return 0; } return 1; } int setgroups(size_t wantsize, const gid_t *wantlist) { /* This is a bit of a hack really. What we want when we're in debug mode is to * have initgroups() be a no-op iff the groups are already set right (so that * we notice if we're trying to change to the wrong user) but to fail if they're * not. * * We can't just call initgroups() because it unconditionally calls * setgroups, which always fails for non-root even if the two group * lists are the same. So here we have a faked-up setgroups which * uses getgroups to see what the group list is and `succeeds' if * the actual group list and the desired one have the same set of * groups, and fails with EPERM if the real setgroups would have * added group(s) or otherwise EINVAL if it would have removed some. * * The usual magic with dynamic linking makes the libc initgroups(3) call * pick up our setgroups() rather than the real setgroups(2). */ int realsize, e; gid_t *reallist; realsize= getgroups(0,0); if (realsize == -1) return -1; reallist= malloc(sizeof(gid_t)*realsize); if (!reallist) return -1; if (getgroups(realsize,reallist) != realsize) { e= errno; free(reallist); errno= e; return -1; } if (!groupsallin(wantsize,wantlist,realsize,reallist)) { free(reallist); errno= EPERM; return -1; } if (!groupsallin(realsize,reallist,wantsize,wantlist)) { free(reallist); errno= EINVAL; return -1; } free(reallist); return 0; } pid_t nondebug_fork(void) { return 0; } const char *nondebug_serviceuserdir(const char *ifnondebug) { return SERVICEUSERDIR; } #else void debug_dumprequest(pid_t mypid) { } void debug_dumpexecsettings(void) { } void debug_dumpparameter(const char *parm, char **values) { } pid_t nondebug_fork(void) { return fork(); } const char *nondebug_serviceuserdir(const char *ifnondebug) { return ifnondebug; } #endif work/install-sh0000775000000000000000000001267114163725562010756 0ustar #!/bin/sh # # install - install a program, script, or datafile # This comes from X11R5 (mit/util/scripts/install.sh). # # Copyright 1991 by the Massachusetts Institute of Technology # # Permission to use, copy, modify, distribute, and sell this software and its # documentation for any purpose is hereby granted without fee, provided that # the above copyright notice appear in all copies and that both that # copyright notice and this permission notice appear in supporting # documentation, and that the name of M.I.T. not be used in advertising or # publicity pertaining to distribution of the software without specific, # written prior permission. M.I.T. makes no representations about the # suitability of this software for any purpose. It is provided "as is" # without express or implied warranty. # # Calling this script install-sh is preferred over install.sh, to prevent # `make' implicit rules from creating a file called install from it # when there is no Makefile. # # This script is compatible with the BSD install script, but was written # from scratch. It can only install one file at a time, a restriction # shared with many OS's install programs. # set DOITPROG to echo to test this script # Don't use :- since 4.3BSD and earlier shells don't like it. doit="${DOITPROG-}" # put in absolute paths if you don't have them in your path; or use env. vars. mvprog="${MVPROG-mv}" cpprog="${CPPROG-cp}" chmodprog="${CHMODPROG-chmod}" chownprog="${CHOWNPROG-chown}" chgrpprog="${CHGRPPROG-chgrp}" stripprog="${STRIPPROG-strip}" rmprog="${RMPROG-rm}" mkdirprog="${MKDIRPROG-mkdir}" transformbasename="" transform_arg="" instcmd="$mvprog" chmodcmd="$chmodprog 0755" chowncmd="" chgrpcmd="" stripcmd="" rmcmd="$rmprog -f" mvcmd="$mvprog" src="" dst="" dir_arg="" while [ x"$1" != x ]; do case $1 in -c) instcmd="$cpprog" shift continue;; -d) dir_arg=true shift continue;; -m) chmodcmd="$chmodprog $2" shift shift continue;; -o) chowncmd="$chownprog $2" shift shift continue;; -g) chgrpcmd="$chgrpprog $2" shift shift continue;; -s) stripcmd="$stripprog" shift continue;; -t=*) transformarg=`echo $1 | sed 's/-t=//'` shift continue;; -b=*) transformbasename=`echo $1 | sed 's/-b=//'` shift continue;; *) if [ x"$src" = x ] then src=$1 else # this colon is to work around a 386BSD /bin/sh bug : dst=$1 fi shift continue;; esac done if [ x"$src" = x ] then echo "install: no input file specified" exit 1 else : fi if [ x"$dir_arg" != x ]; then dst=$src src="" if [ -d $dst ]; then instcmd=: chmodcmd="" else instcmd=$mkdirprog fi else # Waiting for this to be detected by the "$instcmd $src $dsttmp" command # might cause directories to be created, which would be especially bad # if $src (and thus $dsttmp) contains '*'. if [ -f $src -o -d $src ] then : else echo "install: $src does not exist" exit 1 fi if [ x"$dst" = x ] then echo "install: no destination specified" exit 1 else : fi # If destination is a directory, append the input filename; if your system # does not like double slashes in filenames, you may need to add some logic if [ -d $dst ] then dst="$dst"/`basename $src` else : fi fi ## this sed command emulates the dirname command dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'` # Make sure that the destination directory exists. # this part is taken from Noah Friedman's mkinstalldirs script # Skip lots of stat calls in the usual case. if [ ! -d "$dstdir" ]; then defaultIFS=' ' IFS="${IFS-${defaultIFS}}" oIFS="${IFS}" # Some sh's can't handle IFS=/ for some reason. IFS='%' set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'` IFS="${oIFS}" pathcomp='' while [ $# -ne 0 ] ; do pathcomp="${pathcomp}${1}" shift if [ ! -d "${pathcomp}" ] ; then $mkdirprog "${pathcomp}" else : fi pathcomp="${pathcomp}/" done fi if [ x"$dir_arg" != x ] then $doit $instcmd $dst && if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else : ; fi && if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else : ; fi && if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else : ; fi && if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else : ; fi else # If we're going to rename the final executable, determine the name now. if [ x"$transformarg" = x ] then dstfile=`basename $dst` else dstfile=`basename $dst $transformbasename | sed $transformarg`$transformbasename fi # don't allow the sed command to completely eliminate the filename if [ x"$dstfile" = x ] then dstfile=`basename $dst` else : fi # Make a temp file name in the proper directory. dsttmp=$dstdir/#inst.$$# # Move or copy the file name to the temp name $doit $instcmd $src $dsttmp && trap "rm -f ${dsttmp}" 0 && # and set any options; do chmod last to preserve setuid bits # If any of these fail, we abort the whole thing. If we want to # ignore errors from any of these, just make sure not to ignore # errors from the above "$doit $instcmd $src $dsttmp" command. if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else :;fi && if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else :;fi && if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else :;fi && if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else :;fi && # Now rename the file to the real destination. $doit $rmcmd -f $dstdir/$dstfile && $doit $mvcmd $dsttmp $dstdir/$dstfile fi && exit 0 work/language.i40000664000000000000000000002226214163725562010770 0ustar dnl userv - language.i4 dnl definition of the configuration language, used for tokens.h and lexer.l dnl dnl userv is copyright Ian Jackson and other contributors. dnl See README for full authorship information. dnl dnl This is free software; you can redistribute it and/or modify it dnl under the terms of the GNU General Public License as published by dnl the Free Software Foundation; either version 3 of the License, or dnl (at your option) any later version. dnl dnl This program is distributed in the hope that it will be useful, but dnl WITHOUT ANY WARRANTY; without even the implied warranty of dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU dnl General Public License for more details. dnl dnl You should have received a copy of the GNU General Public License dnl along with this program. If not, see . dnl Diversions are dnl 1,2,4: sections of token enum list dnl 3: flex rules divert(-1) define(`makename',`translit(``$1'',`-_')') define(`hasvalistype',`pushdef(`odiv',divnum)dnl divert(1)dnl format(``%-50s'',`toki_$1=')`$2', divert(2)dnl format(``%-30s'',`tokv_$1=')`$3|toki_$1', divert(odiv)popdef(`odiv')') define(`cautotoki',eval(`0x1')) define(`cautotokt',eval(`0x1000')) define(`autovalistype',`hasvalistype(`$1',format(``0x%08x'',cautotoki),`$2')`'define(`cautotoki',incr(cautotoki))') define(`autovaldeftype',`pushdef(`odiv',divnum)divert(4)dnl format(``%-25s'',`tokt_$1=')format(``0x%08x'',cautotokt), divert(odiv)popdef(`odiv')define(`cautotokt',eval(cautotokt`*2'))') define(`nametypelexpatexec',` autovalistype(`$1',`$2') pushdef(`odiv',divnum)divert(3)dnl `$3 { $4'`return tokv_$1; }' divert(odiv)popdef(`odiv')') define(`wordtypelexexec', `nametypelexpatexec(`word_'makename(`$1'),`$2|tokr_word',`$1',`$3')') dnl types autovaldeftype(`directive') autovaldeftype(`controlstart') autovaldeftype(`controlend') autovaldeftype(`exception') autovaldeftype(`parmcondition') autovaldeftype(`condop') autovaldeftype(`parameter') autovaldeftype(`number') autovaldeftype(`fdrange') autovaldeftype(`logfacility') autovaldeftype(`loglevel') autovaldeftype(`readwrite') autovaldeftype(`string') autovaldeftype(`execmode') autovaldeftype(`ehandlemode') autovaldeftype(`lookupquotemode') autovaldeftype(`builtinservice') autovaldeftype(`misc') autovaldeftype(`internal') dnl simple isdirectives define(`isdirectivefn',`dnl wordtypelexexec(`$1',`tokt_directive$3',`lr_dir= $2; $4')dnl pushdef(`odiv',divnum) divert(odiv)popdef(`odiv')') define(`isdirective',`isdirectivefn(`$1',`df_'makename(`$1'),`$2')') define(`isdirectiveinternal',`isdirectivefn(`$1',`dfi_'makename(`$1'), `|tokt_internal$2')') define(`isexecmode',`isdirective(`$1',`|tokt_execmode')') define(`isehandlemode',`isdirective(`$1',`|tokt_ehandlemode')') define(`islookupquotemode',`isdirectivefn(`$1',`dfg_lookupquotemode', `|tokt_lookupquotemode')') define(`isfdwant',`isdirectivefn(`$1',`dfg_fdwant',`', `lr_fdwant_readwrite=$2; ')') define(`isflagpair',`isdirectivefn(`$1',`dfg_setflag',`', `lr_flag= &'makename(`$1')`; lr_flagval= 1; ') isdirectivefn(`no-$1',`dfg_setflag',`', `lr_flag= &'makename(`$1')`; lr_flagval= 0; ')') dnl `reset' is also a builtin service isexecmode(`reject') dnl `execute' is also a builtin service isexecmode(`execute-from-directory') isexecmode(`execute-from-path') isexecmode(`execute-builtin') isehandlemode(`errors-to-stderr') isehandlemode(`errors-to-syslog') isehandlemode(`errors-to-file') islookupquotemode(`include-lookup-quote-old') islookupquotemode(`include-lookup-quote-new') isfdwant(`require-fd',`1') isfdwant(`allow-fd',`0') isfdwant(`null-fd',`0') isfdwant(`reject-fd',`-1') isfdwant(`ignore-fd',`-1') isflagpair(`set-environment') isflagpair(`suppress-args') isflagpair(`disconnect-hup') isdirective(`cd') isdirective(`user-rcfile') isdirective(`include') isdirectivefn(`include-ifexist',`df_include') isdirective(`include-lookup') isdirectivefn(`include-lookup-all',`df_includelookup') isdirective(`include-directory') isdirective(`message') isdirectivefn(`_include-sysconfig',`df_include',`|tokt_internal') isdirectiveinternal(`_include-user-rcfile') isdirectiveinternal(`_include-client-config') dnl quit and eof are each a directive _and_ an exception dnl as separate tokens. A true end of file is returned by yylex dnl as the exception. The directive (word) tokens are dnl tokv_word_{eof,quit}; the exceptions are tokv_{eof,quit}. isdirective(`quit') isdirective(`eof') dnl control construct starters define(`iscontrolstart', `isdirective(`$1',`|tokt_controlstart')') iscontrolstart(`if') iscontrolstart(`catch-quit') iscontrolstart(`errors-push') dnl control construct enders define(`iscontrolend', `wordtypelexexec(`$1',`tokt_controlend$3', `lr_controlend= tokv_word_'makename(`$2')`; ')') iscontrolend(`elif', `if', `|tokt_controlstart') iscontrolend(`else', `if', `|tokt_controlstart') iscontrolend(`fi', `if') iscontrolend(`hctac', `catch-quit') iscontrolend(`srorre', `errors-push') dnl conditions define(`isparmcondition',`wordtypelexexec(`$1',`tokt_parmcondition', `lr_parmcond= pcf_'makename(`$1')`; ')') isparmcondition(`glob') isparmcondition(`range') isparmcondition(`grep') define(`builtininlist',` pushdef(`odiv',divnum)divert(5)dnl `"$1$2"', divert(odiv)popdef(`odiv')') dnl builtin services define(`isbuiltinservice', `wordtypelexexec(`$1',`tokt_builtinservice$3', `lr_bispa= bispa_'makename(`$2')`; lr_bisexec= bisexec_'makename(`$1')`; $5') builtininlist(`$1',`$4')') isbuiltinservice(`environment',`none') isbuiltinservice(`parameter',`parameter',`',` ') isbuiltinservice(`version',`none') isbuiltinservice(`toplevel',`none') isbuiltinservice(`override',`none') isbuiltinservice(`shutdown',`none') dnl builtin services that are also directive names define(`isdirectivebuiltinservice', `isbuiltinservice(`$1',`$2',`|tokt_directive$3',`$4', `lr_dir= df_'makename(`$1')`; ')') isdirectivebuiltinservice(`reset',`none') isdirectivebuiltinservice(`execute',`none',`|tokt_execmode') isbuiltinservice(`help',`none') dnl parameters define(`isparameter',`wordtypelexexec(`$1',`tokt_parameter', `lr_parameter= pf_'makename(`$1')`; ')') isparameter(`service') isparameter(`calling-user') isparameter(`calling-group') isparameter(`calling-user-shell') isparameter(`service-user') isparameter(`service-group') isparameter(`service-user-shell') dnl syslog levels define(`isloglevellexpat', `nametypelexpatexec(`syslog_$1',`tokt_loglevel|tokr_word',`$2', `lr_loglevel= LOG_'translit(``$1'',`a-z',`A-Z')`; ')') define(`isloglevel',`isloglevellexpat(`$1',`$1')') isloglevel(`debug') isloglevel(`info') isloglevel(`notice') isloglevellexpat(`warning',`warn(ing)?') isloglevel(`err')dnl also the word error, which has dual meaning (below) isloglevel(`crit') isloglevel(`alert') isloglevellexpat(`emerg',`emerg|panic') dnl syslog facilities define(`islogfacilitylexpat', `nametypelexpatexec(`syslog_$1',`tokt_logfacility|tokr_word',`$2', `lr_logfacility= LOG_'translit(``$1'',`a-z',`A-Z')`; ')') define(`islogfacility',`islogfacilitylexpat(`$1',`$1')') islogfacilitylexpat(`authpriv',`auth(priv)?|security') islogfacility(`cron') islogfacility(`daemon') islogfacilitylexpat(`kern',`kern(el)?') islogfacility(`lpr') islogfacility(`mail') islogfacility(`news') islogfacility(`syslog') islogfacility(`user') islogfacility(`uucp') islogfacility(`local0') islogfacility(`local1') islogfacility(`local2') islogfacility(`local3') islogfacility(`local4') islogfacility(`local5') islogfacility(`local6') islogfacility(`local7') dnl misc. word-like things wordtypelexexec(`read',`tokt_readwrite',`') wordtypelexexec(`write',`tokt_readwrite',`') dnl small nonnegative integers and fd ranges dnl some of these have two tokt_ bits set, because they can be several things. autovalistype(`ordinal', `tokt_number|tokt_fdrange|tokr_word') autovalistype(`fdrange', `tokt_fdrange|tokr_punct') autovalistype(`fdstoend', `tokt_fdrange|tokr_punct') nametypelexpatexec(`dollar',`tokt_misc|tokr_punct',`\$',`') define(singlefd,` wordtypelexexec(`$1',`tokt_fdrange',` lr_max= lr_min= $2; ')') singlefd(`stdin',`0'); singlefd(`stdout',`1'); singlefd(`stderr',`2'); dnl non-word things autovalistype(`lwsp', `tokt_misc|tokr_nonstring') autovalistype(`newline', `tokt_misc|tokr_nonstring') autovalistype(`barestring', `tokt_string|tokr_string') autovalistype(`quotedstring', `tokt_string|tokr_string') dnl exceptions - NB that there are also tokv_word_{eof,quit} dnl - see above, near the directives. autovalistype(`eof', `tokt_exception|tokr_nonstring') autovalistype(`quit', `tokt_exception|tokr_nonstring') autovalistype(`error', `tokt_exception|tokr_nonstring') define(`iscondop',`nametypelexpatexec(`$2',`tokt_condop|tokr_punct',`$1',`')') iscondop(`\(',`openparen') iscondop(`\)',`closeparen') iscondop(`\!',`not') iscondop(`\&',`and') iscondop(`\|',`or') dnl words that could be two things wordtypelexexec(`error',`tokt_directive|tokt_loglevel', `lr_dir= df_error; lr_loglevel= LOG_ERR; ') divert work/lexer.c0000664000000000000000000024345514163725562010243 0ustar #line 3 "" #define YY_INT_ALIGNED short int /* A lexical scanner generated by flex */ #define FLEX_SCANNER #define YY_FLEX_MAJOR_VERSION 2 #define YY_FLEX_MINOR_VERSION 6 #define YY_FLEX_SUBMINOR_VERSION 4 #if YY_FLEX_SUBMINOR_VERSION > 0 #define FLEX_BETA #endif /* First, we deal with platform-specific or compiler-specific issues. */ /* begin standard C headers. */ #include #include #include #include /* end standard C headers. */ /* flex integer type definitions */ #ifndef FLEXINT_H #define FLEXINT_H /* C99 systems have . Non-C99 systems may or may not. */ #if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* C99 says to define __STDC_LIMIT_MACROS before including stdint.h, * if you want the limit (max/min) macros for int types. */ #ifndef __STDC_LIMIT_MACROS #define __STDC_LIMIT_MACROS 1 #endif #include typedef int8_t flex_int8_t; typedef uint8_t flex_uint8_t; typedef int16_t flex_int16_t; typedef uint16_t flex_uint16_t; typedef int32_t flex_int32_t; typedef uint32_t flex_uint32_t; #else typedef signed char flex_int8_t; typedef short int flex_int16_t; typedef int flex_int32_t; typedef unsigned char flex_uint8_t; typedef unsigned short int flex_uint16_t; typedef unsigned int flex_uint32_t; /* Limits of integral types. */ #ifndef INT8_MIN #define INT8_MIN (-128) #endif #ifndef INT16_MIN #define INT16_MIN (-32767-1) #endif #ifndef INT32_MIN #define INT32_MIN (-2147483647-1) #endif #ifndef INT8_MAX #define INT8_MAX (127) #endif #ifndef INT16_MAX #define INT16_MAX (32767) #endif #ifndef INT32_MAX #define INT32_MAX (2147483647) #endif #ifndef UINT8_MAX #define UINT8_MAX (255U) #endif #ifndef UINT16_MAX #define UINT16_MAX (65535U) #endif #ifndef UINT32_MAX #define UINT32_MAX (4294967295U) #endif #ifndef SIZE_MAX #define SIZE_MAX (~(size_t)0) #endif #endif /* ! C99 */ #endif /* ! FLEXINT_H */ /* begin standard C++ headers. */ /* TODO: this is always defined, so inline it */ #define yyconst const #if defined(__GNUC__) && __GNUC__ >= 3 #define yynoreturn __attribute__((__noreturn__)) #else #define yynoreturn #endif /* Returned upon end-of-file. */ #define YY_NULL 0 /* Promotes a possibly negative, possibly signed char to an * integer in range [0..255] for use as an array index. */ #define YY_SC_TO_UI(c) ((YY_CHAR) (c)) /* Enter a start condition. This macro really ought to take a parameter, * but we do it the disgusting crufty way forced on us by the ()-less * definition of BEGIN. */ #define BEGIN (yy_start) = 1 + 2 * /* Translate the current start state into a value that can be later handed * to BEGIN to return to the state. The YYSTATE alias is for lex * compatibility. */ #define YY_START (((yy_start) - 1) / 2) #define YYSTATE YY_START /* Action number for EOF rule of a given start state. */ #define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1) /* Special action meaning "start processing a new file". */ #define YY_NEW_FILE yyrestart( yyin ) #define YY_END_OF_BUFFER_CHAR 0 /* Size of default input buffer. */ #ifndef YY_BUF_SIZE #ifdef __ia64__ /* On IA-64, the buffer size is 16k, not 8k. * Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case. * Ditto for the __ia64__ case accordingly. */ #define YY_BUF_SIZE 32768 #else #define YY_BUF_SIZE 16384 #endif /* __ia64__ */ #endif /* The state buf must be large enough to hold one state per character in the main buffer. */ #define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type)) #ifndef YY_TYPEDEF_YY_BUFFER_STATE #define YY_TYPEDEF_YY_BUFFER_STATE typedef struct yy_buffer_state *YY_BUFFER_STATE; #endif #ifndef YY_TYPEDEF_YY_SIZE_T #define YY_TYPEDEF_YY_SIZE_T typedef size_t yy_size_t; #endif extern int yyleng; extern FILE *yyin, *yyout; #define EOB_ACT_CONTINUE_SCAN 0 #define EOB_ACT_END_OF_FILE 1 #define EOB_ACT_LAST_MATCH 2 #define YY_LESS_LINENO(n) #define YY_LINENO_REWIND_TO(ptr) /* Return all but the first "n" matched characters back to the input stream. */ #define yyless(n) \ do \ { \ /* Undo effects of setting up yytext. */ \ int yyless_macro_arg = (n); \ YY_LESS_LINENO(yyless_macro_arg);\ *yy_cp = (yy_hold_char); \ YY_RESTORE_YY_MORE_OFFSET \ (yy_c_buf_p) = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \ YY_DO_BEFORE_ACTION; /* set up yytext again */ \ } \ while ( 0 ) #define unput(c) yyunput( c, (yytext_ptr) ) #ifndef YY_STRUCT_YY_BUFFER_STATE #define YY_STRUCT_YY_BUFFER_STATE struct yy_buffer_state { FILE *yy_input_file; char *yy_ch_buf; /* input buffer */ char *yy_buf_pos; /* current position in input buffer */ /* Size of input buffer in bytes, not including room for EOB * characters. */ int yy_buf_size; /* Number of characters read into yy_ch_buf, not including EOB * characters. */ int yy_n_chars; /* Whether we "own" the buffer - i.e., we know we created it, * and can realloc() it to grow it, and should free() it to * delete it. */ int yy_is_our_buffer; /* Whether this is an "interactive" input source; if so, and * if we're using stdio for input, then we want to use getc() * instead of fread(), to make sure we stop fetching input after * each newline. */ int yy_is_interactive; /* Whether we're considered to be at the beginning of a line. * If so, '^' rules will be active on the next match, otherwise * not. */ int yy_at_bol; int yy_bs_lineno; /**< The line count. */ int yy_bs_column; /**< The column count. */ /* Whether to try to fill the input buffer when we reach the * end of it. */ int yy_fill_buffer; int yy_buffer_status; #define YY_BUFFER_NEW 0 #define YY_BUFFER_NORMAL 1 /* When an EOF's been seen but there's still some text to process * then we mark the buffer as YY_EOF_PENDING, to indicate that we * shouldn't try reading from the input source any more. We might * still have a bunch of tokens to match, though, because of * possible backing-up. * * When we actually see the EOF, we change the status to "new" * (via yyrestart()), so that the user can continue scanning by * just pointing yyin at a new input file. */ #define YY_BUFFER_EOF_PENDING 2 }; #endif /* !YY_STRUCT_YY_BUFFER_STATE */ /* Stack of input buffers. */ static size_t yy_buffer_stack_top = 0; /**< index of top of stack. */ static size_t yy_buffer_stack_max = 0; /**< capacity of stack. */ static YY_BUFFER_STATE * yy_buffer_stack = NULL; /**< Stack as an array. */ /* We provide macros for accessing buffer states in case in the * future we want to put the buffer states in a more general * "scanner state". * * Returns the top of the stack, or NULL. */ #define YY_CURRENT_BUFFER ( (yy_buffer_stack) \ ? (yy_buffer_stack)[(yy_buffer_stack_top)] \ : NULL) /* Same as previous macro, but useful when we know that the buffer stack is not * NULL or when we need an lvalue. For internal use only. */ #define YY_CURRENT_BUFFER_LVALUE (yy_buffer_stack)[(yy_buffer_stack_top)] /* yy_hold_char holds the character lost when yytext is formed. */ static char yy_hold_char; static int yy_n_chars; /* number of characters read into yy_ch_buf */ int yyleng; /* Points to current character in buffer. */ static char *yy_c_buf_p = NULL; static int yy_init = 0; /* whether we need to initialize */ static int yy_start = 0; /* start state number */ /* Flag which is used to allow yywrap()'s to do buffer switches * instead of setting up a fresh yyin. A bit of a hack ... */ static int yy_did_buffer_switch_on_eof; void yyrestart ( FILE *input_file ); void yy_switch_to_buffer ( YY_BUFFER_STATE new_buffer ); YY_BUFFER_STATE yy_create_buffer ( FILE *file, int size ); void yy_delete_buffer ( YY_BUFFER_STATE b ); void yy_flush_buffer ( YY_BUFFER_STATE b ); void yypush_buffer_state ( YY_BUFFER_STATE new_buffer ); void yypop_buffer_state ( void ); static void yyensure_buffer_stack ( void ); static void yy_load_buffer_state ( void ); static void yy_init_buffer ( YY_BUFFER_STATE b, FILE *file ); #define YY_FLUSH_BUFFER yy_flush_buffer( YY_CURRENT_BUFFER ) YY_BUFFER_STATE yy_scan_buffer ( char *base, yy_size_t size ); YY_BUFFER_STATE yy_scan_string ( const char *yy_str ); YY_BUFFER_STATE yy_scan_bytes ( const char *bytes, int len ); void *yyalloc ( yy_size_t ); void *yyrealloc ( void *, yy_size_t ); void yyfree ( void * ); #define yy_new_buffer yy_create_buffer #define yy_set_interactive(is_interactive) \ { \ if ( ! YY_CURRENT_BUFFER ){ \ yyensure_buffer_stack (); \ YY_CURRENT_BUFFER_LVALUE = \ yy_create_buffer( yyin, YY_BUF_SIZE ); \ } \ YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \ } #define yy_set_bol(at_bol) \ { \ if ( ! YY_CURRENT_BUFFER ){\ yyensure_buffer_stack (); \ YY_CURRENT_BUFFER_LVALUE = \ yy_create_buffer( yyin, YY_BUF_SIZE ); \ } \ YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \ } #define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol) /* Begin user sect3 */ #define yywrap() (/*CONSTCOND*/1) #define YY_SKIP_YYWRAP typedef flex_uint8_t YY_CHAR; FILE *yyin = NULL, *yyout = NULL; typedef int yy_state_type; extern int yylineno; int yylineno = 1; extern char *yytext; #ifdef yytext_ptr #undef yytext_ptr #endif #define yytext_ptr yytext static yy_state_type yy_get_previous_state ( void ); static yy_state_type yy_try_NUL_trans ( yy_state_type current_state ); static int yy_get_next_buffer ( void ); static void yynoreturn yy_fatal_error ( const char* msg ); /* Done after the current pattern has been matched and before the * corresponding action - sets up yytext. */ #define YY_DO_BEFORE_ACTION \ (yytext_ptr) = yy_bp; \ yyleng = (int) (yy_cp - yy_bp); \ (yy_hold_char) = *yy_cp; \ *yy_cp = '\0'; \ (yy_c_buf_p) = yy_cp; #define YY_NUM_RULES 112 #define YY_END_OF_BUFFER 113 /* This struct is not used in this scanner, but its presence is necessary. */ struct yy_trans_info { flex_int32_t yy_verify; flex_int32_t yy_nxt; }; static const flex_int16_t yy_accept[587] = { 0, 0, 0, 113, 108, 103, 104, 95, 109, 106, 89, 96, 93, 94, 99, 110, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 97, 108, 103, 104, 106, 0, 0, 107, 0, 106, 106, 105, 101, 99, 0, 102, 108, 108, 108, 108, 21, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 39, 108, 108, 108, 108, 34, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 0, 0, 0, 100, 99, 102, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 33, 65, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 73, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 0, 0, 100, 99, 108, 108, 108, 69, 108, 108, 66, 70, 108, 108, 108, 37, 38, 108, 108, 108, 108, 42, 44, 108, 53, 108, 108, 62, 72, 108, 74, 108, 75, 108, 108, 108, 108, 108, 108, 108, 32, 108, 87, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 77, 78, 108, 64, 108, 0, 100, 99, 108, 67, 108, 108, 108, 108, 108, 61, 108, 68, 108, 98, 108, 40, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 43, 108, 108, 51, 108, 108, 108, 108, 108, 108, 90, 108, 108, 108, 108, 108, 108, 108, 88, 100, 99, 108, 108, 108, 108, 108, 71, 108, 108, 108, 108, 108, 108, 72, 79, 80, 81, 82, 83, 84, 85, 86, 108, 108, 108, 108, 63, 108, 108, 108, 1, 108, 108, 108, 108, 108, 41, 92, 91, 108, 76, 108, 108, 108, 108, 100, 99, 108, 108, 108, 108, 108, 108, 108, 108, 52, 108, 23, 28, 108, 108, 108, 12, 108, 108, 108, 108, 108, 54, 108, 108, 108, 108, 108, 47, 64, 100, 99, 108, 11, 69, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 49, 108, 108, 108, 108, 108, 50, 108, 48, 108, 100, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 14, 108, 108, 108, 108, 108, 108, 46, 13, 108, 108, 108, 108, 108, 108, 100, 108, 108, 108, 108, 108, 35, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 10, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 45, 36, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 22, 108, 108, 108, 108, 55, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 58, 108, 108, 108, 108, 108, 56, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 59, 108, 108, 17, 108, 108, 108, 108, 19, 7, 108, 108, 108, 108, 108, 108, 108, 25, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 4, 108, 108, 108, 24, 108, 108, 108, 108, 108, 15, 108, 108, 108, 108, 5, 6, 108, 108, 108, 108, 108, 108, 108, 18, 108, 108, 108, 108, 108, 108, 3, 27, 108, 108, 20, 108, 108, 108, 29, 108, 57, 108, 26, 108, 16, 60, 108, 108, 108, 108, 108, 30, 108, 108, 108, 108, 108, 31, 2, 108, 108, 108, 108, 9, 8, 0 } ; static const YY_CHAR yy_ec[256] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 4, 5, 6, 7, 8, 9, 8, 10, 11, 8, 8, 8, 12, 8, 8, 13, 14, 15, 16, 17, 18, 19, 20, 21, 21, 8, 8, 8, 8, 8, 8, 8, 22, 22, 22, 22, 22, 22, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 8, 23, 8, 8, 24, 8, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 8, 51, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 } ; static const YY_CHAR yy_meta[52] = { 0, 1, 2, 3, 1, 2, 1, 1, 1, 1, 1, 1, 1, 4, 4, 4, 4, 4, 4, 4, 4, 4, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 } ; static const flex_int16_t yy_base[593] = { 0, 0, 0, 801, 0, 50, 802, 0, 49, 55, 0, 0, 0, 0, 67, 59, 767, 19, 49, 34, 56, 766, 29, 39, 59, 769, 30, 71, 70, 751, 771, 750, 76, 74, 755, 65, 764, 82, 0, 0, 111, 802, 789, 73, 97, 802, 134, 123, 788, 802, 170, 179, 109, 119, 752, 93, 745, 94, 0, 94, 759, 761, 743, 98, 756, 738, 753, 740, 752, 0, 741, 750, 734, 741, 0, 738, 113, 733, 747, 731, 739, 728, 723, 120, 733, 739, 119, 734, 728, 133, 118, 720, 725, 735, 722, 718, 720, 730, 731, 715, 714, 722, 163, 0, 196, 214, 223, 157, 727, 711, 713, 719, 714, 722, 704, 709, 709, 700, 717, 713, 713, 699, 707, 0, 700, 711, 711, 696, 710, 694, 694, 696, 692, 692, 704, 0, 692, 684, 683, 135, 692, 688, 681, 689, 696, 676, 688, 690, 688, 671, 686, 669, 667, 700, 667, 668, 140, 669, 672, 671, 664, 665, 661, 665, 658, 0, 232, 250, 259, 665, 656, 652, 658, 664, 664, 0, 0, 656, 663, 654, 0, 0, 661, 649, 648, 644, 0, 0, 661, 0, 645, 641, 0, 656, 648, 0, 658, 0, 649, 175, 654, 668, 637, 651, 640, 0, 647, 0, 648, 641, 629, 630, 638, 641, 641, 626, 625, 628, 620, 622, 624, 633, 649, 0, 627, 626, 629, 276, 287, 296, 612, 0, 644, 613, 616, 641, 614, 0, 613, 0, 611, 606, 604, 0, 618, 618, 609, 305, 613, 600, 598, 601, 611, 609, 605, 608, 0, 592, 593, 0, 601, 606, 594, 592, 601, 587, 0, 584, 598, 595, 579, 582, 584, 584, 0, 313, 322, 593, 590, 586, 587, 576, 0, 578, 577, 602, 584, 600, 582, 0, 0, 0, 0, 0, 0, 0, 0, 0, 581, 582, 596, 567, 0, 578, 577, 560, 591, 573, 557, 571, 553, 551, 0, 0, 0, 554, 0, 567, 568, 556, 562, 331, 340, 563, 563, 544, 577, 543, 558, 549, 128, 573, 554, 571, 0, 543, 552, 538, 0, 550, 549, 547, 564, 526, 562, 540, 534, 528, 534, 539, 0, 0, 349, 556, 555, 0, 0, 251, 533, 538, 535, 518, 523, 145, 533, 255, 522, 521, 529, 0, 515, 528, 525, 253, 512, 0, 541, 0, 519, 358, 353, 509, 507, 505, 504, 509, 503, 533, 499, 501, 0, 509, 511, 501, 501, 492, 494, 0, 0, 508, 493, 491, 494, 507, 495, 0, 494, 480, 485, 488, 497, 0, 513, 480, 491, 351, 489, 482, 478, 490, 479, 488, 483, 472, 0, 475, 484, 474, 469, 481, 476, 465, 478, 461, 463, 472, 0, 0, 470, 95, 466, 464, 471, 451, 463, 470, 454, 483, 449, 451, 455, 460, 0, 461, 462, 446, 447, 474, 440, 448, 455, 439, 437, 468, 452, 445, 432, 432, 436, 449, 433, 460, 442, 427, 431, 429, 455, 0, 423, 425, 435, 434, 426, 428, 257, 416, 416, 418, 445, 418, 413, 0, 411, 415, 0, 408, 413, 408, 417, 0, 0, 406, 408, 408, 412, 419, 404, 398, 429, 408, 402, 407, 405, 392, 423, 404, 406, 403, 389, 399, 0, 387, 384, 385, 0, 358, 381, 396, 381, 394, 0, 395, 388, 390, 383, 0, 0, 389, 385, 367, 370, 357, 361, 359, 0, 359, 354, 361, 358, 354, 362, 0, 0, 352, 348, 0, 342, 349, 346, 0, 346, 0, 251, 0, 250, 0, 0, 263, 263, 251, 260, 254, 0, 244, 244, 224, 159, 164, 0, 0, 178, 170, 158, 153, 0, 0, 802, 399, 403, 407, 411, 173, 166 } ; static const flex_int16_t yy_def[593] = { 0, 586, 1, 586, 587, 586, 586, 587, 588, 589, 587, 587, 587, 587, 587, 586, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 586, 586, 590, 586, 588, 586, 588, 589, 590, 586, 587, 14, 586, 586, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 586, 591, 588, 587, 14, 586, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 592, 104, 587, 14, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 588, 587, 14, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 14, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 14, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 0, 586, 586, 586, 586, 586, 586 } ; static const flex_int16_t yy_nxt[854] = { 0, 4, 5, 6, 7, 8, 9, 10, 4, 11, 12, 13, 4, 14, 14, 14, 14, 14, 14, 14, 14, 14, 4, 15, 16, 17, 4, 18, 19, 20, 21, 22, 23, 24, 4, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 4, 4, 4, 38, 40, 41, 45, 55, 42, 48, 49, 60, 48, 52, 53, 61, 56, 70, 72, 62, 73, 78, 79, 71, 46, 43, 57, 52, 53, 58, 48, 50, 51, 51, 51, 51, 51, 51, 51, 51, 51, 74, 75, 59, 63, 64, 65, 66, 80, 76, 67, 82, 81, 88, 45, 90, 68, 89, 91, 100, 97, 83, 98, 52, 53, 40, 41, 84, 92, 42, 93, 94, 46, 107, 109, 95, 101, 48, 49, 114, 48, 110, 112, 119, 139, 115, 43, 586, 102, 44, 113, 460, 131, 120, 43, 132, 461, 151, 48, 103, 103, 103, 103, 103, 103, 103, 103, 103, 586, 143, 147, 107, 152, 144, 153, 198, 140, 102, 44, 148, 361, 216, 44, 388, 362, 217, 149, 389, 150, 165, 199, 218, 43, 585, 104, 105, 105, 105, 105, 105, 105, 105, 105, 105, 106, 106, 106, 106, 106, 106, 106, 106, 106, 45, 580, 581, 250, 584, 583, 582, 579, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 46, 251, 166, 166, 166, 166, 166, 166, 167, 167, 167, 167, 167, 167, 167, 167, 167, 168, 168, 168, 168, 168, 168, 168, 168, 168, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 578, 577, 227, 227, 227, 227, 227, 227, 228, 228, 228, 228, 228, 228, 228, 228, 228, 229, 229, 229, 229, 229, 229, 229, 229, 229, 45, 381, 391, 400, 504, 576, 575, 392, 574, 573, 393, 572, 571, 570, 569, 382, 505, 401, 46, 275, 275, 275, 275, 275, 275, 275, 275, 275, 276, 276, 276, 276, 276, 276, 276, 276, 276, 290, 291, 292, 293, 294, 295, 296, 297, 321, 321, 321, 321, 321, 321, 321, 321, 321, 322, 322, 322, 322, 322, 322, 322, 322, 322, 352, 352, 352, 352, 352, 352, 352, 352, 352, 353, 353, 353, 353, 353, 353, 353, 353, 353, 379, 379, 379, 379, 379, 379, 379, 379, 379, 405, 405, 405, 405, 405, 405, 405, 405, 405, 406, 438, 568, 540, 567, 566, 565, 564, 563, 562, 561, 560, 559, 558, 439, 557, 407, 556, 408, 541, 39, 555, 554, 39, 44, 44, 553, 44, 47, 47, 47, 47, 48, 48, 48, 48, 552, 551, 550, 549, 548, 547, 546, 545, 544, 543, 542, 539, 538, 537, 536, 535, 534, 533, 532, 531, 530, 529, 528, 527, 526, 525, 524, 523, 522, 521, 520, 519, 518, 517, 516, 515, 514, 513, 512, 511, 510, 509, 508, 507, 506, 503, 502, 501, 500, 499, 498, 497, 496, 495, 494, 493, 492, 491, 490, 489, 488, 487, 486, 485, 484, 483, 482, 481, 480, 479, 478, 477, 476, 475, 474, 473, 472, 471, 470, 469, 468, 467, 466, 465, 464, 463, 462, 459, 458, 457, 456, 455, 454, 453, 452, 451, 450, 449, 448, 447, 446, 445, 444, 443, 442, 441, 440, 437, 436, 435, 434, 433, 432, 431, 430, 429, 428, 427, 426, 425, 424, 423, 422, 421, 420, 419, 418, 417, 416, 415, 414, 413, 412, 411, 410, 409, 404, 403, 402, 399, 398, 397, 396, 395, 394, 390, 387, 386, 385, 384, 383, 380, 50, 378, 377, 376, 375, 374, 373, 356, 372, 371, 370, 369, 368, 367, 366, 365, 364, 363, 360, 359, 358, 357, 356, 355, 354, 351, 350, 349, 348, 347, 346, 345, 344, 343, 342, 341, 340, 339, 338, 337, 336, 335, 334, 333, 332, 331, 330, 329, 328, 327, 326, 325, 324, 323, 320, 319, 318, 317, 316, 315, 314, 313, 312, 311, 310, 309, 308, 307, 306, 305, 304, 303, 302, 301, 300, 299, 298, 289, 288, 287, 286, 285, 284, 283, 282, 281, 280, 279, 278, 277, 274, 273, 272, 271, 270, 269, 268, 267, 266, 265, 264, 263, 262, 261, 260, 259, 258, 257, 256, 255, 239, 254, 253, 252, 249, 248, 247, 246, 245, 244, 243, 242, 241, 240, 239, 238, 237, 236, 235, 234, 233, 232, 231, 230, 226, 225, 224, 223, 222, 221, 220, 219, 215, 214, 213, 212, 211, 210, 209, 208, 207, 206, 205, 204, 203, 202, 201, 200, 197, 196, 195, 194, 193, 192, 191, 190, 189, 188, 187, 186, 185, 184, 183, 182, 181, 180, 179, 178, 177, 176, 175, 174, 173, 172, 171, 170, 169, 164, 163, 162, 161, 160, 159, 158, 157, 156, 155, 154, 146, 145, 142, 141, 138, 137, 136, 135, 134, 133, 130, 129, 128, 127, 126, 125, 124, 123, 122, 121, 118, 117, 116, 111, 108, 49, 49, 99, 96, 87, 86, 85, 77, 69, 54, 586, 3, 586, 586, 586, 586, 586, 586, 586, 586, 586, 586, 586, 586, 586, 586, 586, 586, 586, 586, 586, 586, 586, 586, 586, 586, 586, 586, 586, 586, 586, 586, 586, 586, 586, 586, 586, 586, 586, 586, 586, 586, 586, 586, 586, 586, 586, 586, 586, 586, 586, 586, 586 } ; static const flex_int16_t yy_chk[854] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 5, 8, 17, 5, 9, 9, 19, 9, 15, 15, 19, 17, 22, 23, 19, 23, 26, 26, 22, 8, 5, 18, 43, 43, 18, 9, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 24, 24, 18, 20, 20, 20, 20, 27, 24, 20, 28, 27, 32, 44, 33, 20, 32, 33, 37, 35, 28, 35, 52, 52, 40, 40, 28, 33, 40, 33, 33, 44, 53, 55, 33, 37, 47, 47, 59, 47, 55, 57, 63, 83, 59, 40, 46, 46, 46, 57, 439, 76, 63, 53, 76, 439, 90, 47, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 86, 89, 107, 90, 86, 90, 139, 83, 102, 102, 89, 330, 156, 592, 363, 330, 156, 89, 363, 89, 591, 139, 156, 107, 583, 46, 50, 50, 50, 50, 50, 50, 50, 50, 50, 51, 51, 51, 51, 51, 51, 51, 51, 51, 104, 577, 577, 199, 582, 581, 580, 576, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 199, 104, 104, 104, 104, 104, 104, 105, 105, 105, 105, 105, 105, 105, 105, 105, 106, 106, 106, 106, 106, 106, 106, 106, 106, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 575, 574, 166, 166, 166, 166, 166, 166, 167, 167, 167, 167, 167, 167, 167, 167, 167, 168, 168, 168, 168, 168, 168, 168, 168, 168, 227, 357, 365, 373, 484, 573, 571, 365, 570, 569, 365, 568, 567, 564, 562, 357, 484, 373, 227, 228, 228, 228, 228, 228, 228, 228, 228, 228, 229, 229, 229, 229, 229, 229, 229, 229, 229, 247, 247, 247, 247, 247, 247, 247, 247, 275, 275, 275, 275, 275, 275, 275, 275, 275, 276, 276, 276, 276, 276, 276, 276, 276, 276, 321, 321, 321, 321, 321, 321, 321, 321, 321, 322, 322, 322, 322, 322, 322, 322, 322, 322, 352, 352, 352, 352, 352, 352, 352, 352, 352, 379, 379, 379, 379, 379, 379, 379, 379, 379, 380, 415, 560, 525, 558, 557, 556, 554, 553, 550, 549, 548, 547, 546, 415, 545, 380, 543, 380, 525, 587, 542, 541, 587, 588, 588, 540, 588, 589, 589, 589, 589, 590, 590, 590, 590, 539, 538, 537, 534, 533, 532, 531, 529, 528, 527, 526, 523, 522, 521, 519, 518, 517, 516, 515, 514, 513, 512, 511, 510, 509, 508, 507, 506, 505, 504, 503, 502, 501, 498, 497, 496, 495, 493, 492, 490, 489, 488, 487, 486, 485, 483, 482, 481, 480, 479, 478, 476, 475, 474, 473, 472, 471, 470, 469, 468, 467, 466, 465, 464, 463, 462, 461, 460, 459, 458, 457, 456, 455, 454, 453, 451, 450, 449, 448, 447, 446, 445, 444, 443, 442, 441, 440, 438, 435, 434, 433, 432, 431, 430, 429, 428, 427, 426, 425, 423, 422, 421, 420, 419, 418, 417, 416, 414, 413, 412, 410, 409, 408, 407, 406, 404, 403, 402, 401, 400, 399, 396, 395, 394, 393, 392, 391, 389, 388, 387, 386, 385, 384, 383, 382, 381, 378, 376, 374, 372, 371, 370, 368, 367, 366, 364, 362, 361, 360, 359, 358, 354, 353, 349, 348, 347, 346, 345, 344, 343, 342, 341, 340, 339, 337, 336, 335, 333, 332, 331, 329, 328, 327, 326, 325, 324, 323, 320, 319, 318, 317, 315, 311, 310, 309, 308, 307, 306, 305, 304, 303, 301, 300, 299, 298, 288, 287, 286, 285, 284, 283, 281, 280, 279, 278, 277, 273, 272, 271, 270, 269, 268, 267, 265, 264, 263, 262, 261, 260, 258, 257, 255, 254, 253, 252, 251, 250, 249, 248, 246, 245, 244, 242, 241, 240, 238, 236, 235, 234, 233, 232, 230, 226, 225, 224, 222, 221, 220, 219, 218, 217, 216, 215, 214, 213, 212, 211, 210, 209, 208, 206, 204, 203, 202, 201, 200, 198, 196, 194, 193, 191, 190, 188, 185, 184, 183, 182, 179, 178, 177, 174, 173, 172, 171, 170, 169, 164, 163, 162, 161, 160, 159, 158, 157, 155, 154, 153, 152, 151, 150, 149, 148, 147, 146, 145, 144, 143, 142, 141, 140, 138, 137, 136, 134, 133, 132, 131, 130, 129, 128, 127, 126, 125, 124, 122, 121, 120, 119, 118, 117, 116, 115, 114, 113, 112, 111, 110, 109, 108, 101, 100, 99, 98, 97, 96, 95, 94, 93, 92, 91, 88, 87, 85, 84, 82, 81, 80, 79, 78, 77, 75, 73, 72, 71, 70, 68, 67, 66, 65, 64, 62, 61, 60, 56, 54, 48, 42, 36, 34, 31, 30, 29, 25, 21, 16, 3, 586, 586, 586, 586, 586, 586, 586, 586, 586, 586, 586, 586, 586, 586, 586, 586, 586, 586, 586, 586, 586, 586, 586, 586, 586, 586, 586, 586, 586, 586, 586, 586, 586, 586, 586, 586, 586, 586, 586, 586, 586, 586, 586, 586, 586, 586, 586, 586, 586, 586, 586, 586 } ; static yy_state_type yy_last_accepting_state; static char *yy_last_accepting_cpos; extern int yy_flex_debug; int yy_flex_debug = 0; /* The intent behind this definition is that it'll catch * any uses of REJECT which flex missed. */ #define REJECT reject_used_but_not_detected #define yymore() yymore_used_but_not_detected #define YY_MORE_ADJ 0 #define YY_RESTORE_YY_MORE_OFFSET char *yytext; #line 1 "lexer.l" /* * userv is copyright Ian Jackson and other contributors. * See README for full authorship information. * * 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; if not, see . */ #line 20 "lexer.l" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "config.h" #include "common.h" #include "daemon.h" #include "lib.h" #include "both.h" #include "tokens.h" #define HYPHEN '-' typedef int directive_fnt(int dtoken); static directive_fnt df_reject, df_execute, df_executefrompath; static directive_fnt df_executefromdirectory, df_executebuiltin; static directive_fnt df_errorstostderr, df_errorstosyslog, df_errorstofile; static directive_fnt dfg_fdwant, dfg_setflag, dfg_lookupquotemode; static directive_fnt df_reset, df_cd, df_userrcfile, df_include; static directive_fnt df_includelookup, df_includedirectory; static directive_fnt df_message, df_error, df_quit, df_eof; static directive_fnt df_if, df_catchquit, df_errorspush; static directive_fnt dfi_includeuserrcfile, dfi_includeclientconfig; /* directive functions return: * 0 for success having scanned up to and including end of line but not beyond, * or tokv_error or tokv_quit. * They expect to parse the whitespace before their parameters (if any). */ typedef int parmcondition_fnt(int ctoken, char *const *parmvalues, int *rtrue); static parmcondition_fnt pcf_glob, pcf_range, pcf_grep; /* all conditional functions return tokv_error for failure or 0 for success * at parsing and testing, in which case *rtrue is set to 0 or 1. * On success they have scanned up to and including the condition's * terminating newline; the pcf_... functions expect to parse the whitespace * between the parameter name and the condition's arguments. * Otherwise they return tokv_error. * The parameter-based conditionals take a list of parameter values * as obtained from the parameter functions and pa_parameter, * and do _not_ free it. */ typedef int parameter_fnt(int ptoken, char ***rvalues); static parameter_fnt pf_service; static parameter_fnt pf_callinguser, pf_serviceuser; static parameter_fnt pf_callinggroup, pf_servicegroup; static parameter_fnt pf_callingusershell, pf_serviceusershell; /* Parameter functions return tokv_error or 0 for success at parsing * and determining the value, in which case *rvalues is made to be * a mallocd null-terminated array of pointers to mallocd strings. * freeparm can be used to free such an array. */ typedef int builtinserviceparse_fnt(char ***rnewargs); static builtinserviceparse_fnt bispa_none, bispa_parameter; /* These parse the arguments to a builtin service, including the * newline at the end of the line. *rnewargs will initially be * null, indicating that no arguments are to be set; the function * may store a mallocd array of mallocd strings in it, * containing the arguments it wishes to have set (null-pointer * terminated). */ static int yylex(void); /* Returns a token (which may be an eof or error exception) */ static directive_fnt *lr_dir; static parmcondition_fnt *lr_parmcond; static builtinserviceparse_fnt *lr_bispa; static builtinserviceexec_fnt *lr_bisexec; static parameter_fnt *lr_parameter; static int lr_loglevel, lr_logfacility, lr_min, lr_max, *lr_flag; static int lr_flagval, lr_controlend; static int lr_fdwant_readwrite; /* -1=never, 0=opt, 1=always */ /* Forward declarations of things used in lexer and parser */ struct parser_state { int lineno, reportlineno, notedreferer, isinternal; const char *filename; struct stat filestab; YY_BUFFER_STATE ybuf; struct parser_state *upstate; }; static struct parser_state *cstate; struct error_handling { int handling; /* One of the error handling modes tokt_ehandlemode */ int logfacility, loglevel; int filekeep; /* File is in use by higher-level errors-push, leave it open */ FILE *file; char *filename; }; static struct error_handling eh = { tokv_word_errorstostderr, 0,0,0,0,0 }; static int dequote(char *inplace); static void countnewlines(void); #define YY_NO_INPUT #line 966 "" #line 967 "" #define INITIAL 0 #ifndef YY_NO_UNISTD_H /* Special case for "unistd.h", since it is non-ANSI. We include it way * down here because we want the user's section 1 to have been scanned first. * The user has a chance to override it with an option. */ #include #endif #ifndef YY_EXTRA_TYPE #define YY_EXTRA_TYPE void * #endif static int yy_init_globals ( void ); /* Accessor methods to globals. These are made visible to non-reentrant scanners for convenience. */ int yylex_destroy ( void ); int yyget_debug ( void ); void yyset_debug ( int debug_flag ); YY_EXTRA_TYPE yyget_extra ( void ); void yyset_extra ( YY_EXTRA_TYPE user_defined ); FILE *yyget_in ( void ); void yyset_in ( FILE * _in_str ); FILE *yyget_out ( void ); void yyset_out ( FILE * _out_str ); int yyget_leng ( void ); char *yyget_text ( void ); int yyget_lineno ( void ); void yyset_lineno ( int _line_number ); /* Macros after this point can all be overridden by user definitions in * section 1. */ #ifndef YY_SKIP_YYWRAP #ifdef __cplusplus extern "C" int yywrap ( void ); #else extern int yywrap ( void ); #endif #endif #ifndef YY_NO_UNPUT #endif #ifndef yytext_ptr static void yy_flex_strncpy ( char *, const char *, int ); #endif #ifdef YY_NEED_STRLEN static int yy_flex_strlen ( const char * ); #endif #ifndef YY_NO_INPUT #ifdef __cplusplus static int yyinput ( void ); #else static int input ( void ); #endif #endif /* Amount of stuff to slurp up with each read. */ #ifndef YY_READ_BUF_SIZE #ifdef __ia64__ /* On IA-64, the buffer size is 16k, not 8k */ #define YY_READ_BUF_SIZE 16384 #else #define YY_READ_BUF_SIZE 8192 #endif /* __ia64__ */ #endif /* Copy whatever the last rule matched to the standard output. */ #ifndef ECHO /* This used to be an fputs(), but since the string might contain NUL's, * we now use fwrite(). */ #define ECHO do { if (fwrite( yytext, (size_t) yyleng, 1, yyout )) {} } while (0) #endif /* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, * is returned in "result". */ #ifndef YY_INPUT #define YY_INPUT(buf,result,max_size) \ if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \ { \ int c = '*'; \ int n; \ for ( n = 0; n < max_size && \ (c = getc( yyin )) != EOF && c != '\n'; ++n ) \ buf[n] = (char) c; \ if ( c == '\n' ) \ buf[n++] = (char) c; \ if ( c == EOF && ferror( yyin ) ) \ YY_FATAL_ERROR( "input in flex scanner failed" ); \ result = n; \ } \ else \ { \ errno=0; \ while ( (result = (int) fread(buf, 1, (yy_size_t) max_size, yyin)) == 0 && ferror(yyin)) \ { \ if( errno != EINTR) \ { \ YY_FATAL_ERROR( "input in flex scanner failed" ); \ break; \ } \ errno=0; \ clearerr(yyin); \ } \ }\ \ #endif /* No semi-colon after return; correct usage is to write "yyterminate();" - * we don't want an extra ';' after the "return" because that will cause * some compilers to complain about unreachable statements. */ #ifndef yyterminate #define yyterminate() return YY_NULL #endif /* Number of entries by which start-condition stack grows. */ #ifndef YY_START_STACK_INCR #define YY_START_STACK_INCR 25 #endif /* Report a fatal error. */ #ifndef YY_FATAL_ERROR #define YY_FATAL_ERROR(msg) yy_fatal_error( msg ) #endif /* end tables serialization structures and prototypes */ /* Default declaration of generated scanner - a define so the user can * easily add parameters. */ #ifndef YY_DECL #define YY_DECL_IS_OURS 1 extern int yylex (void); #define YY_DECL int yylex (void) #endif /* !YY_DECL */ /* Code executed at the beginning of each rule, after yytext and yyleng * have been set up. */ #ifndef YY_USER_ACTION #define YY_USER_ACTION #endif /* Code executed at the end of each rule. */ #ifndef YY_BREAK #define YY_BREAK /*LINTED*/break; #endif #define YY_RULE_SETUP \ YY_USER_ACTION /** The main scanner function which does all the work. */ YY_DECL { yy_state_type yy_current_state; char *yy_cp, *yy_bp; int yy_act; if ( !(yy_init) ) { (yy_init) = 1; #ifdef YY_USER_INIT YY_USER_INIT; #endif if ( ! (yy_start) ) (yy_start) = 1; /* first start state */ if ( ! yyin ) yyin = stdin; if ( ! yyout ) yyout = stdout; if ( ! YY_CURRENT_BUFFER ) { yyensure_buffer_stack (); YY_CURRENT_BUFFER_LVALUE = yy_create_buffer( yyin, YY_BUF_SIZE ); } yy_load_buffer_state( ); } { #line 145 "lexer.l" #line 1185 "" while ( /*CONSTCOND*/1 ) /* loops until end-of-file is reached */ { yy_cp = (yy_c_buf_p); /* Support of yytext. */ *yy_cp = (yy_hold_char); /* yy_bp points to the position in yy_ch_buf of the start of * the current run. */ yy_bp = yy_cp; yy_current_state = (yy_start); yy_match: do { YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)] ; if ( yy_accept[yy_current_state] ) { (yy_last_accepting_state) = yy_current_state; (yy_last_accepting_cpos) = yy_cp; } while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; if ( yy_current_state >= 587 ) yy_c = yy_meta[yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; ++yy_cp; } while ( yy_base[yy_current_state] != 802 ); yy_find_action: yy_act = yy_accept[yy_current_state]; if ( yy_act == 0 ) { /* have to back up */ yy_cp = (yy_last_accepting_cpos); yy_current_state = (yy_last_accepting_state); yy_act = yy_accept[yy_current_state]; } YY_DO_BEFORE_ACTION; do_action: /* This label is used only to access EOF actions. */ switch ( yy_act ) { /* beginning of action switch */ case 0: /* must back up */ /* undo the effects of YY_DO_BEFORE_ACTION */ *yy_cp = (yy_hold_char); yy_cp = (yy_last_accepting_cpos); yy_current_state = (yy_last_accepting_state); goto yy_find_action; case 1: YY_RULE_SETUP #line 147 "lexer.l" { lr_dir= df_reject; return tokv_word_reject; } YY_BREAK case 2: YY_RULE_SETUP #line 148 "lexer.l" { lr_dir= df_executefromdirectory; return tokv_word_executefromdirectory; } YY_BREAK case 3: YY_RULE_SETUP #line 149 "lexer.l" { lr_dir= df_executefrompath; return tokv_word_executefrompath; } YY_BREAK case 4: YY_RULE_SETUP #line 150 "lexer.l" { lr_dir= df_executebuiltin; return tokv_word_executebuiltin; } YY_BREAK case 5: YY_RULE_SETUP #line 151 "lexer.l" { lr_dir= df_errorstostderr; return tokv_word_errorstostderr; } YY_BREAK case 6: YY_RULE_SETUP #line 152 "lexer.l" { lr_dir= df_errorstosyslog; return tokv_word_errorstosyslog; } YY_BREAK case 7: YY_RULE_SETUP #line 153 "lexer.l" { lr_dir= df_errorstofile; return tokv_word_errorstofile; } YY_BREAK case 8: YY_RULE_SETUP #line 154 "lexer.l" { lr_dir= dfg_lookupquotemode; return tokv_word_includelookupquoteold; } YY_BREAK case 9: YY_RULE_SETUP #line 155 "lexer.l" { lr_dir= dfg_lookupquotemode; return tokv_word_includelookupquotenew; } YY_BREAK case 10: YY_RULE_SETUP #line 156 "lexer.l" { lr_dir= dfg_fdwant; lr_fdwant_readwrite=1; return tokv_word_requirefd; } YY_BREAK case 11: YY_RULE_SETUP #line 157 "lexer.l" { lr_dir= dfg_fdwant; lr_fdwant_readwrite=0; return tokv_word_allowfd; } YY_BREAK case 12: YY_RULE_SETUP #line 158 "lexer.l" { lr_dir= dfg_fdwant; lr_fdwant_readwrite=0; return tokv_word_nullfd; } YY_BREAK case 13: YY_RULE_SETUP #line 159 "lexer.l" { lr_dir= dfg_fdwant; lr_fdwant_readwrite=-1; return tokv_word_rejectfd; } YY_BREAK case 14: YY_RULE_SETUP #line 160 "lexer.l" { lr_dir= dfg_fdwant; lr_fdwant_readwrite=-1; return tokv_word_ignorefd; } YY_BREAK case 15: YY_RULE_SETUP #line 161 "lexer.l" { lr_dir= dfg_setflag; lr_flag= &setenvironment; lr_flagval= 1; return tokv_word_setenvironment; } YY_BREAK case 16: YY_RULE_SETUP #line 162 "lexer.l" { lr_dir= dfg_setflag; lr_flag= &setenvironment; lr_flagval= 0; return tokv_word_nosetenvironment; } YY_BREAK case 17: YY_RULE_SETUP #line 163 "lexer.l" { lr_dir= dfg_setflag; lr_flag= &suppressargs; lr_flagval= 1; return tokv_word_suppressargs; } YY_BREAK case 18: YY_RULE_SETUP #line 164 "lexer.l" { lr_dir= dfg_setflag; lr_flag= &suppressargs; lr_flagval= 0; return tokv_word_nosuppressargs; } YY_BREAK case 19: YY_RULE_SETUP #line 165 "lexer.l" { lr_dir= dfg_setflag; lr_flag= &disconnecthup; lr_flagval= 1; return tokv_word_disconnecthup; } YY_BREAK case 20: YY_RULE_SETUP #line 166 "lexer.l" { lr_dir= dfg_setflag; lr_flag= &disconnecthup; lr_flagval= 0; return tokv_word_nodisconnecthup; } YY_BREAK case 21: YY_RULE_SETUP #line 167 "lexer.l" { lr_dir= df_cd; return tokv_word_cd; } YY_BREAK case 22: YY_RULE_SETUP #line 168 "lexer.l" { lr_dir= df_userrcfile; return tokv_word_userrcfile; } YY_BREAK case 23: YY_RULE_SETUP #line 169 "lexer.l" { lr_dir= df_include; return tokv_word_include; } YY_BREAK case 24: YY_RULE_SETUP #line 170 "lexer.l" { lr_dir= df_include; return tokv_word_includeifexist; } YY_BREAK case 25: YY_RULE_SETUP #line 171 "lexer.l" { lr_dir= df_includelookup; return tokv_word_includelookup; } YY_BREAK case 26: YY_RULE_SETUP #line 172 "lexer.l" { lr_dir= df_includelookup; return tokv_word_includelookupall; } YY_BREAK case 27: YY_RULE_SETUP #line 173 "lexer.l" { lr_dir= df_includedirectory; return tokv_word_includedirectory; } YY_BREAK case 28: YY_RULE_SETUP #line 174 "lexer.l" { lr_dir= df_message; return tokv_word_message; } YY_BREAK case 29: YY_RULE_SETUP #line 175 "lexer.l" { lr_dir= df_include; return tokv_word_includesysconfig; } YY_BREAK case 30: YY_RULE_SETUP #line 176 "lexer.l" { lr_dir= dfi_includeuserrcfile; return tokv_word_includeuserrcfile; } YY_BREAK case 31: YY_RULE_SETUP #line 177 "lexer.l" { lr_dir= dfi_includeclientconfig; return tokv_word_includeclientconfig; } YY_BREAK case 32: YY_RULE_SETUP #line 178 "lexer.l" { lr_dir= df_quit; return tokv_word_quit; } YY_BREAK case 33: YY_RULE_SETUP #line 179 "lexer.l" { lr_dir= df_eof; return tokv_word_eof; } YY_BREAK case 34: YY_RULE_SETUP #line 180 "lexer.l" { lr_dir= df_if; return tokv_word_if; } YY_BREAK case 35: YY_RULE_SETUP #line 181 "lexer.l" { lr_dir= df_catchquit; return tokv_word_catchquit; } YY_BREAK case 36: YY_RULE_SETUP #line 182 "lexer.l" { lr_dir= df_errorspush; return tokv_word_errorspush; } YY_BREAK case 37: YY_RULE_SETUP #line 183 "lexer.l" { lr_controlend= tokv_word_if; return tokv_word_elif; } YY_BREAK case 38: YY_RULE_SETUP #line 184 "lexer.l" { lr_controlend= tokv_word_if; return tokv_word_else; } YY_BREAK case 39: YY_RULE_SETUP #line 185 "lexer.l" { lr_controlend= tokv_word_if; return tokv_word_fi; } YY_BREAK case 40: YY_RULE_SETUP #line 186 "lexer.l" { lr_controlend= tokv_word_catchquit; return tokv_word_hctac; } YY_BREAK case 41: YY_RULE_SETUP #line 187 "lexer.l" { lr_controlend= tokv_word_errorspush; return tokv_word_srorre; } YY_BREAK case 42: YY_RULE_SETUP #line 188 "lexer.l" { lr_parmcond= pcf_glob; return tokv_word_glob; } YY_BREAK case 43: YY_RULE_SETUP #line 189 "lexer.l" { lr_parmcond= pcf_range; return tokv_word_range; } YY_BREAK case 44: YY_RULE_SETUP #line 190 "lexer.l" { lr_parmcond= pcf_grep; return tokv_word_grep; } YY_BREAK case 45: YY_RULE_SETUP #line 191 "lexer.l" { lr_bispa= bispa_none; lr_bisexec= bisexec_environment; return tokv_word_environment; } YY_BREAK case 46: YY_RULE_SETUP #line 192 "lexer.l" { lr_bispa= bispa_parameter; lr_bisexec= bisexec_parameter; return tokv_word_parameter; } YY_BREAK case 47: YY_RULE_SETUP #line 193 "lexer.l" { lr_bispa= bispa_none; lr_bisexec= bisexec_version; return tokv_word_version; } YY_BREAK case 48: YY_RULE_SETUP #line 194 "lexer.l" { lr_bispa= bispa_none; lr_bisexec= bisexec_toplevel; return tokv_word_toplevel; } YY_BREAK case 49: YY_RULE_SETUP #line 195 "lexer.l" { lr_bispa= bispa_none; lr_bisexec= bisexec_override; return tokv_word_override; } YY_BREAK case 50: YY_RULE_SETUP #line 196 "lexer.l" { lr_bispa= bispa_none; lr_bisexec= bisexec_shutdown; return tokv_word_shutdown; } YY_BREAK case 51: YY_RULE_SETUP #line 197 "lexer.l" { lr_bispa= bispa_none; lr_bisexec= bisexec_reset; lr_dir= df_reset; return tokv_word_reset; } YY_BREAK case 52: YY_RULE_SETUP #line 198 "lexer.l" { lr_bispa= bispa_none; lr_bisexec= bisexec_execute; lr_dir= df_execute; return tokv_word_execute; } YY_BREAK case 53: YY_RULE_SETUP #line 199 "lexer.l" { lr_bispa= bispa_none; lr_bisexec= bisexec_help; return tokv_word_help; } YY_BREAK case 54: YY_RULE_SETUP #line 200 "lexer.l" { lr_parameter= pf_service; return tokv_word_service; } YY_BREAK case 55: YY_RULE_SETUP #line 201 "lexer.l" { lr_parameter= pf_callinguser; return tokv_word_callinguser; } YY_BREAK case 56: YY_RULE_SETUP #line 202 "lexer.l" { lr_parameter= pf_callinggroup; return tokv_word_callinggroup; } YY_BREAK case 57: YY_RULE_SETUP #line 203 "lexer.l" { lr_parameter= pf_callingusershell; return tokv_word_callingusershell; } YY_BREAK case 58: YY_RULE_SETUP #line 204 "lexer.l" { lr_parameter= pf_serviceuser; return tokv_word_serviceuser; } YY_BREAK case 59: YY_RULE_SETUP #line 205 "lexer.l" { lr_parameter= pf_servicegroup; return tokv_word_servicegroup; } YY_BREAK case 60: YY_RULE_SETUP #line 206 "lexer.l" { lr_parameter= pf_serviceusershell; return tokv_word_serviceusershell; } YY_BREAK case 61: YY_RULE_SETUP #line 207 "lexer.l" { lr_loglevel= LOG_DEBUG; return tokv_syslog_debug; } YY_BREAK case 62: YY_RULE_SETUP #line 208 "lexer.l" { lr_loglevel= LOG_INFO; return tokv_syslog_info; } YY_BREAK case 63: YY_RULE_SETUP #line 209 "lexer.l" { lr_loglevel= LOG_NOTICE; return tokv_syslog_notice; } YY_BREAK case 64: YY_RULE_SETUP #line 210 "lexer.l" { lr_loglevel= LOG_WARNING; return tokv_syslog_warning; } YY_BREAK case 65: YY_RULE_SETUP #line 211 "lexer.l" { lr_loglevel= LOG_ERR; return tokv_syslog_err; } YY_BREAK case 66: YY_RULE_SETUP #line 212 "lexer.l" { lr_loglevel= LOG_CRIT; return tokv_syslog_crit; } YY_BREAK case 67: YY_RULE_SETUP #line 213 "lexer.l" { lr_loglevel= LOG_ALERT; return tokv_syslog_alert; } YY_BREAK case 68: YY_RULE_SETUP #line 214 "lexer.l" { lr_loglevel= LOG_EMERG; return tokv_syslog_emerg; } YY_BREAK case 69: YY_RULE_SETUP #line 215 "lexer.l" { lr_logfacility= LOG_AUTHPRIV; return tokv_syslog_authpriv; } YY_BREAK case 70: YY_RULE_SETUP #line 216 "lexer.l" { lr_logfacility= LOG_CRON; return tokv_syslog_cron; } YY_BREAK case 71: YY_RULE_SETUP #line 217 "lexer.l" { lr_logfacility= LOG_DAEMON; return tokv_syslog_daemon; } YY_BREAK case 72: YY_RULE_SETUP #line 218 "lexer.l" { lr_logfacility= LOG_KERN; return tokv_syslog_kern; } YY_BREAK case 73: YY_RULE_SETUP #line 219 "lexer.l" { lr_logfacility= LOG_LPR; return tokv_syslog_lpr; } YY_BREAK case 74: YY_RULE_SETUP #line 220 "lexer.l" { lr_logfacility= LOG_MAIL; return tokv_syslog_mail; } YY_BREAK case 75: YY_RULE_SETUP #line 221 "lexer.l" { lr_logfacility= LOG_NEWS; return tokv_syslog_news; } YY_BREAK case 76: YY_RULE_SETUP #line 222 "lexer.l" { lr_logfacility= LOG_SYSLOG; return tokv_syslog_syslog; } YY_BREAK case 77: YY_RULE_SETUP #line 223 "lexer.l" { lr_logfacility= LOG_USER; return tokv_syslog_user; } YY_BREAK case 78: YY_RULE_SETUP #line 224 "lexer.l" { lr_logfacility= LOG_UUCP; return tokv_syslog_uucp; } YY_BREAK case 79: YY_RULE_SETUP #line 225 "lexer.l" { lr_logfacility= LOG_LOCAL0; return tokv_syslog_local0; } YY_BREAK case 80: YY_RULE_SETUP #line 226 "lexer.l" { lr_logfacility= LOG_LOCAL1; return tokv_syslog_local1; } YY_BREAK case 81: YY_RULE_SETUP #line 227 "lexer.l" { lr_logfacility= LOG_LOCAL2; return tokv_syslog_local2; } YY_BREAK case 82: YY_RULE_SETUP #line 228 "lexer.l" { lr_logfacility= LOG_LOCAL3; return tokv_syslog_local3; } YY_BREAK case 83: YY_RULE_SETUP #line 229 "lexer.l" { lr_logfacility= LOG_LOCAL4; return tokv_syslog_local4; } YY_BREAK case 84: YY_RULE_SETUP #line 230 "lexer.l" { lr_logfacility= LOG_LOCAL5; return tokv_syslog_local5; } YY_BREAK case 85: YY_RULE_SETUP #line 231 "lexer.l" { lr_logfacility= LOG_LOCAL6; return tokv_syslog_local6; } YY_BREAK case 86: YY_RULE_SETUP #line 232 "lexer.l" { lr_logfacility= LOG_LOCAL7; return tokv_syslog_local7; } YY_BREAK case 87: YY_RULE_SETUP #line 233 "lexer.l" { return tokv_word_read; } YY_BREAK case 88: YY_RULE_SETUP #line 234 "lexer.l" { return tokv_word_write; } YY_BREAK case 89: YY_RULE_SETUP #line 235 "lexer.l" { return tokv_dollar; } YY_BREAK case 90: YY_RULE_SETUP #line 236 "lexer.l" { lr_max= lr_min= 0; return tokv_word_stdin; } YY_BREAK case 91: YY_RULE_SETUP #line 237 "lexer.l" { lr_max= lr_min= 1; return tokv_word_stdout; } YY_BREAK case 92: YY_RULE_SETUP #line 238 "lexer.l" { lr_max= lr_min= 2; return tokv_word_stderr; } YY_BREAK case 93: YY_RULE_SETUP #line 239 "lexer.l" { return tokv_openparen; } YY_BREAK case 94: YY_RULE_SETUP #line 240 "lexer.l" { return tokv_closeparen; } YY_BREAK case 95: YY_RULE_SETUP #line 241 "lexer.l" { return tokv_not; } YY_BREAK case 96: YY_RULE_SETUP #line 242 "lexer.l" { return tokv_and; } YY_BREAK case 97: YY_RULE_SETUP #line 243 "lexer.l" { return tokv_or; } YY_BREAK case 98: YY_RULE_SETUP #line 244 "lexer.l" { lr_dir= df_error; lr_loglevel= LOG_ERR; return tokv_word_error; } YY_BREAK case 99: YY_RULE_SETUP #line 248 "lexer.l" { char *ep; lr_min=lr_max= (int)strtoul(yytext,&ep,10); assert(!*ep); return tokv_ordinal; } YY_BREAK case 100: YY_RULE_SETUP #line 254 "lexer.l" { char *ep; lr_min= (int)strtoul(yytext,&ep,10); assert(*ep == HYPHEN); ep++; assert(*ep); lr_max= (int)strtoul(ep,&ep,10); assert(!*ep); if (lr_max < lr_min) return parseerrprint("fd range has min > max"); return tokv_fdrange; } YY_BREAK case 101: YY_RULE_SETUP #line 265 "lexer.l" { char *ep; lr_min= (int)strtoul(yytext,&ep,10); assert(*ep == HYPHEN); ep++; assert(!*ep); lr_max=-1; return tokv_fdstoend; } YY_BREAK case 102: /* rule 102 can match eol */ YY_RULE_SETUP #line 273 "lexer.l" countnewlines(); return tokv_lwsp; YY_BREAK case 103: YY_RULE_SETUP #line 274 "lexer.l" return tokv_lwsp; YY_BREAK case 104: /* rule 104 can match eol */ YY_RULE_SETUP #line 275 "lexer.l" cstate->lineno++; return tokv_newline; YY_BREAK case 105: /* rule 105 can match eol */ YY_RULE_SETUP #line 276 "lexer.l" cstate->lineno++; return tokv_newline; YY_BREAK case 106: YY_RULE_SETUP #line 277 "lexer.l" return parseerrprint("missing newline at eof after comment"); YY_BREAK case 107: /* rule 107 can match eol */ YY_RULE_SETUP #line 278 "lexer.l" { countnewlines(); return dequote(yytext); } YY_BREAK case 108: YY_RULE_SETUP #line 282 "lexer.l" return tokv_barestring; YY_BREAK case YY_STATE_EOF(INITIAL): #line 283 "lexer.l" return tokv_eof; YY_BREAK case 109: YY_RULE_SETUP #line 284 "lexer.l" return parseerrprint("misquoted or unterminated string"); YY_BREAK case 110: YY_RULE_SETUP #line 285 "lexer.l" return parseerrprint("unexpected backslash"); YY_BREAK case 111: YY_RULE_SETUP #line 286 "lexer.l" abort(); /* expect lex warning "rule cannot be matched" */ YY_BREAK case 112: YY_RULE_SETUP #line 289 "lexer.l" ECHO; YY_BREAK #line 1835 "" case YY_END_OF_BUFFER: { /* Amount of text matched not including the EOB char. */ int yy_amount_of_matched_text = (int) (yy_cp - (yytext_ptr)) - 1; /* Undo the effects of YY_DO_BEFORE_ACTION. */ *yy_cp = (yy_hold_char); YY_RESTORE_YY_MORE_OFFSET if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW ) { /* We're scanning a new file or input source. It's * possible that this happened because the user * just pointed yyin at a new source and called * yylex(). If so, then we have to assure * consistency between YY_CURRENT_BUFFER and our * globals. Here is the right place to do so, because * this is the first action (other than possibly a * back-up) that will match for the new input source. */ (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin; YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL; } /* Note that here we test for yy_c_buf_p "<=" to the position * of the first EOB in the buffer, since yy_c_buf_p will * already have been incremented past the NUL character * (since all states make transitions on EOB to the * end-of-buffer state). Contrast this with the test * in input(). */ if ( (yy_c_buf_p) <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] ) { /* This was really a NUL. */ yy_state_type yy_next_state; (yy_c_buf_p) = (yytext_ptr) + yy_amount_of_matched_text; yy_current_state = yy_get_previous_state( ); /* Okay, we're now positioned to make the NUL * transition. We couldn't have * yy_get_previous_state() go ahead and do it * for us because it doesn't know how to deal * with the possibility of jamming (and we don't * want to build jamming into it because then it * will run more slowly). */ yy_next_state = yy_try_NUL_trans( yy_current_state ); yy_bp = (yytext_ptr) + YY_MORE_ADJ; if ( yy_next_state ) { /* Consume the NUL. */ yy_cp = ++(yy_c_buf_p); yy_current_state = yy_next_state; goto yy_match; } else { yy_cp = (yy_c_buf_p); goto yy_find_action; } } else switch ( yy_get_next_buffer( ) ) { case EOB_ACT_END_OF_FILE: { (yy_did_buffer_switch_on_eof) = 0; if ( yywrap( ) ) { /* Note: because we've taken care in * yy_get_next_buffer() to have set up * yytext, we can now set up * yy_c_buf_p so that if some total * hoser (like flex itself) wants to * call the scanner after we return the * YY_NULL, it'll still work - another * YY_NULL will get returned. */ (yy_c_buf_p) = (yytext_ptr) + YY_MORE_ADJ; yy_act = YY_STATE_EOF(YY_START); goto do_action; } else { if ( ! (yy_did_buffer_switch_on_eof) ) YY_NEW_FILE; } break; } case EOB_ACT_CONTINUE_SCAN: (yy_c_buf_p) = (yytext_ptr) + yy_amount_of_matched_text; yy_current_state = yy_get_previous_state( ); yy_cp = (yy_c_buf_p); yy_bp = (yytext_ptr) + YY_MORE_ADJ; goto yy_match; case EOB_ACT_LAST_MATCH: (yy_c_buf_p) = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)]; yy_current_state = yy_get_previous_state( ); yy_cp = (yy_c_buf_p); yy_bp = (yytext_ptr) + YY_MORE_ADJ; goto yy_find_action; } break; } default: YY_FATAL_ERROR( "fatal flex scanner internal error--no action found" ); } /* end of action switch */ } /* end of scanning one token */ } /* end of user's declarations */ } /* end of yylex */ /* yy_get_next_buffer - try to read in a new buffer * * Returns a code representing an action: * EOB_ACT_LAST_MATCH - * EOB_ACT_CONTINUE_SCAN - continue scanning from current position * EOB_ACT_END_OF_FILE - end of file */ static int yy_get_next_buffer (void) { char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf; char *source = (yytext_ptr); int number_to_move, i; int ret_val; if ( (yy_c_buf_p) > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] ) YY_FATAL_ERROR( "fatal flex scanner internal error--end of buffer missed" ); if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 ) { /* Don't try to fill the buffer, so this is an EOF. */ if ( (yy_c_buf_p) - (yytext_ptr) - YY_MORE_ADJ == 1 ) { /* We matched a single character, the EOB, so * treat this as a final EOF. */ return EOB_ACT_END_OF_FILE; } else { /* We matched some text prior to the EOB, first * process it. */ return EOB_ACT_LAST_MATCH; } } /* Try to read more data. */ /* First move last chars to start of buffer. */ number_to_move = (int) ((yy_c_buf_p) - (yytext_ptr) - 1); for ( i = 0; i < number_to_move; ++i ) *(dest++) = *(source++); if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING ) /* don't do the read, it's not guaranteed to return an EOF, * just force an EOF */ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars) = 0; else { int num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; while ( num_to_read <= 0 ) { /* Not enough room in the buffer - grow it. */ /* just a shorter name for the current buffer */ YY_BUFFER_STATE b = YY_CURRENT_BUFFER_LVALUE; int yy_c_buf_p_offset = (int) ((yy_c_buf_p) - b->yy_ch_buf); if ( b->yy_is_our_buffer ) { int new_size = b->yy_buf_size * 2; if ( new_size <= 0 ) b->yy_buf_size += b->yy_buf_size / 8; else b->yy_buf_size *= 2; b->yy_ch_buf = (char *) /* Include room in for 2 EOB chars. */ yyrealloc( (void *) b->yy_ch_buf, (yy_size_t) (b->yy_buf_size + 2) ); } else /* Can't grow it, we don't own it. */ b->yy_ch_buf = NULL; if ( ! b->yy_ch_buf ) YY_FATAL_ERROR( "fatal error - scanner input buffer overflow" ); (yy_c_buf_p) = &b->yy_ch_buf[yy_c_buf_p_offset]; num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; } if ( num_to_read > YY_READ_BUF_SIZE ) num_to_read = YY_READ_BUF_SIZE; /* Read in more data. */ YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]), (yy_n_chars), num_to_read ); YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); } if ( (yy_n_chars) == 0 ) { if ( number_to_move == YY_MORE_ADJ ) { ret_val = EOB_ACT_END_OF_FILE; yyrestart( yyin ); } else { ret_val = EOB_ACT_LAST_MATCH; YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_EOF_PENDING; } } else ret_val = EOB_ACT_CONTINUE_SCAN; if (((yy_n_chars) + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) { /* Extend the array by 50%, plus the number we really need. */ int new_size = (yy_n_chars) + number_to_move + ((yy_n_chars) >> 1); YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) yyrealloc( (void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf, (yy_size_t) new_size ); if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" ); /* "- 2" to take care of EOB's */ YY_CURRENT_BUFFER_LVALUE->yy_buf_size = (int) (new_size - 2); } (yy_n_chars) += number_to_move; YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] = YY_END_OF_BUFFER_CHAR; YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] = YY_END_OF_BUFFER_CHAR; (yytext_ptr) = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0]; return ret_val; } /* yy_get_previous_state - get the state just before the EOB char was reached */ static yy_state_type yy_get_previous_state (void) { yy_state_type yy_current_state; char *yy_cp; yy_current_state = (yy_start); for ( yy_cp = (yytext_ptr) + YY_MORE_ADJ; yy_cp < (yy_c_buf_p); ++yy_cp ) { YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1); if ( yy_accept[yy_current_state] ) { (yy_last_accepting_state) = yy_current_state; (yy_last_accepting_cpos) = yy_cp; } while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; if ( yy_current_state >= 587 ) yy_c = yy_meta[yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; } return yy_current_state; } /* yy_try_NUL_trans - try to make a transition on the NUL character * * synopsis * next_state = yy_try_NUL_trans( current_state ); */ static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state ) { int yy_is_jam; char *yy_cp = (yy_c_buf_p); YY_CHAR yy_c = 1; if ( yy_accept[yy_current_state] ) { (yy_last_accepting_state) = yy_current_state; (yy_last_accepting_cpos) = yy_cp; } while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; if ( yy_current_state >= 587 ) yy_c = yy_meta[yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; yy_is_jam = (yy_current_state == 586); return yy_is_jam ? 0 : yy_current_state; } #ifndef YY_NO_UNPUT #endif #ifndef YY_NO_INPUT #ifdef __cplusplus static int yyinput (void) #else static int input (void) #endif { int c; *(yy_c_buf_p) = (yy_hold_char); if ( *(yy_c_buf_p) == YY_END_OF_BUFFER_CHAR ) { /* yy_c_buf_p now points to the character we want to return. * If this occurs *before* the EOB characters, then it's a * valid NUL; if not, then we've hit the end of the buffer. */ if ( (yy_c_buf_p) < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] ) /* This was really a NUL. */ *(yy_c_buf_p) = '\0'; else { /* need more input */ int offset = (int) ((yy_c_buf_p) - (yytext_ptr)); ++(yy_c_buf_p); switch ( yy_get_next_buffer( ) ) { case EOB_ACT_LAST_MATCH: /* This happens because yy_g_n_b() * sees that we've accumulated a * token and flags that we need to * try matching the token before * proceeding. But for input(), * there's no matching to consider. * So convert the EOB_ACT_LAST_MATCH * to EOB_ACT_END_OF_FILE. */ /* Reset buffer status. */ yyrestart( yyin ); /*FALLTHROUGH*/ case EOB_ACT_END_OF_FILE: { if ( yywrap( ) ) return 0; if ( ! (yy_did_buffer_switch_on_eof) ) YY_NEW_FILE; #ifdef __cplusplus return yyinput(); #else return input(); #endif } case EOB_ACT_CONTINUE_SCAN: (yy_c_buf_p) = (yytext_ptr) + offset; break; } } } c = *(unsigned char *) (yy_c_buf_p); /* cast for 8-bit char's */ *(yy_c_buf_p) = '\0'; /* preserve yytext */ (yy_hold_char) = *++(yy_c_buf_p); return c; } #endif /* ifndef YY_NO_INPUT */ /** Immediately switch to a different input stream. * @param input_file A readable stream. * * @note This function does not reset the start condition to @c INITIAL . */ void yyrestart (FILE * input_file ) { if ( ! YY_CURRENT_BUFFER ){ yyensure_buffer_stack (); YY_CURRENT_BUFFER_LVALUE = yy_create_buffer( yyin, YY_BUF_SIZE ); } yy_init_buffer( YY_CURRENT_BUFFER, input_file ); yy_load_buffer_state( ); } /** Switch to a different input buffer. * @param new_buffer The new input buffer. * */ void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer ) { /* TODO. We should be able to replace this entire function body * with * yypop_buffer_state(); * yypush_buffer_state(new_buffer); */ yyensure_buffer_stack (); if ( YY_CURRENT_BUFFER == new_buffer ) return; if ( YY_CURRENT_BUFFER ) { /* Flush out information for old buffer. */ *(yy_c_buf_p) = (yy_hold_char); YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p); YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); } YY_CURRENT_BUFFER_LVALUE = new_buffer; yy_load_buffer_state( ); /* We don't actually know whether we did this switch during * EOF (yywrap()) processing, but the only time this flag * is looked at is after yywrap() is called, so it's safe * to go ahead and always set it. */ (yy_did_buffer_switch_on_eof) = 1; } static void yy_load_buffer_state (void) { (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; (yytext_ptr) = (yy_c_buf_p) = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos; yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file; (yy_hold_char) = *(yy_c_buf_p); } /** Allocate and initialize an input buffer state. * @param file A readable stream. * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE. * * @return the allocated buffer state. */ YY_BUFFER_STATE yy_create_buffer (FILE * file, int size ) { YY_BUFFER_STATE b; b = (YY_BUFFER_STATE) yyalloc( sizeof( struct yy_buffer_state ) ); if ( ! b ) YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); b->yy_buf_size = size; /* yy_ch_buf has to be 2 characters longer than the size given because * we need to put in 2 end-of-buffer characters. */ b->yy_ch_buf = (char *) yyalloc( (yy_size_t) (b->yy_buf_size + 2) ); if ( ! b->yy_ch_buf ) YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); b->yy_is_our_buffer = 1; yy_init_buffer( b, file ); return b; } /** Destroy the buffer. * @param b a buffer created with yy_create_buffer() * */ void yy_delete_buffer (YY_BUFFER_STATE b ) { if ( ! b ) return; if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */ YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0; if ( b->yy_is_our_buffer ) yyfree( (void *) b->yy_ch_buf ); yyfree( (void *) b ); } /* Initializes or reinitializes a buffer. * This function is sometimes called more than once on the same buffer, * such as during a yyrestart() or at EOF. */ static void yy_init_buffer (YY_BUFFER_STATE b, FILE * file ) { int oerrno = errno; yy_flush_buffer( b ); b->yy_input_file = file; b->yy_fill_buffer = 1; /* If b is the current buffer, then yy_init_buffer was _probably_ * called from yyrestart() or through yy_get_next_buffer. * In that case, we don't want to reset the lineno or column. */ if (b != YY_CURRENT_BUFFER){ b->yy_bs_lineno = 1; b->yy_bs_column = 0; } b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0; errno = oerrno; } /** Discard all buffered characters. On the next scan, YY_INPUT will be called. * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER. * */ void yy_flush_buffer (YY_BUFFER_STATE b ) { if ( ! b ) return; b->yy_n_chars = 0; /* We always need two end-of-buffer characters. The first causes * a transition to the end-of-buffer state. The second causes * a jam in that state. */ b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR; b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR; b->yy_buf_pos = &b->yy_ch_buf[0]; b->yy_at_bol = 1; b->yy_buffer_status = YY_BUFFER_NEW; if ( b == YY_CURRENT_BUFFER ) yy_load_buffer_state( ); } /** Pushes the new state onto the stack. The new state becomes * the current state. This function will allocate the stack * if necessary. * @param new_buffer The new state. * */ void yypush_buffer_state (YY_BUFFER_STATE new_buffer ) { if (new_buffer == NULL) return; yyensure_buffer_stack(); /* This block is copied from yy_switch_to_buffer. */ if ( YY_CURRENT_BUFFER ) { /* Flush out information for old buffer. */ *(yy_c_buf_p) = (yy_hold_char); YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p); YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); } /* Only push if top exists. Otherwise, replace top. */ if (YY_CURRENT_BUFFER) (yy_buffer_stack_top)++; YY_CURRENT_BUFFER_LVALUE = new_buffer; /* copied from yy_switch_to_buffer. */ yy_load_buffer_state( ); (yy_did_buffer_switch_on_eof) = 1; } /** Removes and deletes the top of the stack, if present. * The next element becomes the new top. * */ void yypop_buffer_state (void) { if (!YY_CURRENT_BUFFER) return; yy_delete_buffer(YY_CURRENT_BUFFER ); YY_CURRENT_BUFFER_LVALUE = NULL; if ((yy_buffer_stack_top) > 0) --(yy_buffer_stack_top); if (YY_CURRENT_BUFFER) { yy_load_buffer_state( ); (yy_did_buffer_switch_on_eof) = 1; } } /* Allocates the stack if it does not exist. * Guarantees space for at least one push. */ static void yyensure_buffer_stack (void) { yy_size_t num_to_alloc; if (!(yy_buffer_stack)) { /* First allocation is just for 2 elements, since we don't know if this * scanner will even need a stack. We use 2 instead of 1 to avoid an * immediate realloc on the next call. */ num_to_alloc = 1; /* After all that talk, this was set to 1 anyways... */ (yy_buffer_stack) = (struct yy_buffer_state**)yyalloc (num_to_alloc * sizeof(struct yy_buffer_state*) ); if ( ! (yy_buffer_stack) ) YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" ); memset((yy_buffer_stack), 0, num_to_alloc * sizeof(struct yy_buffer_state*)); (yy_buffer_stack_max) = num_to_alloc; (yy_buffer_stack_top) = 0; return; } if ((yy_buffer_stack_top) >= ((yy_buffer_stack_max)) - 1){ /* Increase the buffer to prepare for a possible push. */ yy_size_t grow_size = 8 /* arbitrary grow size */; num_to_alloc = (yy_buffer_stack_max) + grow_size; (yy_buffer_stack) = (struct yy_buffer_state**)yyrealloc ((yy_buffer_stack), num_to_alloc * sizeof(struct yy_buffer_state*) ); if ( ! (yy_buffer_stack) ) YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" ); /* zero only the new slots.*/ memset((yy_buffer_stack) + (yy_buffer_stack_max), 0, grow_size * sizeof(struct yy_buffer_state*)); (yy_buffer_stack_max) = num_to_alloc; } } /** Setup the input buffer state to scan directly from a user-specified character buffer. * @param base the character buffer * @param size the size in bytes of the character buffer * * @return the newly allocated buffer state object. */ YY_BUFFER_STATE yy_scan_buffer (char * base, yy_size_t size ) { YY_BUFFER_STATE b; if ( size < 2 || base[size-2] != YY_END_OF_BUFFER_CHAR || base[size-1] != YY_END_OF_BUFFER_CHAR ) /* They forgot to leave room for the EOB's. */ return NULL; b = (YY_BUFFER_STATE) yyalloc( sizeof( struct yy_buffer_state ) ); if ( ! b ) YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" ); b->yy_buf_size = (int) (size - 2); /* "- 2" to take care of EOB's */ b->yy_buf_pos = b->yy_ch_buf = base; b->yy_is_our_buffer = 0; b->yy_input_file = NULL; b->yy_n_chars = b->yy_buf_size; b->yy_is_interactive = 0; b->yy_at_bol = 1; b->yy_fill_buffer = 0; b->yy_buffer_status = YY_BUFFER_NEW; yy_switch_to_buffer( b ); return b; } /** Setup the input buffer state to scan a string. The next call to yylex() will * scan from a @e copy of @a str. * @param yystr a NUL-terminated string to scan * * @return the newly allocated buffer state object. * @note If you want to scan bytes that may contain NUL values, then use * yy_scan_bytes() instead. */ YY_BUFFER_STATE yy_scan_string (const char * yystr ) { return yy_scan_bytes( yystr, (int) strlen(yystr) ); } /** Setup the input buffer state to scan the given bytes. The next call to yylex() will * scan from a @e copy of @a bytes. * @param yybytes the byte buffer to scan * @param _yybytes_len the number of bytes in the buffer pointed to by @a bytes. * * @return the newly allocated buffer state object. */ YY_BUFFER_STATE yy_scan_bytes (const char * yybytes, int _yybytes_len ) { YY_BUFFER_STATE b; char *buf; yy_size_t n; int i; /* Get memory for full buffer, including space for trailing EOB's. */ n = (yy_size_t) (_yybytes_len + 2); buf = (char *) yyalloc( n ); if ( ! buf ) YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" ); for ( i = 0; i < _yybytes_len; ++i ) buf[i] = yybytes[i]; buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR; b = yy_scan_buffer( buf, n ); if ( ! b ) YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" ); /* It's okay to grow etc. this buffer, and we should throw it * away when we're done. */ b->yy_is_our_buffer = 1; return b; } #ifndef YY_EXIT_FAILURE #define YY_EXIT_FAILURE 2 #endif static void yynoreturn yy_fatal_error (const char* msg ) { fprintf( stderr, "%s\n", msg ); exit( YY_EXIT_FAILURE ); } /* Redefine yyless() so it works in section 3 code. */ #undef yyless #define yyless(n) \ do \ { \ /* Undo effects of setting up yytext. */ \ int yyless_macro_arg = (n); \ YY_LESS_LINENO(yyless_macro_arg);\ yytext[yyleng] = (yy_hold_char); \ (yy_c_buf_p) = yytext + yyless_macro_arg; \ (yy_hold_char) = *(yy_c_buf_p); \ *(yy_c_buf_p) = '\0'; \ yyleng = yyless_macro_arg; \ } \ while ( 0 ) /* Accessor methods (get/set functions) to struct members. */ /** Get the current line number. * */ int yyget_lineno (void) { return yylineno; } /** Get the input stream. * */ FILE *yyget_in (void) { return yyin; } /** Get the output stream. * */ FILE *yyget_out (void) { return yyout; } /** Get the length of the current token. * */ int yyget_leng (void) { return yyleng; } /** Get the current token. * */ char *yyget_text (void) { return yytext; } /** Set the current line number. * @param _line_number line number * */ void yyset_lineno (int _line_number ) { yylineno = _line_number; } /** Set the input stream. This does not discard the current * input buffer. * @param _in_str A readable stream. * * @see yy_switch_to_buffer */ void yyset_in (FILE * _in_str ) { yyin = _in_str ; } void yyset_out (FILE * _out_str ) { yyout = _out_str ; } int yyget_debug (void) { return yy_flex_debug; } void yyset_debug (int _bdebug ) { yy_flex_debug = _bdebug ; } static int yy_init_globals (void) { /* Initialization is the same as for the non-reentrant scanner. * This function is called from yylex_destroy(), so don't allocate here. */ (yy_buffer_stack) = NULL; (yy_buffer_stack_top) = 0; (yy_buffer_stack_max) = 0; (yy_c_buf_p) = NULL; (yy_init) = 0; (yy_start) = 0; /* Defined in main.c */ #ifdef YY_STDINIT yyin = stdin; yyout = stdout; #else yyin = NULL; yyout = NULL; #endif /* For future reference: Set errno on error, since we are called by * yylex_init() */ return 0; } /* yylex_destroy is for both reentrant and non-reentrant scanners. */ int yylex_destroy (void) { /* Pop the buffer stack, destroying each element. */ while(YY_CURRENT_BUFFER){ yy_delete_buffer( YY_CURRENT_BUFFER ); YY_CURRENT_BUFFER_LVALUE = NULL; yypop_buffer_state(); } /* Destroy the stack itself. */ yyfree((yy_buffer_stack) ); (yy_buffer_stack) = NULL; /* Reset the globals. This is important in a non-reentrant scanner so the next time * yylex() is called, initialization will occur. */ yy_init_globals( ); return 0; } /* * Internal utility routines. */ #ifndef yytext_ptr static void yy_flex_strncpy (char* s1, const char * s2, int n ) { int i; for ( i = 0; i < n; ++i ) s1[i] = s2[i]; } #endif #ifdef YY_NEED_STRLEN static int yy_flex_strlen (const char * s ) { int n; for ( n = 0; s[n]; ++n ) ; return n; } #endif void *yyalloc (yy_size_t size ) { return malloc(size); } void *yyrealloc (void * ptr, yy_size_t size ) { /* The cast to (char *) in the following accommodates both * implementations that use char* generic pointers, and those * that use void* generic pointers. It works with the latter * because both ANSI C and C++ allow castless assignment from * any pointer type to void*, and deal with argument conversions * as though doing an assignment. */ return realloc(ptr, size); } void yyfree (void * ptr ) { free( (char *) ptr ); /* see yyrealloc() for (char *) cast */ } #define YYTABLES_NAME "yytables" #line 289 "lexer.l" const char *const builtinservicehelpstrings[]= { "environment", "parameter ", "version", "toplevel", "override", "shutdown", "reset", "execute", "help", 0 }; #include "parser.c" work/lexer.l0000664000000000000000000003202614163725562010242 0ustar /* * userv is copyright Ian Jackson and other contributors. * See README for full authorship information. * * 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; if not, see . */ %{ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "config.h" #include "common.h" #include "daemon.h" #include "lib.h" #include "both.h" #include "tokens.h" #define HYPHEN '-' typedef int directive_fnt(int dtoken); static directive_fnt df_reject, df_execute, df_executefrompath; static directive_fnt df_executefromdirectory, df_executebuiltin; static directive_fnt df_errorstostderr, df_errorstosyslog, df_errorstofile; static directive_fnt dfg_fdwant, dfg_setflag, dfg_lookupquotemode; static directive_fnt df_reset, df_cd, df_userrcfile, df_include; static directive_fnt df_includelookup, df_includedirectory; static directive_fnt df_message, df_error, df_quit, df_eof; static directive_fnt df_if, df_catchquit, df_errorspush; static directive_fnt dfi_includeuserrcfile, dfi_includeclientconfig; /* directive functions return: * 0 for success having scanned up to and including end of line but not beyond, * or tokv_error or tokv_quit. * They expect to parse the whitespace before their parameters (if any). */ typedef int parmcondition_fnt(int ctoken, char *const *parmvalues, int *rtrue); static parmcondition_fnt pcf_glob, pcf_range, pcf_grep; /* all conditional functions return tokv_error for failure or 0 for success * at parsing and testing, in which case *rtrue is set to 0 or 1. * On success they have scanned up to and including the condition's * terminating newline; the pcf_... functions expect to parse the whitespace * between the parameter name and the condition's arguments. * Otherwise they return tokv_error. * The parameter-based conditionals take a list of parameter values * as obtained from the parameter functions and pa_parameter, * and do _not_ free it. */ typedef int parameter_fnt(int ptoken, char ***rvalues); static parameter_fnt pf_service; static parameter_fnt pf_callinguser, pf_serviceuser; static parameter_fnt pf_callinggroup, pf_servicegroup; static parameter_fnt pf_callingusershell, pf_serviceusershell; /* Parameter functions return tokv_error or 0 for success at parsing * and determining the value, in which case *rvalues is made to be * a mallocd null-terminated array of pointers to mallocd strings. * freeparm can be used to free such an array. */ typedef int builtinserviceparse_fnt(char ***rnewargs); static builtinserviceparse_fnt bispa_none, bispa_parameter; /* These parse the arguments to a builtin service, including the * newline at the end of the line. *rnewargs will initially be * null, indicating that no arguments are to be set; the function * may store a mallocd array of mallocd strings in it, * containing the arguments it wishes to have set (null-pointer * terminated). */ static int yylex(void); /* Returns a token (which may be an eof or error exception) */ static directive_fnt *lr_dir; static parmcondition_fnt *lr_parmcond; static builtinserviceparse_fnt *lr_bispa; static builtinserviceexec_fnt *lr_bisexec; static parameter_fnt *lr_parameter; static int lr_loglevel, lr_logfacility, lr_min, lr_max, *lr_flag; static int lr_flagval, lr_controlend; static int lr_fdwant_readwrite; /* -1=never, 0=opt, 1=always */ /* Forward declarations of things used in lexer and parser */ struct parser_state { int lineno, reportlineno, notedreferer, isinternal; const char *filename; struct stat filestab; YY_BUFFER_STATE ybuf; struct parser_state *upstate; }; static struct parser_state *cstate; struct error_handling { int handling; /* One of the error handling modes tokt_ehandlemode */ int logfacility, loglevel; int filekeep; /* File is in use by higher-level errors-push, leave it open */ FILE *file; char *filename; }; static struct error_handling eh = { tokv_word_errorstostderr, 0,0,0,0,0 }; static int dequote(char *inplace); static void countnewlines(void); #define YY_NO_INPUT %} %option noyywrap %option nounput %% reject { lr_dir= df_reject; return tokv_word_reject; } execute-from-directory { lr_dir= df_executefromdirectory; return tokv_word_executefromdirectory; } execute-from-path { lr_dir= df_executefrompath; return tokv_word_executefrompath; } execute-builtin { lr_dir= df_executebuiltin; return tokv_word_executebuiltin; } errors-to-stderr { lr_dir= df_errorstostderr; return tokv_word_errorstostderr; } errors-to-syslog { lr_dir= df_errorstosyslog; return tokv_word_errorstosyslog; } errors-to-file { lr_dir= df_errorstofile; return tokv_word_errorstofile; } include-lookup-quote-old { lr_dir= dfg_lookupquotemode; return tokv_word_includelookupquoteold; } include-lookup-quote-new { lr_dir= dfg_lookupquotemode; return tokv_word_includelookupquotenew; } require-fd { lr_dir= dfg_fdwant; lr_fdwant_readwrite=1; return tokv_word_requirefd; } allow-fd { lr_dir= dfg_fdwant; lr_fdwant_readwrite=0; return tokv_word_allowfd; } null-fd { lr_dir= dfg_fdwant; lr_fdwant_readwrite=0; return tokv_word_nullfd; } reject-fd { lr_dir= dfg_fdwant; lr_fdwant_readwrite=-1; return tokv_word_rejectfd; } ignore-fd { lr_dir= dfg_fdwant; lr_fdwant_readwrite=-1; return tokv_word_ignorefd; } set-environment { lr_dir= dfg_setflag; lr_flag= &setenvironment; lr_flagval= 1; return tokv_word_setenvironment; } no-set-environment { lr_dir= dfg_setflag; lr_flag= &setenvironment; lr_flagval= 0; return tokv_word_nosetenvironment; } suppress-args { lr_dir= dfg_setflag; lr_flag= &suppressargs; lr_flagval= 1; return tokv_word_suppressargs; } no-suppress-args { lr_dir= dfg_setflag; lr_flag= &suppressargs; lr_flagval= 0; return tokv_word_nosuppressargs; } disconnect-hup { lr_dir= dfg_setflag; lr_flag= &disconnecthup; lr_flagval= 1; return tokv_word_disconnecthup; } no-disconnect-hup { lr_dir= dfg_setflag; lr_flag= &disconnecthup; lr_flagval= 0; return tokv_word_nodisconnecthup; } cd { lr_dir= df_cd; return tokv_word_cd; } user-rcfile { lr_dir= df_userrcfile; return tokv_word_userrcfile; } include { lr_dir= df_include; return tokv_word_include; } include-ifexist { lr_dir= df_include; return tokv_word_includeifexist; } include-lookup { lr_dir= df_includelookup; return tokv_word_includelookup; } include-lookup-all { lr_dir= df_includelookup; return tokv_word_includelookupall; } include-directory { lr_dir= df_includedirectory; return tokv_word_includedirectory; } message { lr_dir= df_message; return tokv_word_message; } _include-sysconfig { lr_dir= df_include; return tokv_word_includesysconfig; } _include-user-rcfile { lr_dir= dfi_includeuserrcfile; return tokv_word_includeuserrcfile; } _include-client-config { lr_dir= dfi_includeclientconfig; return tokv_word_includeclientconfig; } quit { lr_dir= df_quit; return tokv_word_quit; } eof { lr_dir= df_eof; return tokv_word_eof; } if { lr_dir= df_if; return tokv_word_if; } catch-quit { lr_dir= df_catchquit; return tokv_word_catchquit; } errors-push { lr_dir= df_errorspush; return tokv_word_errorspush; } elif { lr_controlend= tokv_word_if; return tokv_word_elif; } else { lr_controlend= tokv_word_if; return tokv_word_else; } fi { lr_controlend= tokv_word_if; return tokv_word_fi; } hctac { lr_controlend= tokv_word_catchquit; return tokv_word_hctac; } srorre { lr_controlend= tokv_word_errorspush; return tokv_word_srorre; } glob { lr_parmcond= pcf_glob; return tokv_word_glob; } range { lr_parmcond= pcf_range; return tokv_word_range; } grep { lr_parmcond= pcf_grep; return tokv_word_grep; } environment { lr_bispa= bispa_none; lr_bisexec= bisexec_environment; return tokv_word_environment; } parameter { lr_bispa= bispa_parameter; lr_bisexec= bisexec_parameter; return tokv_word_parameter; } version { lr_bispa= bispa_none; lr_bisexec= bisexec_version; return tokv_word_version; } toplevel { lr_bispa= bispa_none; lr_bisexec= bisexec_toplevel; return tokv_word_toplevel; } override { lr_bispa= bispa_none; lr_bisexec= bisexec_override; return tokv_word_override; } shutdown { lr_bispa= bispa_none; lr_bisexec= bisexec_shutdown; return tokv_word_shutdown; } reset { lr_bispa= bispa_none; lr_bisexec= bisexec_reset; lr_dir= df_reset; return tokv_word_reset; } execute { lr_bispa= bispa_none; lr_bisexec= bisexec_execute; lr_dir= df_execute; return tokv_word_execute; } help { lr_bispa= bispa_none; lr_bisexec= bisexec_help; return tokv_word_help; } service { lr_parameter= pf_service; return tokv_word_service; } calling-user { lr_parameter= pf_callinguser; return tokv_word_callinguser; } calling-group { lr_parameter= pf_callinggroup; return tokv_word_callinggroup; } calling-user-shell { lr_parameter= pf_callingusershell; return tokv_word_callingusershell; } service-user { lr_parameter= pf_serviceuser; return tokv_word_serviceuser; } service-group { lr_parameter= pf_servicegroup; return tokv_word_servicegroup; } service-user-shell { lr_parameter= pf_serviceusershell; return tokv_word_serviceusershell; } debug { lr_loglevel= LOG_DEBUG; return tokv_syslog_debug; } info { lr_loglevel= LOG_INFO; return tokv_syslog_info; } notice { lr_loglevel= LOG_NOTICE; return tokv_syslog_notice; } warn(ing)? { lr_loglevel= LOG_WARNING; return tokv_syslog_warning; } err { lr_loglevel= LOG_ERR; return tokv_syslog_err; } crit { lr_loglevel= LOG_CRIT; return tokv_syslog_crit; } alert { lr_loglevel= LOG_ALERT; return tokv_syslog_alert; } emerg|panic { lr_loglevel= LOG_EMERG; return tokv_syslog_emerg; } auth(priv)?|security { lr_logfacility= LOG_AUTHPRIV; return tokv_syslog_authpriv; } cron { lr_logfacility= LOG_CRON; return tokv_syslog_cron; } daemon { lr_logfacility= LOG_DAEMON; return tokv_syslog_daemon; } kern(el)? { lr_logfacility= LOG_KERN; return tokv_syslog_kern; } lpr { lr_logfacility= LOG_LPR; return tokv_syslog_lpr; } mail { lr_logfacility= LOG_MAIL; return tokv_syslog_mail; } news { lr_logfacility= LOG_NEWS; return tokv_syslog_news; } syslog { lr_logfacility= LOG_SYSLOG; return tokv_syslog_syslog; } user { lr_logfacility= LOG_USER; return tokv_syslog_user; } uucp { lr_logfacility= LOG_UUCP; return tokv_syslog_uucp; } local0 { lr_logfacility= LOG_LOCAL0; return tokv_syslog_local0; } local1 { lr_logfacility= LOG_LOCAL1; return tokv_syslog_local1; } local2 { lr_logfacility= LOG_LOCAL2; return tokv_syslog_local2; } local3 { lr_logfacility= LOG_LOCAL3; return tokv_syslog_local3; } local4 { lr_logfacility= LOG_LOCAL4; return tokv_syslog_local4; } local5 { lr_logfacility= LOG_LOCAL5; return tokv_syslog_local5; } local6 { lr_logfacility= LOG_LOCAL6; return tokv_syslog_local6; } local7 { lr_logfacility= LOG_LOCAL7; return tokv_syslog_local7; } read { return tokv_word_read; } write { return tokv_word_write; } \$ { return tokv_dollar; } stdin { lr_max= lr_min= 0; return tokv_word_stdin; } stdout { lr_max= lr_min= 1; return tokv_word_stdout; } stderr { lr_max= lr_min= 2; return tokv_word_stderr; } \( { return tokv_openparen; } \) { return tokv_closeparen; } \! { return tokv_not; } \& { return tokv_and; } \| { return tokv_or; } error { lr_dir= df_error; lr_loglevel= LOG_ERR; return tokv_word_error; } [0-9]{1,8} { char *ep; lr_min=lr_max= (int)strtoul(yytext,&ep,10); assert(!*ep); return tokv_ordinal; } [0-9]{1,8}-[0-9]{1,8} { char *ep; lr_min= (int)strtoul(yytext,&ep,10); assert(*ep == HYPHEN); ep++; assert(*ep); lr_max= (int)strtoul(ep,&ep,10); assert(!*ep); if (lr_max < lr_min) return parseerrprint("fd range has min > max"); return tokv_fdrange; } [0-9]{1,8}- { char *ep; lr_min= (int)strtoul(yytext,&ep,10); assert(*ep == HYPHEN); ep++; assert(!*ep); lr_max=-1; return tokv_fdstoend; } ([\ \t]*\\[\ \t]*\n[\ \t]*)+ countnewlines(); return tokv_lwsp; [\ \t]+ return tokv_lwsp; [\ \t]*\n cstate->lineno++; return tokv_newline; [\ \t]*\#[^\n]*\n cstate->lineno++; return tokv_newline; [\ \t]*\#[^\n]* return parseerrprint("missing newline at eof after comment"); \"([^\\\"\n]|\\[a-z]|\\[0-9]{3}|\\x[0-9A-Fa-f]{2}|\\[[:punct:]]|\\[ \t]*\n)*\" { countnewlines(); return dequote(yytext); } [^\ \t\n\\\"]+ return tokv_barestring; <> return tokv_eof; \" return parseerrprint("misquoted or unterminated string"); \\ return parseerrprint("unexpected backslash"); . abort(); /* expect lex warning "rule cannot be matched" */ %% const char *const builtinservicehelpstrings[]= { "environment", "parameter ", "version", "toplevel", "override", "shutdown", "reset", "execute", "help", 0 }; #include "parser.c" work/lexer.l.m40000664000000000000000000001444114163725562010562 0ustar dnl userv - lexer.l.m4 dnl lexer, passed through m4 with defs from langauge.i4 /* * userv is copyright Ian Jackson and other contributors. * See README for full authorship information. * * 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; if not, see . */ %{ include(language.i4) #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "config.h" #include "common.h" #include "daemon.h" #include "lib.h" #include "both.h" #include "tokens.h" #define HYPHEN '-' typedef int directive_fnt(int dtoken); static directive_fnt df_reject, df_execute, df_executefrompath; static directive_fnt df_executefromdirectory, df_executebuiltin; static directive_fnt df_errorstostderr, df_errorstosyslog, df_errorstofile; static directive_fnt dfg_fdwant, dfg_setflag, dfg_lookupquotemode; static directive_fnt df_reset, df_cd, df_userrcfile, df_include; static directive_fnt df_includelookup, df_includedirectory; static directive_fnt df_message, df_error, df_quit, df_eof; static directive_fnt df_if, df_catchquit, df_errorspush; static directive_fnt dfi_includeuserrcfile, dfi_includeclientconfig; /* directive functions return: * 0 for success having scanned up to and including end of line but not beyond, * or tokv_error or tokv_quit. * They expect to parse the whitespace before their parameters (if any). */ typedef int parmcondition_fnt(int ctoken, char *const *parmvalues, int *rtrue); static parmcondition_fnt pcf_glob, pcf_range, pcf_grep; /* all conditional functions return tokv_error for failure or 0 for success * at parsing and testing, in which case *rtrue is set to 0 or 1. * On success they have scanned up to and including the condition's * terminating newline; the pcf_... functions expect to parse the whitespace * between the parameter name and the condition's arguments. * Otherwise they return tokv_error. * The parameter-based conditionals take a list of parameter values * as obtained from the parameter functions and pa_parameter, * and do _not_ free it. */ typedef int parameter_fnt(int ptoken, char ***rvalues); static parameter_fnt pf_service; static parameter_fnt pf_callinguser, pf_serviceuser; static parameter_fnt pf_callinggroup, pf_servicegroup; static parameter_fnt pf_callingusershell, pf_serviceusershell; /* Parameter functions return tokv_error or 0 for success at parsing * and determining the value, in which case *rvalues is made to be * a mallocd null-terminated array of pointers to mallocd strings. * freeparm can be used to free such an array. */ typedef int builtinserviceparse_fnt(char ***rnewargs); static builtinserviceparse_fnt bispa_none, bispa_parameter; /* These parse the arguments to a builtin service, including the * newline at the end of the line. *rnewargs will initially be * null, indicating that no arguments are to be set; the function * may store a mallocd array of mallocd strings in it, * containing the arguments it wishes to have set (null-pointer * terminated). */ static int yylex(void); /* Returns a token (which may be an eof or error exception) */ static directive_fnt *lr_dir; static parmcondition_fnt *lr_parmcond; static builtinserviceparse_fnt *lr_bispa; static builtinserviceexec_fnt *lr_bisexec; static parameter_fnt *lr_parameter; static int lr_loglevel, lr_logfacility, lr_min, lr_max, *lr_flag; static int lr_flagval, lr_controlend; static int lr_fdwant_readwrite; /* -1=never, 0=opt, 1=always */ /* Forward declarations of things used in lexer and parser */ struct parser_state { int lineno, reportlineno, notedreferer, isinternal; const char *filename; struct stat filestab; YY_BUFFER_STATE ybuf; struct parser_state *upstate; }; static struct parser_state *cstate; struct error_handling { int handling; /* One of the error handling modes tokt_ehandlemode */ int logfacility, loglevel; int filekeep; /* File is in use by higher-level errors-push, leave it open */ FILE *file; char *filename; }; static struct error_handling eh = { tokv_word_errorstostderr, 0,0,0,0,0 }; static int dequote(char *inplace); static void countnewlines(void); #define YY_NO_INPUT %} %option noyywrap %option nounput %% dnl simple words undivert(3) changequote({*,*}) {* [0-9]{1,8} { char *ep; lr_min=lr_max= (int)strtoul(yytext,&ep,10); assert(!*ep); return tokv_ordinal; } [0-9]{1,8}-[0-9]{1,8} { char *ep; lr_min= (int)strtoul(yytext,&ep,10); assert(*ep == HYPHEN); ep++; assert(*ep); lr_max= (int)strtoul(ep,&ep,10); assert(!*ep); if (lr_max < lr_min) return parseerrprint("fd range has min > max"); return tokv_fdrange; } [0-9]{1,8}- { char *ep; lr_min= (int)strtoul(yytext,&ep,10); assert(*ep == HYPHEN); ep++; assert(!*ep); lr_max=-1; return tokv_fdstoend; } ([\ \t]*\\[\ \t]*\n[\ \t]*)+ countnewlines(); return tokv_lwsp; [\ \t]+ return tokv_lwsp; [\ \t]*\n cstate->lineno++; return tokv_newline; [\ \t]*\#[^\n]*\n cstate->lineno++; return tokv_newline; [\ \t]*\#[^\n]* return parseerrprint("missing newline at eof after comment"); \"([^\\\"\n]|\\[a-z]|\\[0-9]{3}|\\x[0-9A-Fa-f]{2}|\\[[:punct:]]|\\[ \t]*\n)*\" { countnewlines(); return dequote(yytext); } [^\ \t\n\\\"]+ return tokv_barestring; <> return tokv_eof; \" return parseerrprint("misquoted or unterminated string"); \\ return parseerrprint("unexpected backslash"); . abort(); /* expect lex warning "rule cannot be matched" */ *} changequote(`,') %% const char *const builtinservicehelpstrings[]= { undivert(5)dnl 0 }; ` #include "parser.c" ' divert(-1) undivert work/lib.c0000664000000000000000000000520514163725562007657 0ustar /* * userv - lib.c * useful utility routines, used in daemon, but not very dependent on it * * userv is copyright Ian Jackson and other contributors. * See README for full authorship information. * * 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; if not, see . */ #include #include #include #include #include #include #include #include #include "config.h" #include "common.h" #include "lib.h" #include "both.h" char *xstrcat3save(const char *a, const char *b, const char *c) { char *r; r= xmalloc(strlen(a)+strlen(b)+strlen(c)+1); strcpy(r,a); strcat(r,b); strcat(r,c); return r; } char *xstrsubsave(const char *begin, int len) { char *r; r= xmalloc(len+1); memcpy(r,begin,len); r[len]= 0; return r; } int makeroom(char **buffer, int *size, int needed) { if (needed > MAX_GENERAL_STRING) return -1; if (*size >= needed) return 0; *buffer= xrealloc(*buffer,needed); *size= needed; return 0; } void vsnyprintf(char *buffer, size_t size, const char *fmt, va_list al) { vsnprintf(buffer,size,fmt,al); buffer[size-1]= 0; } void snyprintf(char *buffer, size_t size, const char *fmt, ...) { va_list al; va_start(al,fmt); vsnyprintf(buffer,size,fmt,al); va_end(al); } void strnycpy(char *dest, const char *src, size_t size) { strncpy(dest,src,size-1); dest[size-1]= 0; } void strnytcat(char *dest, const char *src, size_t size) { size_t l; l= strlen(dest); strnycpy(dest+l,src,size-l); } void vsnytprintfcat(char *buffer, size_t size, const char *fmt, va_list al) { size_t l; l= strlen(buffer); vsnyprintf(buffer+l,size-l,fmt,al); } void snytprintfcat(char *buffer, size_t size, const char *fmt, ...) { va_list al; va_start(al,fmt); vsnytprintfcat(buffer,size,fmt,al); va_end(al); } #ifndef HAVE_SETENV int setenv(const char *name, const char *value, int overwrite) { char *buffer= 0; assert(overwrite==1); buffer= xmalloc(strlen(name)+strlen(value)+2); sprintf(buffer,"%s=%s",name,value); return putenv(buffer); } #endif /* HAVE_SETENV */ work/lib.h0000664000000000000000000000457714163725562007677 0ustar /* * userv - lib.c * useful utility routines' imports and exports, used in daemon * * userv is copyright Ian Jackson and other contributors. * See README for full authorship information. * * 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; if not, see . */ #ifndef LIB_H #define LIB_H char *xstrcat3save(const char *a, const char *b, const char *c); char *xstrsubsave(const char *begin, int len); void miscerror(const char *what) NONRETURNING; int makeroom(char **buffer, int *size, int needed); /* makeroom returns -1 if needed was far too large; otherwise returns 0. */ /* It doesn't appear to be documented whether [v]snprintf put a null * in if they overrun. GNU libc does, but I don't want to rely on * that. * So here are some functions that always do, regardless - including * versions of strcat and strcpy. The ...nyt...cat functions take the * maximum length of the resulting buffer as size parameter, rather * than the maximum length of the added portion. * * So, * ...n... specify copied length (inc. any null), may or may not null-terminate * ...ny... specify copied length (inc. null) and always null-terminate * ...nyt...cat specify total buffer length and always null-terminate */ /* Function names best pronounced with a Russian accent. */ void vsnyprintf(char *buffer, size_t size, const char *fmt, va_list al); void snyprintf(char *buffer, size_t size, const char *fmt, ...) PRINTFFORMAT(3,4); void strnycpy(char *dest, const char *src, size_t size); void vsnytprintfcat(char *buffer, size_t size, const char *fmt, va_list al); void snytprintfcat(char *buffer, size_t size, const char *fmt, ...) PRINTFFORMAT(3,4); void strnytcat(char *dest, const char *src, size_t size); #ifndef HAVE_SETENV int setenv(const char *name, const char *value, int overwrite); #endif /* HAVE_SETENV */ #endif /* LIB_H */ work/overlord.c0000664000000000000000000003015614163725562010750 0ustar /* * userv - overlord.c * daemon main program, collects request and forks handlers * * userv is copyright Ian Jackson and other contributors. * See README for full authorship information. * * 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; if not, see . */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "config.h" #include "common.h" #include "daemon.h" pid_t overlordpid; static pid_t checkpid= -1, detachpid= -1; static sig_atomic_t needcheck= 1; /* 2 means we half-expect the server to be down */ static void checkstalepipes(void) { /* There is an unimportant race here. If there is a stale pipe but * another pair of processes with the same pids is about to create a * new one we can check that the pipe is stale before they recreate * it but then only remove it afterwards; then we remove the pipe * they're actually using causing that invocation to fail with * ENOENT on the pipe. However, this can only happen if things are * already shafted, because we check for stale pipes at startup * before any children have been started, and then only when a child * dies unhelpfully - and we actually have to have some stale pipes * for the race to exist. */ DIR *dir; struct dirent *de; struct stat stab; time_t now; unsigned long timediff; int r; if (time(&now) == -1) { syslog(LOG_ERR,"get current time: %m"); return; } dir= opendir("."); if (!dir) { syslog(LOG_ERR,"open directory " VARDIR ": %m"); return; } while ((errno=0, de= readdir(dir))) { if (fnmatch(PIPEPATTERN,de->d_name,FNM_PATHNAME|FNM_PERIOD)) continue; r= lstat(de->d_name,&stab); if (r && errno==ENOENT) continue; if (r) { syslog(LOG_ERR,"could not stat `" VARDIR "/%s': %m",de->d_name); continue; } timediff= (unsigned long)now - (unsigned long)stab.st_ctime; if (timediff >= (~0UL>>1) || timediff < 3600) continue; if (unlink(de->d_name) && errno!=ENOENT) syslog(LOG_ERR,"could not remove stale pipe `%s': %m",de->d_name); } if (errno) syslog(LOG_ERR,"read directory " VARDIR ": %m"); if (closedir(dir)) syslog(LOG_ERR,"close directory " VARDIR ": %m"); } static void sighandler_chld(int x) { pid_t r; int status, es; es= errno; for (;;) { r= waitpid((pid_t)-1,&status,WNOHANG); if (!r || (r==-1 && errno==ECHILD)) break; if (r==-1) { syslog(LOG_ERR,"wait in sigchild handler gave error: %m"); break; } if (r==detachpid) { if (WIFEXITED(status) && WEXITSTATUS(status)==4) _exit(4); fprintf(stderr,"uservd: detaching child failed with unexpected code %d\n",status); exit(6); } if (r==checkpid) { if (WIFEXITED(status)) { if (!WEXITSTATUS(status)) { syslog(LOG_WARNING,"no longer the uservd - exiting"); _exit(2); } else if (WEXITSTATUS(status)!=1) { syslog(LOG_ERR,"check pid %ld exited with status %d", (long)checkpid,WEXITSTATUS(status)); } } else if (WIFSIGNALED(status)) { if (WTERMSIG(status) == SIGALRM && !WCOREDUMP(status)) { syslog(LOG_WARNING,"check timed out; no longer the uservd - exiting"); _exit(2); } else { syslog(LOG_ERR,"check pid %ld %s due to signal %s", (long)checkpid, WCOREDUMP(status) ? "dumped core" : "died", strsignal(WTERMSIG(status))); } } else { syslog(LOG_ERR,"check pid %ld died due to unknown reason, code %d", (long)checkpid,status); } checkpid= -1; alarm(USERVD_MYSELF_CHECK); } else { if (WIFSIGNALED(status)) { syslog(LOG_ERR,"call pid %ld %s due to signal %s", (long)r, WCOREDUMP(status) ? "dumped core" : "died", strsignal(WTERMSIG(status))); } else if (!WIFEXITED(status)) { syslog(LOG_ERR,"call pid %ld died due to unknown reason, code %d", (long)r,status); } else if (WEXITSTATUS(status)==10) { needcheck= 2; } else if (WEXITSTATUS(status)>12) { if (WEXITSTATUS(status)>24) syslog(LOG_ERR,"call pid %ld exited with status %d >24", (long)r,WEXITSTATUS(status)); checkstalepipes(); needcheck= 1; } } } errno= es; return; } static void sighandler_usr1(int x) { _exit(0); } static void sighandler_alrm(int x) { needcheck= 1; } static void sighandler_termint(int sig) { syslog(LOG_NOTICE,"terminating due to signal %s",strsignal(sig)); _exit(1); } static void blocksignals(int how) { int r; sigset_t set; sigemptyset(&set); sigaddset(&set,SIGCHLD); sigaddset(&set,SIGALRM); sigaddset(&set,SIGTERM); sigaddset(&set,SIGINT); r= sigprocmask(how,&set,0); assert(!r); } static void NONRETURNING docheck(int needwanted) { #ifndef DEBUG /* This subprocess exits with status 0 if the parent should die, * 1 if it should not, and something else if it fails horribly. */ int sfd, r, remain; unsigned char *p; struct opening_msg opening_mbuf; struct request_msg request_mbuf; unsigned long endmagic; struct sigaction sig; struct sockaddr_un ssockname; openlog(USERVDCHECK_LOGIDENT,LOG_NDELAY|LOG_PID,USERVD_LOGFACILITY); sigemptyset(&sig.sa_mask); sig.sa_flags= 0; sig.sa_handler= SIG_IGN; if (sigaction(SIGPIPE,&sig,0)) { syslog(LOG_ERR,"ignore sigpipe"); exit(1); } sig.sa_handler= SIG_DFL; if (sigaction(SIGALRM,&sig,0)) { syslog(LOG_ERR,"default sigalarm"); exit(1); } sfd= socket(AF_UNIX,SOCK_STREAM,0); if (!sfd) { syslog(LOG_ERR,"ignore sigpipe"); exit(1); } assert(sizeof(ssockname.sun_path) > sizeof(RENDEZVOUS)); ssockname.sun_family= AF_UNIX; strcpy(ssockname.sun_path,RENDEZVOUS); r= connect(sfd,(struct sockaddr*)&ssockname,sizeof(ssockname)); if (r) { if (errno == ECONNREFUSED || errno == ENOENT) { if (needwanted != 2) syslog(LOG_WARNING,"real uservd daemon is not running: %m"); exit(0); } syslog(LOG_ERR,"unable to connect to uservd daemon: %m"); exit(1); } alarm(USERVD_MYSELF_TIMEOUT); remain= sizeof(opening_mbuf); p= (unsigned char*)&opening_mbuf; while (remain) { r= read(sfd,p,remain); if (r<0) { syslog(LOG_ERR,"read from server: %m"); exit(1); } if (r==0) { syslog(LOG_ERR,"unexpected EOF from server"); exit(1); } remain-= r; p+= r; } if (opening_mbuf.magic != OPENING_MAGIC) { syslog(LOG_WARNING,"magic number mismatch"); exit(0); } if (memcmp(opening_mbuf.protocolchecksumversion,protocolchecksumversion,PCSUMSIZE)) { syslog(LOG_WARNING,"protocol checksum mismatch"); exit(0); } if (opening_mbuf.overlordpid != overlordpid) { syslog(LOG_WARNING,"overlord pid mismatch"); exit(0); } memset(&request_mbuf,0,sizeof(request_mbuf)); request_mbuf.magic= REQUEST_MAGIC; request_mbuf.clientpid= -1; request_mbuf.serviceuserlen= 0; request_mbuf.servicelen= 0; request_mbuf.loginnamelen= 0; request_mbuf.spoofed= 0; request_mbuf.cwdlen= 0; request_mbuf.overridelen= -1; request_mbuf.callinguid= -1; request_mbuf.ngids= 0; request_mbuf.nreadfds= 0; request_mbuf.nwritefds= 0; request_mbuf.nargs= 0; request_mbuf.nvars= 0; r= write(sfd,&request_mbuf,sizeof(request_mbuf)); if (r==sizeof(request_mbuf)) { endmagic= REQUEST_END_MAGIC; r= write(sfd,&endmagic,sizeof(endmagic)); (void)r; } syslog(LOG_NOTICE,"uservd[%ld] is running",(long)overlordpid); #endif exit(1); } static void NONRETURNING startupsyscallerr(const char *what) { fprintf(stderr, "uservd: system call failed during startup:\n" "uservd: %s: %s\n", what,strerror(errno)); exit(4); } int main(int argc, char *const *argv) { int mfd, sfd, nfd, e, r, becomedaemon; socklen_t csocklen; struct sigaction sigact; struct sockaddr_un ssockname, csockname; pid_t child, parentpid, sid; #ifdef NDEBUG abort(); /* Do not disable assertions in this security-critical code ! */ #endif becomedaemon= 0; if (argv[1] && !strcmp(argv[1],"-daemon")) { becomedaemon= 1; argv++; argc--; } if (argc>1) { fputs("usage: uservd [-daemon]\n",stderr); exit(3); } openlog(USERVD_LOGIDENT,LOG_NDELAY|LOG_PID,USERVD_LOGFACILITY); if (chdir(VARDIR)) startupsyscallerr("cannot change to " VARDIR); checkstalepipes(); overlordpid= parentpid= getpid(); if (parentpid==-1) startupsyscallerr("cannot getpid"); mfd= socket(AF_UNIX,SOCK_STREAM,0); if (mfd<0) startupsyscallerr("cannot create master socket"); assert(sizeof(ssockname.sun_path) > sizeof(RENDEZVOUS)); ssockname.sun_family= AF_UNIX; strcpy(ssockname.sun_path,RENDEZVOUS); unlink(RENDEZVOUS); r= bind(mfd,(struct sockaddr*)&ssockname,sizeof(ssockname)); if (r) startupsyscallerr("cannot bind master socket"); if (listen(mfd,5)) startupsyscallerr("cannot listen on master socket"); sigemptyset(&sigact.sa_mask); sigaddset(&sigact.sa_mask,SIGCHLD); sigaddset(&sigact.sa_mask,SIGALRM); sigact.sa_flags= SA_NOCLDSTOP; sigact.sa_handler= sighandler_chld; if (sigaction(SIGCHLD,&sigact,0)) startupsyscallerr("cannot setup sigchld handler"); sigact.sa_handler= sighandler_alrm; if (sigaction(SIGALRM,&sigact,0)) startupsyscallerr("cannot setup sigalrm handler"); if (becomedaemon) { sigact.sa_handler= sighandler_usr1; if (sigaction(SIGUSR1,&sigact,0)) startupsyscallerr("cannot setup sigusr1 handler"); detachpid= fork(); if (detachpid==-1) startupsyscallerr("cannot fork to detach"); if (detachpid) { pause(); fputs("uservd: pause unexpectedly returned during detach\n",stderr); exit(4); } sigact.sa_handler= SIG_DFL; if (sigaction(SIGUSR1,&sigact,0)) startupsyscallerr("cannot restore sigusr1"); } sigact.sa_handler= sighandler_termint; if (sigaction(SIGTERM,&sigact,0)) startupsyscallerr("cannot setup sigterm handler"); if (sigaction(SIGINT,&sigact,0)) startupsyscallerr("cannot setup sigint handler"); if (becomedaemon) { nfd= open("/dev/null",O_RDWR); if (nfd<0) startupsyscallerr("cannot open /dev/null"); sid= setsid(); if (sid == -1) startupsyscallerr("cannot create new session"); overlordpid= getpid(); if (overlordpid == -1) startupsyscallerr("getpid after detach"); if (dup2(nfd,0)<0 || dup2(nfd,1)<0) startupsyscallerr("cannot dup /dev/null for stdin/out"); r= kill(parentpid,SIGUSR1); if (r) startupsyscallerr("send SIGUSR1 to detach"); r= dup2(nfd,2); if (r<0) { syslog(LOG_CRIT,"cannot dup /dev/null for stderr: %m"); exit(5); } close(nfd); } syslog(LOG_NOTICE,"started"); for (;;) { if (needcheck) { while (checkpid==-1) { checkpid= fork(); if (checkpid!=-1) { if (!checkpid) docheck(needcheck); break; } else if (errno==EAGAIN) { syslog(LOG_ERR,"fork for check - will wait and retry: %m"); alarm(USERVD_CHECKFORK_RETRY); break; } else if (errno!=EINTR) { syslog(LOG_CRIT,"fork for check: %m"); exit(5); } } needcheck= 0; } csocklen= sizeof(csockname); blocksignals(SIG_UNBLOCK); sfd= accept(mfd,(struct sockaddr*)&csockname,&csocklen); e= errno; blocksignals(SIG_BLOCK); if (sfd<0) { errno= e; if (errno == EINTR) continue; if (errno == ENOMEM || errno == EPROTO || errno == EAGAIN) { syslog(LOG_ERR,"unable to accept connection: %m"); continue; } else { syslog(LOG_CRIT,"unable to accept new connections: %m"); exit(5); } } child= nondebug_fork(); if (child == (pid_t)-1) { syslog(LOG_ERR,"unable to fork server: %m"); close(sfd); continue; } if (!child) { close(mfd); closelog(); blocksignals(SIG_UNBLOCK); servicerequest(sfd); } close(sfd); } } work/overview.fig0000664000000000000000000000664014163725562011306 0ustar #FIG 3.2 Landscape Center Inches A4 100.00 Single 0 1200 2 2 1 2 1 -1 7 0 0 -1 3.000 0 0 -1 1 0 2 0 0 1.00 60.00 120.00 3375 1875 3375 2475 2 1 2 1 -1 7 0 0 -1 3.000 0 0 -1 1 1 2 0 0 1.00 60.00 120.00 0 0 1.00 60.00 120.00 4159 2999 6075 3000 2 1 2 1 -1 7 0 0 -1 3.000 0 0 -1 1 0 2 0 0 1.00 60.00 120.00 3375 3525 3375 4350 2 2 0 1 0 7 0 0 -1 0.000 0 0 -1 0 0 5 2700 4425 4125 4425 4125 5025 2700 5025 2700 4425 2 2 0 1 0 7 0 0 -1 0.000 0 0 -1 0 0 5 2700 4575 4125 4575 4125 5175 2700 5175 2700 4575 2 1 2 1 -1 7 0 0 -1 3.000 0 0 -1 1 0 2 0 0 1.00 60.00 120.00 6900 3525 6900 5775 2 2 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 5 2700 2533 4125 2533 4125 3465 2700 3465 2700 2533 2 2 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 5 2700 900 4125 900 4125 1834 2700 1834 2700 900 2 2 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 5 6176 2533 7650 2533 7650 3465 6176 3465 6176 2533 2 2 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 5 6176 5815 7650 5815 7650 6749 6176 6749 6176 5815 3 2 1 1 -1 7 0 0 -1 4.000 0 0 0 6 825 5250 1875 5250 2700 5475 4800 5550 7875 5400 8850 5250 0.000 -1.000 -1.000 -1.000 -1.000 0.000 3 2 1 1 -1 7 0 0 -1 4.000 0 0 0 11 4650 6750 4575 5025 4275 4200 3000 3900 2400 3525 2400 2475 2775 2100 4800 2025 7500 2100 8175 2325 8850 2475 0.000 -1.000 -1.000 -1.000 -1.000 -1.000 -1.000 -1.000 -1.000 -1.000 0.000 3 0 2 1 -1 7 0 0 -1 3.000 0 0 1 4 0 0 1.00 60.00 120.00 2625 4725 2025 4725 1575 4500 750 4500 0.000 1.000 1.000 0.000 3 0 2 1 -1 7 0 0 -1 3.000 0 0 1 6 0 0 1.00 60.00 120.00 4200 4650 4650 4650 4950 5025 5100 6150 5550 6300 6075 6300 0.000 1.000 1.000 1.000 1.000 0.000 3 0 2 1 -1 7 0 0 -1 3.000 0 1 0 6 0 0 1.00 60.00 120.00 4200 4800 4650 4800 4950 5175 5100 6300 5550 6450 6075 6450 0.000 1.000 1.000 1.000 1.000 0.000 3 0 2 1 -1 7 0 0 -1 3.000 0 1 0 4 0 0 1.00 60.00 120.00 2625 4575 2025 4575 1575 4350 750 4350 0.000 1.000 1.000 0.000 4 0 -1 0 0 1 16 0.0000 4 225 885 3460 2300 fork/exec\001 4 0 -1 0 0 1 16 0.0000 4 225 885 3460 3825 fork/exec\001 4 0 -1 0 0 12 19 0.0000 4 165 495 3075 4800 cat\001 4 0 -1 0 0 12 19 0.0000 4 165 495 3075 4950 cat\001 4 0 -1 0 0 16 15 0.0000 4 165 675 1425 5175 trusted\001 4 0 -1 0 0 16 19 0.0000 4 270 2520 1275 6525 unrelated processes\001 4 0 -1 0 0 16 15 0.0000 4 165 915 1050 5475 untrusted\001 4 0 -1 0 0 16 15 0.0000 4 210 3240 975 5775 invoking user's security boundary\001 4 0 -1 0 0 16 19 0.0000 4 210 585 7800 4725 TCB\001 4 0 -1 0 0 16 19 0.0000 4 210 885 7800 6000 service\001 4 0 -1 0 0 16 19 0.0000 4 150 525 7875 6225 user\001 4 0 -1 0 0 16 15 0.0000 4 165 915 7950 2175 untrusted\001 4 0 -1 0 0 16 19 0.0000 4 270 1635 5475 1500 invoking user\001 4 0 -1 0 0 1 16 0.0000 4 225 1515 4875 4875 pipes (set up by\001 4 0 -1 0 0 1 16 0.0000 4 210 1575 5025 5100 client+daemon)\001 4 0 -1 0 0 1 16 0.0000 4 225 885 5925 3758 fork/exec\001 4 0 -1 0 0 0 20 0.0000 4 195 975 6422 3058 Daemon\001 4 0 -1 0 0 0 20 0.0000 4 195 975 6422 6516 program\001 4 0 -1 0 0 0 20 0.0000 4 195 840 6422 6282 Service\001 4 0 -1 0 0 0 20 0.0000 4 195 705 2993 3058 Client\001 4 0 -1 0 0 0 20 0.0000 4 195 705 3000 1425 Caller\001 4 0 -1 0 0 16 15 0.0000 4 165 675 7050 2325 trusted\001 4 0 -1 0 0 1 16 0.0000 4 165 600 4800 2942 socket\001 4 0 -1 0 0 1 16 0.0000 4 225 2070 750 4275 or passed from caller\001 4 0 -1 0 0 1 16 0.0000 4 225 285 825 3825 fds\001 4 0 -1 0 0 1 16 0.0000 4 225 1590 825 4050 opened by client\001 4 0 -1 0 0 16 15 0.0000 4 210 3165 5700 1950 service user's security boundary\001 work/overview.pdf0000664000000000000000000004367514163725562011323 0ustar %PDF-1.7 %Çì¢ 5 0 obj <> stream xœ…[K“^·qÝϯøv¶“ân<¶vRÞdc‰UYÈYPäH¡Ä!i’r¢Ÿîs÷^ I¥\2ï¼FŸÆ¾ÜÒ}¾%ÿ_üûòñî›oûí§wÿ¸s<¤¤›NM·wµÖt_nµt?n†K¶Ào 'C£uËä¨4K›HäLûï»ÿü—ÛÛ»ïoóVúí¿üÿ^ÝɽÞþÇZý+‹Je#^ÍP+öÝÝß¶\g•Ÿ5wíÊw_Ø¿>é‚ Ü£‘ѪNÔ«Y¨§kÚµ[X¶Ý‹wfa«33ú¸oÈoÿ8N ¸§À‘®ø‹óc•zíQÈ;,muÈgf¯äñëD'¾Û†ñøµ!êWg0ì¡4Õ«=ŽE(]Êi¥õtÚÑöåñbE³VPZ;Æz)þøYÕ×f¿C¿ÓíÛ¿Þ•Yò­«pصaßÅŸs{òç/ XEܼòHÜ*µÙGà7†K54hu–;ÊHç™öÅ»Q£P :*HËô™~VóøY׿c`5ÏŒ©Îû<çeÌ’Û4K@bK÷u&j¢á ä$l¥#C.Å-ëÈr­ã{›HW²a•ÛÏwÙl×æØæòÑ¿»›‰£7w1yŽ`•ïe_³«B4˜7c¾ó(Ãv„á T'Sk”Uÿ0,‘» b¦eYNWž hâ»TÔTS¤‰ûÃÙŠ8Æ>7Ìíšç`͵¢¥’2r+¾+R9Kj‰9[äÊ–眙ÞÑ’}Œ[Ë劧^J›q_Ú2KgYaÞ2ÆÙçRaõ1ÂR•ýˆÙ(u¦5wÀRÚZ±âÒQÖ¤© lšÌ«•u¥˜ m6WiöB‡wÝp!nÉêJöGÔÕ²Wb¸°l³v܉jõ嘆U_XÃ1Kõ~¥Ö¢®šˆ+kB¯’2Ûõñ'm2æ5éj7”•¹0¬4I‹¶rÆ($f$Õ¾zíiµ®~ÀÞS‘ª¹ÍÈØöðÜi=wÿ¦•®,™”Øö†û›9{1ÌšÄqfK¾«Íaw³eä]䜒(Ïôœ¤¢lg/ÍiV¦[Øî6Ôz Hmg8œ{)^—r¶jÁ4¦•ÖÒ'r+-ÓVÛ’ÔÕ6p† }sÝk6íã:b¦ºæW½Î®1\b*WÉ–¡­ÍóºÚ¢=/»÷$6„´Ö:,Ì¿{Ô©•i}Ù+=¥t8'ÃÜí2Ê<­9"#ÃŒ£dÌÆ½˜>K`îJ™1žFß"¾%‘î¹Kµµ ñT8ÓžIÝ]v¢¦ÆqµùW¢q¦5'î€ØÇš ­¾sv5ÇÞê%ò+ë ? ¹ûŒ)ƒûk0ÆÊðq3".€–ÿSéôJ“žUuùK¤¶2Óc.7ÿêv©-Ã×V|ƒ&Ï«=9;$zíþO9Æåöâ=ÓŸéÀ4ܲK¡…è ¦ PŸ ¯¯pÍ[*`“„ïIF¬ìIËŒ=’#Z)d“`&#ÌB&ãœ4ÒÇÉtÞÓX‘»¯Ù|"‹úE‚E¹†M`8ë6™l¿s743`ÛàŽÐMCä ; pdƒÖÚ´9ƒÏh[Q©a Ú7ÜÏäqDZ¨1ªj7&rŠaÆli5 Ì7Ì8*sf¬˜™Šl†4RuŸßÑÿ]óÍhƒ±*Ï(bƒD„ì'+~#ôoÄÎÞ`áž2‘YéO\³n鯂WÌ l_‡^D®Œl8¼P¤îÞUºq¯ëê \ña…†óc‹o$·œÞ¢nE$h‘9y°ñˆéß ÃRS0—mhÏY5x"!þ°P{õ2{ƒf\øZ ¶S”NØç2V¯0X ¾—Ý$ìk-}Ç‹e“ŸoT·²ÇÚ°n]Ò‡96G«æl{Vƒ? yÎ` ñIôzû²Î‚]©}õ²x;}Æ7Zk fŽ‚K]sµê¹Í®ñÀï´Lk«¬k¡vÖÇ&?:yº>®Núë6r¤Û±ô8ŸÔá~¥ÇÉÇâGŠˆËN”öݘ‹'€>"zìFñã+±-z9¢Ç^,P;OH£¶ˆÜ:,c¬HÔëßÀêÔ†›¡ˆžZìGïÍG,îq¡×Cµójo˜•H%ªQvåÉF9ÊÑÉNösEùB³žÜŽ8×ú9#aF½‚´vÄÖ÷™7Lj»pp殈.½¦ˆøu°—h·â€{Ž¿òÌìÞ€§ëK|3û34rœEÈ—cD¯3ùlÄ™ªfT[f¢¬~`¶¾Ìð5'óÜ\S³v<2EN°¶G…8›MZñ8 '»év5G‰TÐw™Á„~rC«ë”<á4jZgè_[SŠs?‡c8ÎÜkÌüˆ¼®¸2?GECý¡ÐØ +‘²mÖc™ p ;Q»æ„³ñZ¢*Š)XØ6PÇwžö½ô†‘rÖèoÇî®ællw×Ô5ÒÚDÚŒ±wÅ\y ËÜKBóoJÖ9|ŽmsôЄ(›1/eÜ;&¸š+YØsOè º•™Oí­Öº¸q³Í¥>@A1SÖ•ž M~ %7-Õ#pÉK ®rÔuó µÆ ±;VËÔm‹,TÞUû)s© ðU—¦Ð`r¶ñ£¶ŽpËEè3˜•˜ hÂzÎVIG]y±2mYmÏÁ[aÍÐ)ÍÙ%"Œ±­ùéíà*£_½,‹€W¬=¼"W™÷öí›Îް3Æ@‹5/‹ñT]57O[û²÷‚¼#” nçŸ:Ó²a3?sè+}`ægè‘'žg^ª~¾úù—91Ì:#ê3œÅúvðUueâì/I+T c½O,Øëgi(;Àl[ÒŽqþÞðµ4ºl¸³laÏÆªûtêšè›Ê¹7‘3¢h¹…9’ å~úâ¾¼ìiŽ¥w ¦G„i^Ò»l¡Àһ̧"X¿õÅGxâ¾Ö!<õDÉ “Ñ É2}ü@jÛ£Ü3ñb”ä†dÁ](<¥2}ñwQ–_*TÁ†t(VØ'*BïêćÞÕÿÐÃZez0 ùа’+ ú¾Ô4Iœ•ç¶§#$¼`ˆ8,}/¯+?gO¤wödáÁy]=×”>´­ ‚"{ŽÛìliá¶Ï‹Â:¾1:¿q½s ^/ùz[-]ÚÖj_}< #Ÿ½ƒ¶±Æ4±_.xê9˜¦å|™;¨^ë»Ôq~³|Wˆœg Ç|Á:Vï+(ýè­XŽÅB0½ŽM츾æEÚˆ’q~ë%æ)NqãϾp¨`ãjÕ2”醂ìØÑŒUTóù­ø{œ2)L]ðÌ'Ò”¢ÍP^Tü –rEû>ÔÔe•¦V6óJ¦V懶¥•Ñ ï‡C#|]oŒµ…VVRY8Ô±h=”5ªcŽ:g;TOÛ1¡ÛÕð1¡ Zà^P:V5K:¡TÚQÄ jËí¨„ò•èaàïTcG”:Ø …G¥-Ú.¡Í5è48Üû-…{Zæîž7Æ9R^^Y„KJÑ'Dxôh‰Qrõ 4*_ÁMƒ³ÒÙyFì×Ò'4¿‚rÜBʘñ:C¡hž¯N¥=n‹­ qfz´–1„ƒíZ¾’¥ËÙ¾­Sj ´Ì~ß½’Ȭ·m-u22â¢ÆÀÖW>êÛµæç ‹GƵ¿KËXG;À–/ŽáîÀ•äi]ñ]ÁÓ#îÆZiÄ#5*u„±½Ùwœjì0:KÅÖˆ—">lÕçdàÞÈ<†i5cC™º!¹}ä¥#vÆh‰›£b½)z¨æ W ì{CÐDUÜÖk·ñžÄðR9º>CíS¾|è3ìF!G„²h(Í–Ö–Rؘ÷ÐY×q¸‰HàñZå O,¤Á› A”õxÁ+…à^$DÅ8™[:ÃÊ i@”.è‹Ïì,ØXà‘'9ÿŽø öÁ¡)­3LT Ö}rçM¯Ô#æ†Z •©|î!u;9`h¼ç¤.!Ø!þxuIÄnk 7½¨Ä},ëZQ©âaaD¥ŠÃ¡ˆJ—!6-ÜAEyó-Š›_sþªš ,¢qîtõ:T6bìø"-N0f•Žb>„ºtŒHšÏm^# óbÍçÇ-°¨Ž®ß1Ý_©È\·ñÓû8cžÍ‚nq­îžßpDÉQ“u=NhÇ …w÷¼ËÖuš¬ˆÉ Ç*˜nÑQxÁU‘a"· –1 K§†XÈh†c. NíEƒOùA#(y°^e_.hÄ1%k¤†-ús Cë]C¦"¹Î¸vØ?õÊ’hY =¨$e/B¥â‹ mq&Å[ ­—JƒJ'_vP³ÒÐÃò¤Ú£PËBPvÄÒƒë¯q÷–‡reByZïQNœ¢5næÜG”_˜÷Š“{î zÚB¸°9Q¹æ4Gßþ0èûxi“n??qŸ;ͽ|ù]×È4ݯٯxd„¸9yÕ"s ¨5L?.¦gÂf¿ã£¬§F¾GBÒ®»ÇoŸ±{¨r££Cën𠍄od‰¹’Ðl3Em5Ò±ù}ßÞÇíuá®÷ ~ˆ]hçá¨ãS—–¶tkj™¢Tµy_&Ê4ø[]Zy̽¬›…oÝi\½«¤ÉV+oÐëEŒ ™ïQÖºIÅŽºr,AZç0daŒSG(ü™{¦vžS¼`mµu@ÕU;_)UÞe*›µD]Å—»®;¦Â›µ2q?U¸ËX©ˆ°KY7 ¥òöd!ü”T¬¡È dÝ­˜¼™‹‰[ÛE7w1ø†ûÆ> ì2kÁÙ¯³øÞ€7 9Ç Né¼A]¼ïÄ}¦!Ü…ÆD™hÇ—<^.èy‹kˆ7µ)îFj’ó~ÛPÜÓÇœÖ|¼ Ü‘^âôUù:e̹°¿4\·„~ÊÖeáž}„Ú$vÄ7„›H©8 ÙDÅ TÍÕ…qïÆó%K—UYîug–Ü3{„kþÜSX_:æ1–E~¸î*äuã€z=åÚ‚ÅÙRp­“o5¥à&«igßq¶¿ºÌ-˜Ñb…á÷±/§?³l¾ÁµfÖÎöøvF㤠v<5çQLNÖˆDqMœ±ˆ(_'ie^OY×]¤bsg¿wcº¿UÒxƒÈ)Ê•ð‹/oeÙòm…æ˜žÝ ÃòZöZC¯7߃Wz½4¾NRèõÒpd7¶ÆiκּuÔµ^ ìµíÛé0×,3úß!g™ŒÃÅuWäOÒñ°ÀpÜjv<¿æ[h6†± Þ ËºãØï†ÃC’A/¸Çtì ;Ú8Šu™ÜC'Æ¢c ¸Yär~Çeð–øBW_"³ì~ï-y–´½%ÏunoÉsÅÓ—xhm¹/­³`Sý?li½Ay‡UgÜR }{ô8¸´ŽKë¸ri;—Ö±si;—Ö±si;—Ö¾sií;—Ó—ú!òÊ¥µ]¹´¶“KkÛ¹´ê•K† .eh|ri•+—ÖzåÒZv.­eçÒšŸpiÚ¹´ÌK˸r)å“KKÛ¹´È•KK½ri)O¸4]¹4ÏKsß¹”º—fÙ¹”¯ŸƒKÓ•KÓ¼riêW.]¯f—ž ¯‰Ê.M.õ÷Y‹KwgÁ¥ç<çÒ<ëÆ¥6Ô+—޹séè;—ݹtÔ'\š®\ÚÇÎ¥½]¹ôä@çÒ^¯\ÚóΥǛpiëW.mºsi“K[¹riË—¦+—êØ¹TûÎ¥Úv.U9¹TëÉ¥7K5o\šv. /\*ãÊ¥mŸ\*mçRi;—O^¸TäÊ¥";—J½r©Ô+—J½r©”K¥ì\êƒ_\*yçRÉ;—Ú>¾p©äK7TàRÉO¸4m\šžpizÂ¥é —¦'\šžpiÚ¸4=áÒô„KÓ.M—¦'\šžpiºpdZy%©Ç¯Éí‹ü˜ý fœ¿:p8l§â)TÃ3Û‰pÀü¹Ï‘WþU~¤ê¥…ªßph9^3ø÷¦8Þ>•]Ó²k`ë]ÕÒÀ´\50-»¦e×À´^50­»¦u×ÀB‰ Lë®i½j`Zw Le×ÀTN ìÐm ªMh`ª»v(5ÐÀTw ,´h`K]YØÒ?–¶^‹- LûU[ïÁ¨­×`¡Í'ØÜ5°õ:li`-íX˻ƟyœX+»æ?ÜXz²40^‰œ|rj`­^5°Vw ŒÆ»40瀫Öäª5Ù5°&W ¬É®5½j`M¯XÓ«Öt×À|3^5°¦»Öôª5Ý5°¦»Öt×ÀNœ¢µ];15°ØìP¶Îßù]7ÿã×Cg\žn?™ïÉü¹_üóòñöççwß|ëÄ{ŸüÍÒóïøS×ìosîý~bÞž?ÞýñÇw~ùæá^þéùÏwbéíù\ÿú«&ûO"ŽzžÙäÛ3¨å}u÷Ç—/>¡, :@gbä¶Õ{f¤Â¼Ÿ>üúñÓÃ+ÏÏ<—j-ßÈÈõëÛo^X¾Ûûï^>|üøðñ,ÁZQc«‘ýRí3ÿ¥ì3óמòúí?ßýòúíO·_?>|øÃÇÛLJ—¿~xýé·Ûï~}ûêŇ߾Ô#µ³îçù³ç±`–cõüóõË#ÛYóžôÑ3˜+ø¼‹ŸÜ"Œ{¿º¶^³À¶ÏÌÈŸù­+³¿ýþáãíïÖµO·_ßß~ø«qöíå›×o?ýë«ïÞþýOžlQ‰íPõŸ6zŽÍ¬{.àÜÏ9‡7ç>Ý3š-zÞC5ž±ø5òÀ´Ø:ýôáÅ£M‹ÇD÷I3Óå c›õž?͹Aê_Ð1O´hM”r3G7ý"É/Þ¼ùlV}FŸ©|nMû¹Kyf†žÖ?¾{ùËÃ'vÄ«07r4ôîÃíý ³²W·?¼{¼½<ÚÅvNÑ+Ø 'ÕFüîýÃ[+ðÃo7Nïnõeúêø¡ms~× ÿý¹íû¿Ýý…Ðp=endstream endobj 6 0 obj 5538 endobj 4 0 obj <> /Contents 5 0 R >> endobj 3 0 obj << /Type /Pages /Kids [ 4 0 R ] /Count 1 >> endobj 1 0 obj <> endobj 7 0 obj <>endobj 16 0 obj <> endobj 17 0 obj <> endobj 8 0 obj <> endobj 10 0 obj <> endobj 12 0 obj <> endobj 22 0 obj <> endobj 14 0 obj <> endobj 9 0 obj <> endobj 18 0 obj <>stream xœViPTW~ vódˆzZ»£éG㌷¨©1¸Å%,¢ˆ(Yzßè}»½±C³¼nDq%fŒ hfÆ£“Ê2“8•¹\§f&U3¿§nݪW÷ÝwÎyçûÎw›„1Œ—r„™Åoï¥æå¤ODRsÔ¼ êÕ`´¥O&L¾Ï¤øa aÓêç…͇W^†¥3¡t6ÁxwgbÕ¢½»÷-ŽŒ\²¹ P^”“•-ŠX±üUiòˆßÞDlÉ,ÎÉÊX@?H2ó …™ù¢Øaš¸8bw05?âWÿÿ{ô_cÿŸy øù…EÅ"qª,Mžž‘)ÈÉÍF,Z¹ Ãâ°]X<¶KÀöb‰Ø&l?¶;€mÁ¶b`Û°X4ƒÅb l:Š…a³0,lV‰=c˜Oƒ ‚¾>:5í,s5s”µ˜õÇÈ^|!~jzÈôï¦ÿ-tyhqhMèièšAYõ™$Å ‡=cö?ÍaŸ¤RàtÎÞm%Z%ÀõƲŠrwce7q ¦1ÙmŸÛ_ûÊÉÂcFÇ¢•óùŸÁ|«3Q+¶¬Rò”!Cö“Ýd7ãììHôŒ9Æ€+*ügG¯ÿuèÂI€{+´òÓCq­c²=š}Vî•ÌZeg3ùÍm>ÖG-õ1Z–‡Áð>ÃIÚ4ñüøÍ(¼†¯ºšøtäÓ¶áaþÈÍž‡`ÿKüµ5ü çL@°{cî¢v‚ÄÌ¢€Ìë¾r¯íñàçÄék}mg>e¼‘zå ƒšù$ø*µÓäð;H Pò@I6"²W´F¥ŠÖR—¤Øq%Lõ†T”ûkëÇÉq¢YÓ`i8\—Â÷àªû‡¶ìLÎ]O´ýèð8\ð\6§•og¡¥b&¬£²5»Á¶ü5)1©qÉÂ}/zý]'àìö1¢utxð‚•Ž‰HêM’_š}¾_ß{n¢ëjëñzPÜ®\Qn&Þ^×ÐÑ.óˆ U…G‰´”ôxeº:‹{ ­ÎM½mS Oâw»å÷×èäj”Ûˆõ¨ŸIÛ×rµ¤IF†CÆÝsãsØŽn¸€#E+™u¬Šz·» T IC–glòZëç>¼~yü´äÌÁa"s@yðNyâb»à•ü:{ ¦š¥W›,*`z§ÌCY^¤v*æn<˜²=×—Ò·—8TŸ òñC¼Ã{„½ß*ù3àqí ü¥ƒ©(Î{¬À3‡ЋWjs™LV»ÁÄÏØ“”«/2M@ ìÀæ°â÷X›QÀ¦·[¬žîˆ1èp‰OÙz®3ðÍ ¾¦ì@´R©<½©¬Æ€ÃM<†˜YS@_J BI-Þ77ÜŸÃΣRib'îPkhb-¥U¥4Þ!À‹Ì¬½h‘¶è£-8»~IܤܹC¥×\ñþÛêŒW L Fž:¤Ç@¥ÙcóèèÍÅúz+ÛhÊr\Ð ?ñù¥Ëp/ á ¦ÚÄ8;:¯AÑ>àoüáÖ n&“ÔÛþðú‡0éîv?•ƒ8¹¹Z½ð ¦Ò2²F À÷ W¥Ãé¬0º¸±F«U›l8™ïK<ÄCo£håÖSiŸÞ>Ó g=&$ëlP„³eùÕ%žcOÇøè=x‡Óeóƒlðn ݶg÷ç(òçf‰箞üñì ¢gø\Gïÿvi‡áÓ« j æôf“¾D$,Ñ•5Ð×Ö*à´»Š~ÒžÞþû'Î4€RPa­0WËl'k½>¿Â[|X±•Ð^QjÉBÀ\CŒÄdÀls«¸§+Ë• ”êkãÚÐLî:4]"”ɵ€g:—®TS¦sé.U«¤G•ÇWW\¿@´vúÛ{¯´£0n;U8ZŽ ?yQÄMÔ¬AÅý2MÎá\·y¬@ ô6­Qd3ÙŒvzsѼç6¦%D4.¼#áz¸ ®¸}àÂö­ûÒPÐþŒ+ôÃf7IŸoÞ¤ÇaòqζIܱ?".†d¦Hh ÉSU5]oÿ®oŒ8;Ñêü”„ìBi$õ’AÍî öRó9Õ®rGèJroëÆ‹èÈJ£R-+ˆ J4±Ö ¡ÉbriËUÕ:O ÀÅ …ø¨OÞþ)œ ÃdÈ FáÌÀ0ˆ·5 EJ•XY®#5üFm™žF!=kÃjôºâ\Õ×{àZÀ-,›Ý ,À`˜uf»Æª¶½²›"|ŒöGPw'>û™“°+C|à»súî|yâÉÕa¢­½§¡àMµ†³ÍlÑFF/öªÈÆÖÃ]±è- åK.'|3v©}â“)ÞÒržz¹)ÜûŒ¡DF¥ÓdIˆÖ×Ê«ëŽÃÐ.8hú‚¼{ÐiݧÍ2ï4âŠ+¶2+µÝªN<ŒÖr }òº €£Ùh Ú…ÞÚÒ“rsôlÇßG m’MDSL­—7÷]ê½;ÄGkámN»Í+Y4ÁÑ’7PÔ²lQKÏŸ/Àé#·ù¶“_ÿ¼Ÿú}ãøWP6  Îæ]yÊÃß#è¾âuÖ–w7|Ë÷ó8xÄë¶ìGóÑ;h-Š\yÏýÏ'z?û˜òá2N××÷&†î«Uçɲò„„ ;S¾Z‚ÓÚ…Ò}Ôƒ(ó3ÐÂϨm·‚OPœ'¬•Ï׊#Ž$¤^‰¡¬Âípº<„»Ô᥸O^/‘(å¢ì®£ý_ßúÆôñïÀ»LÈ`•v0Æjƒ+NÞ¾ ðÚr³ÆÓj!Ì»h4”þ¦Æÿ)Aëþä ñ¡,¾0]zH‰/cM‰èõ-É †EÅ):b2èt …JG×ÁPV^éª+k < 'ÓòŽYoÊdÖ +Ýž/Û+¬t{6X&Y2ÚÊUÆ™òÔIÛºÛ^ãK¨óœB©8/·QÒÖÒÔhµSÙ½˜F†³µÔ :±Y1&“œÆSÒ™ñ¹FÕ­8 Á9mäy^‡>T†œ±W[€H÷'/ݬҪéèC\³'ViÚm¤Ãt42›ÂX¨9dQ[µ6ƒMÏeG!ös)=.œ‡Ûû:ê·Ä4dóØÚèŽYÛÜÐÜ|îá Z’Ñ; ep&gçZƒAL³Ï\Z]îªñ47Ý„¸3FRãfOí/~ÊßyÒ¤°Ðš` ÿy³Ug§µ›'¨—u\ì |“?cRðbb^ ‡ÿœ€kв<¹•n³Ùl1)¤z­Ý..ÖÕt‚-ž*·»¾ô]±n‡ÇYÊxÝE­G¤R£ª˜ 7-ùÔr¿ö hÄ»EÇrb·î@o.ãÃL«s¯VbY35%£{HÝCÜFZJŠ—e£—ir‹ß·(5IøTVxOu]¼öèã+]¯)Ó+5BšŽ^# ùµæ}¥.'‡†nŽ^8Ûðª =]Í:³”ˆG ]†Ut8>psTãåÒeš´#õ£ÑÚX°l¨ŽòP›êÍíÞÿfÞ nCÛ9pĆnöC,0R}Œk†êëŠQU÷G_ÈÌÜ®õÞõ`!@ì´z?Âòw Sc?ÄgL¾ Hxp„‡é:†§9¨`,@…#°Œ X¸cŠãrr’K{™\Êy>ã_QÌ»,jÆds†¼ÚR³kXM¡÷×T†aÿR©Ï³ endstream endobj 11 0 obj <> endobj 19 0 obj <>stream xœcd`ab`ddäpÎ/-ÊL-±µH3þaú!ËÜ]ýcûc¬?äxzx»y˜»yXýx#ô½Yð{ ÿ÷rFFsßèÙ¡AášÚÚ:Îù•E™é% F†& I• P—ÔâÌô<5 £,5'¿ 75¯Ä/37©´XÁ7?/_! X!(5½4'±Ua"yv0000—$&30„281¸€}ËÀÂÁð1öǾoª÷}¸ñ»Â~æï!?ÌE¿³°/hšZUÕÔP.÷›Å½´¡¹ªjZÓBù ¿§±ÙŸŠ|»ëð´¹»å6Ìœ=£{Ç̆iµmí]­Mr)¥nÕ!ÝžI+wÉŸò=‹}á´)sæ4L.•Û‘±ï»é¾ïÜû„Îíÿ¾{øwIqá¢FbØ•Ín˜R&/\õ} Û—Ú©^u!rµm-ÍÝõµÓfLèëéŸ!wdîÖÉ«»9.îΓ÷e÷ŸUÔ×Íñ[ÌÄßH^¸ÉîLØë ‡8)'¼æ‹—x‰[7‡GâªÝG/n~¿}w[óˆ;¾¿ß—9_èÖ~qá ?Ò~ˆŠ&¯ ›4FVSç·äoÑ×úߥϷþ€üÊù³ævÏä˜Ñ0­®¹­³©I.2֯Ĺ›CÑáâ‡/W.}»{.5r¢|oùäæYÝs¦L›/ÿ”]Ø`AÓ´ªªæ†29¾êÙ?Lg›¾|Û~®}ÜÛ¦ððl›ÌÃËÀ-³ endstream endobj 13 0 obj <> endobj 20 0 obj <>stream xœUkXçžaÙ™)ÁUG4Ý-Šˆ —êr)¹I bÃM ° •[ÀDð? ‰-‰‚qÂMª‚Z¢‹@ÄKÍ"ÐX²€,b·‰ÏkiÎìóᓘ¶Oþößw™ïœ÷}Ï{΄¥A’¤UXV~I–:7#miçÂÛ‘¼½o/BXeö5—‹ù—¬ d-BÖ–Íöt ´­†Ò•°{!"IoEµsb\ÒÆM›\ƒ Ë‹r³sÔò-î¿ô”§—˼‘gçf«äN¢$+¿ P™¥RGç*Ó÷ËãÓTÅÿ{øÿ…"ÂV¥(*,*Vï-IK/ÏÈÌÊÎMÈË—ÿ‚ bGb±ˆ%â‰"‘ØI$ "ˆH!‚‰b;FD^D$EC¬!,…«’"óÉ?[ˆ,TíD?5ŠžZúZ´œûˆuâñ”NERÐ)áû‘†»—£±5NÃûF[öì(¯åµÓÐC³úï¯Î õdDJñF^NÏF\w’²î(Y™ª`æh‰Ù MAÝTNÙL˜`Âm²e&ÖÂ5‚®¾ØÓuAÓ‡Ñ\Fÿ+] Ëßí<×?ö"(ýSÖ¹Ìó)!ˆÁ:Ê„ïrP atê8ÐRÖZzR‰2PF•ò­Ò¢2Õ$á£0<ÃA”Òì”n—@Ê._™^mà] d×,ôÏŠ …ïâ°³‡Æ!sްœ.ÀVˆðzŠ]eǹ¿_ÄkñªØ@·Wâ À;h0É$æ=ê)þñyÕ$2»ðˆS§Û8öD‘~bLxP¶#ÂV[woŒýªðÛÑwß6A"³‰ªIÞŸ[©RÆDå _v" fhp¸ùE…ꌬ­¨AùQ³uœwtXÒùÚ¬-«À*nZ©Ë‰ºâaÄ€ýàÁ^`e2Ö=ÅåeF14ëH±z¨ˆäþvë5¼¿ýšû–¸IX +'Ê$0#±LsHc3"·eoüXÁúØô]úó€fÝk«jŽí·KDéy¿ `ØßÐþÈs?Ÿ…êYÁK¸£OCoà‰¤‹oO&¬RÊÆËnT5— =ë“SÞTìÎ:ÑT"Ý×p°áP7ãAÕáñð’€Ý´þÉøo?sl‘ùmT5¡îõºÏÎ ßíR%ÔJ%Щ¾Ç» “Œ"8.àó‚ >xCpè_åTb—JßôIííÒQú#ï­@LöþúnàzIº{ÉKülôF¨3n³eËø’µ¼Ö÷Òìy|ˆgxÚ¥;RžöYt¦=õñÿ²Á¤kÓ0Š%ŠËâpa-¤òZñf ;/`9 ,!rQ+^ÎÀ»ÈžY8añÐqÕïF‡£z»¡U·iSh/æ£÷ffK‹ ÷+ßKb¦©ã_^èGÌ×,H–í¥f—ï ­ÆV•å‡óöE¿•ŸŠBס˜ õ7Ü”~˜Øª@Ÿ jÛ3Ø B9TPSQ¤ÎÍO;1Yý_tµÏŸ=üøT]û‰çvIÐðQã(8Æ}‚_v ˜•Ü3åØ]šÕE_êWݳé<ˆA¯.`YÐë…;2eÐAƒÖr¦çF‰ú©Qø#X5e^£!ùuBðË‹®øEÞU¼…‚Åæ<Ÿª=åU9h}z§¶¼ŽÙJŸª>u¸ µ¡Žß75¶žnhjì*³dÝ]Ó)X&žp‡¯½{¶´#[Ù¡|ãàŽ-±ÌËÁVOŒÁšz™7UåýFZ0bÜÆ`ØŒ?½œ®¨—ý”ië,ô HÇ×T}ð§TN|ûÒŒ°ß‚Iì‡Cf0 _õ¶é¯ÈØÊí¥qŸÆÍúc{¯ˆõóp‹¾ܾÿHº< l< $_û84yðjåÅÜ¿¾BL§ÍX„·ámóà ÖÆa ´Nõö]Ùah'ÚýiÁåÒ3Îícj‡¹ãoÞ™F̃›á›— cÕ(¬^’@èçó³pÞ`ËÚó΂¤¿¢ÙÇwÒRÛÃí0ë­°¿‡ö×WvÊ.¦ö  ;èJûå!¦ÆòÌ$Çà=í·j¤¯R¿s1D… èË–s=—t z+!\Íæãâ(n®w^Ù×·yz%kz¿žZ¾hÙÕß-Ø Mû’™ÀEHﳨ5Rì³ÒÒÛaš’ð€4fzŠ„“&|o¶ã fjqÄ<³3Qÿi ˆÒ7„žüù’äÏ”Fxƒº? !¸[ü”Âo·Â@ Ë)\„‹ÄËiÍ!rxZ®ÂïgJ!ð"³øŸ¤Þ$Ò §ŽWéc±U…9‡˜,úVÝÙÏÑ$ó„–¨›ymÄ}œw’ºoezaü}kkc½õ ‚ø7„L¹Ã endstream endobj 15 0 obj <> endobj 21 0 obj <>stream xœU{T“çþ>ùÞZÆ,i†æãtµµõ‚:tÝ©7œ7p@€¢\$@$Ü$’hoB.‚Ü‘¢•Ž(juÖÕŠuR·ºiÝÎêì9ïÇùüclçl÷¼ïïí<¿Ëûû=Ž`8Ž'‰Ä²M‰Rq¶diÿ.Sk¨µ,HK›wQ¼` ³`p`û  E}¯¡šŸ"ùJ,Çw¸×'' ÞÙ°aã>iqe©(¿ hQ6™æ’¾ñ¼õN£®çQ¹tyÎyäm¢l©l_ù7ÂháËòÕüJ&Ò&¦Üt;•™$m%Lƒ!V BP¿nŠ öá·XÈA¥pßB€í2Y¼„b‘D¡Õ ÐkÌ&« |LÂÞÙ—579Ò55À«j•(ÏÈ`xžªç3]øž`¾FÝFýº §J$šT±}5< u&]µn=í[‡œ†¦š&è ‡- ö!+ðЩ*bÄd×]~Ó£aƒUo=Ë ½Õh©®3Ya=´7z†Ñëè˰Þ?ÔÛû¬LÄëf?¥ÂºBg¢õVs.QGÏU¨5Fåú¦  8eìUuÉüY­ñlÚ“[ÞZÑÕÕÞÖQWk«µ“&g­ÚA¯ct²G’Ì;JЛŽVžÉÊ*Ô"X8©±™×&ÆÚ§®ñ8)¶–бˆAØîa®è¨‡\(6jåšRuñY9ÒÁ‹da¾:1‚^[öðÔ‹wßcQo -ÜcûóË!ˆŠý/¦o?ð7ê„.²^æ´(:`øùöÖΙýîLO­ÈÏ!Ó2¥àû€æÞߌX—F›ûý¼žÎVoßÜ2î-$ñ!ÂSQ4÷Ø®,ɘ³z%³•#zŸé:@רgoêzK}bÿñvLƒ•BQFNq |м;;ñÝÝ9„óèy´‘Û0?8| ^ƒ]ÒÆíË­%™EŸu£Â 6/î½”÷z¼,ª ã^ø€CµµÂ.s„•¸¤¶6Š=/ü¼,)“Wh´5Õár™A PÖ ¯Ø'()„y å^æ³»óçǧx#ýç|p^ÏÛSGsëÃ’-eNØ Û†zþšV“ÃQOÏ€×3?‚½ÆNµÐú—?ãêç ¿ƒàñ@U~®\:h[bïD§Ó3z…´¡'Ü9ïÐåþó q3¯µ á< øÒ‚ãq97Ÿñ˜êfzçÓç¡óϹ°šs‹iU‡}ȦwÖþ DT[騤 á0»-n³ †w-w‡Š0í9£;P8ß ÀÅ-Üâòr©¤Cæíëèèí-ï!ÔÇj¿¬¢ÇDm¡_ÁÀ<’zˆË)›Ö/„£­È½úABjIB2¯rVÔ“ OÀâªè#à.#g)Œœ¥,É™û?rvÞ©>stream 2012-06-02T14:33:56Z 2012-06-02T14:33:56Z fig2dev Version 3.2.7a overview.fig endstream endobj 2 0 obj <>endobj xref 0 24 0000000000 65535 f 0000005853 00000 n 0000017554 00000 n 0000005794 00000 n 0000005643 00000 n 0000000015 00000 n 0000005623 00000 n 0000005918 00000 n 0000006052 00000 n 0000007392 00000 n 0000006436 00000 n 0000010664 00000 n 0000006635 00000 n 0000011571 00000 n 0000007099 00000 n 0000013747 00000 n 0000005959 00000 n 0000005989 00000 n 0000007700 00000 n 0000010924 00000 n 0000011856 00000 n 0000014008 00000 n 0000007007 00000 n 0000016135 00000 n trailer << /Size 24 /Root 1 0 R /Info 2 0 R /ID [] >> startxref 17731 %%EOF work/parser.c0000664000000000000000000011423414163725562010410 0ustar /* * userv - parser.c * configuration file parser; this file is actually #included from * lexer.c, which is generated using flex from lexer.l, in turn from * lexer.l.m4. It's in a separate file so that we don't have to worry * about m4 quoting &c., but we have to #include it so that the C * objects from the lexer are available. * * userv is copyright Ian Jackson and other contributors. * See README for full authorship information. * * 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; if not, see . */ static int parse_file(const char *string, int *didexist); static int parser(int allowce); int parse_string(const char *string, const char *descrip, int isinternal); /* * Error-handling routines */ static void closeerrorfile(void) { if (eh.file && !eh.filekeep) { if (fclose(eh.file)) { eh.handling= tokv_word_errorstostderr; parseerrprint("error writing to error log file `%s': %s", eh.filename,strerror(errno)); } free(eh.filename); } eh.handling= 0; eh.file= 0; eh.filename= 0; eh.filekeep= 0; } static void senderrmsg(const char *errmsg, int useehandling) { char suberrmsg[MAX_ERRMSG_LEN]; int e; time_t now; struct tm *lt; switch (useehandling) { case tokv_word_errorstostderr: senderrmsgstderr(errmsg); break; case tokv_word_errorstosyslog: ensurelogopen(eh.logfacility); syslog(eh.loglevel,"%s",errmsg); break; case tokv_word_errorstofile: if (time(&now)==-1) syscallerror("get current time"); lt= localtime(&now); if (!lt) syscallerror("convert current time"); if (fprintf(eh.file,"%d-%02d-%02d %02d:%02d:%02d: uservd: %s\n", lt->tm_year+1900, lt->tm_mon+1, lt->tm_mday, lt->tm_hour, lt->tm_min, lt->tm_sec, errmsg) == EOF) { e= errno; closeerrorfile(); eh.handling= tokv_word_errorstofile; snyprintf(suberrmsg,sizeof(suberrmsg), "error writing to error log file `%.*s': %s;" " reverting to errors-to-stderr", (int)(sizeof(suberrmsg)>>1),eh.filename,strerror(e)); senderrmsg(suberrmsg,eh.handling); senderrmsg(errmsg,eh.handling); } break; default: abort(); } } static void errwhere(struct parser_state *tstate, char *bufput, int bufputlen) { static const char suffix[]= "references ..."; char errmsg[MAX_ERRMSG_LEN]; if (!tstate) { strnycpy(bufput,": ",bufputlen); return; } if (!tstate->notedreferer && tstate->upstate && !tstate->upstate->isinternal) { errwhere(tstate->upstate,errmsg,sizeof(errmsg)-sizeof(suffix)); strcat(errmsg,suffix); senderrmsg(errmsg,eh.handling); tstate->notedreferer= 1; } snyprintf(bufput,bufputlen,"%.*s:%d: ",bufputlen-10, tstate->filename,tstate->reportlineno); } int parseerrprint(const char *fmt, ...) { va_list al; char errmsg[MAX_ERRMSG_LEN]; va_start(al,fmt); errwhere(cstate,errmsg,sizeof(errmsg)>>1); vsnytprintfcat(errmsg,sizeof(errmsg),fmt,al); senderrmsg(errmsg,eh.handling); va_end(al); return tokv_error; } static int unexpected(int found, int wanted, const char *wantedstr) { /* pass wanted==-1 if you know it's not what you wanted; * otherwise this function will check it for you. */ if (found == wanted) return 0; if (found == tokv_error) return found; return parseerrprint("found %s, expected %s",printtoken(found),wantedstr); } static int stringoverflow(const char *where) { return parseerrprint("string buffer became far too large building %s",where); } /* * General assistance functions */ static void freecharparray(char **array) { char **pp; if (!array) return; for (pp=array; *pp; pp++) free(*pp); free(array); } static void countnewlines(void) { char *p; for (p=yytext; *p; p++) if (*p == '\n') cstate->lineno++; } static int dequote(char *inplace) { char *p, *q, buf[4], *bep; int v; p=q=inplace; assert(*p=='"'); p++; while (*p && *p != '"') { if (*p != '\\') { *q++= *p++; continue; } switch (*++p) { case 'n': *q++= '\n'; p++; continue; case 'r': *q++= '\r'; p++; continue; case 't': *q++= '\t'; p++; continue; case 'x': p++; if (!((buf[0]= *p++) && (buf[1]= *p++))) return parseerrprint("quoted string ends inside \\x sequence"); buf[2]= 0; v= strtoul(buf,&bep,16); if (bep != buf+2) return parseerrprint("invalid \\ sequence \\x%s in quoted string",buf); assert(!(v & ~0xff)); *q++= v; continue; default: if (ISCHAR(isalpha,*p)) return parseerrprint("unknown \\ sequence \\%c in quoted string",*p); if (ISCHAR(isdigit,*p)) { if (!((buf[0]= *p++) && (buf[1]= *p++) && (buf[2]= *p++))) abort(); buf[3]= 0; v= strtoul(buf,&bep,8); if (bep != buf+3 || (v & ~0xff)) return parseerrprint("invalid \\ sequence \\%s in quoted string",buf); *q++= v; continue; } else if (ISCHAR(ispunct,*p)) { *q++= *p++; continue; } else { while (*p==' ' || *p=='\t') p++; v= *p++; assert(v=='\n'); } } } assert(*p); p++; assert(!*p); *q++= 0; return tokv_quotedstring; } const char *printtoken(int token) { /* Returns pointer to static buffer, overwritten by next call. */ static const char keywordfmt[]= "keyword `%s'"; static const char operatorfmt[]= "operator `%s'"; static char buf[250]; char *q; const char *p; int i, c, l; if ((token & tokm_repres) == tokr_word) { assert(strlen(yytext)+sizeof(keywordfmt)=size) { if (used >= MAX_ARGSDEFVAR) { r= parseerrprint("far too many arguments to service program"); goto error; } size= (used+5)<<1; newargs= xrealloc(newargs,sizeof(char*)*(size+1)); } newargs[used++]= xstrsave(yytext); } newargs[used]= 0; *newargs_r= newargs; return 0; error: newargs[used]=0; freecharparray(newargs); return r; } static int paa_message(const char **message_r) { /* Returned value is invalidated by repeated calls. */ static char *buildbuf; static int buildbuflen; const char *usetext; int r, tl; r= pa_mwsp(); if (r) return r; tl= 1; if (makeroom(&buildbuf,&buildbuflen,50)) return stringoverflow("start of message"); buildbuf[0]= 0; for (;;) { r= yylex(); if (r == tokv_error) return r; if (r == tokv_eof) return parseerrprint("unexpected end of file in message text"); if (r == tokv_newline) break; usetext= r == tokv_lwsp ? " " : yytext; tl+= strlen(usetext); if (makeroom(&buildbuf,&buildbuflen,tl)) return stringoverflow("message"); strcat(buildbuf,usetext); } *message_r= buildbuf; return 0; } /* * Skipping routines (used by e.g. the `if' code). */ static int skiptoeol(void) { /* Returns 0 if OK, having just parsed the newline * or tokv_error if an error occurs, leaving the position at the error * (which may be EOF or a syntax error token). */ int token; do { token= yylex(); } while (token != tokv_newline && !(token & tokt_exception)); if (token == tokv_newline) return 0; if (token == tokv_error) return token; assert(token == tokv_eof); return parseerrprint("unexpected end of file while looking for end of line"); } static int skip(int allowce) { /* Scans a piece of config without executing it. Returns * tokv_error (leaving the parsing state at the error), * or the tokt_controlend token with type allowce if one * was found (in which case rest of line, including any whitespace * after tokt_controlend, has not been parsed), or tokv_eof. */ int token, r; for (;;) { /* loop over lines */ cstate->reportlineno= cstate->lineno; do { token= yylex(); } while (token == tokv_lwsp || token == tokv_newline); if (token & tokt_exception) { return token; } else if (token & tokt_controlend) { if (allowce == lr_controlend) return token; else return unexpected(token,-1,"control structure end of a different kind"); } else if (token & tokt_controlstart) { r= token; while (r & tokt_controlstart) { r= skiptoeol(); if (r) return r; cstate->reportlineno= cstate->lineno; r= skip(token); if (r & tokt_exception) return r; } } else if (!(token & tokt_directive) && !(token & tokt_condop)) { return parseerrprint("not a directive (or conditional operator) " "while looking for control structure end"); } r= skiptoeol(); if (r) return r; } } /* * Routines for parsing and getting the values of parameters */ static void parm_1string(char ***rvalues, const char *tocopy) { char **a; a= xmalloc(sizeof(char*)*2); a[0]= xstrsave(tocopy); a[1]= 0; *rvalues= a; } static char *parm_ulong(unsigned long ul) { char *p; int l; l= CHAR_BIT*sizeof(unsigned long)/3+4; p= xmalloc(l); snyprintf(p,l,"%lu",ul); return p; } static int parm_usernameuid(char ***rvalues, const char *name, uid_t id) { char **a; a= xmalloc(sizeof(char*)*3); a[0]= xstrsave(name); a[1]= parm_ulong(id); a[2]= 0; *rvalues= a; return 0; } static int parm_groups(char ***rvalues, int size, gid_t *gids, const char *const *groups) { char **a; int i; if (size >= 2 && gids[0] == gids[1]) { size--; gids++; groups++; } a= xmalloc(sizeof(char*)*(size+1)*2); for (i=0; i=3) { for (i=0; i=request_mbuf.nvars) { *rvalues= xmalloc(sizeof(char*)); **rvalues= 0; } else { parm_1string(rvalues,defvararray[i].value); } } else if (token & tokt_parameter) { r= (lr_parameter)(token,rvalues); if (r) { free(name); return r; } } else { free(name); return unexpected(token,-1,"parameter name"); } debug_dumpparameter(name,*rvalues); if (rname) *rname= name; else free(name); return 0; } /* * Routines for parsing conditions, including * parameter-based conditional functions (parmcondition's). */ int pcf_glob(int ctoken, char *const *pv, int *rtrue) { int token, actrue, r; char *const *pp; actrue= 0; r= pa_mwsp(); if (r) return r; for (;;) { token= yylex(); if ((token & tokm_repres) == tokr_nonstring) return unexpected(token,-1,"glob pattern"); for (pp= pv; !actrue && *pp; pp++) if (!fnmatch(yytext,*pp,0)) actrue= 1; token= yylex(); if (token == tokv_newline) break; if (unexpected(token,tokv_lwsp,"newline after or whitespace between glob patterns")) return tokv_error; } *rtrue= actrue; return 0; } int pcf_range(int ctoken, char *const *pv, int *rtrue) { int mintoken, min, maxtoken, max, r; char *const *pp; char *ep; unsigned long v; mintoken= pa_numberdollar(&min); if (mintoken == tokv_error) return mintoken; maxtoken= pa_numberdollar(&max); if (maxtoken == tokv_error) return maxtoken; r= pa_mnl(); if (r) return r; for (pp= pv; *pp; pp++) { v= strtoul(*pp,&ep,10); if (*ep) continue; if (mintoken != tokv_dollar && v < min) continue; if (maxtoken != tokv_dollar && v > max) continue; *rtrue= 1; return 0; } *rtrue= 0; return 0; } int pcf_grep(int ctoken, char *const *pv, int *rtrue) { FILE *file; const char *cp; char *const *pp; char *buf, *p; int r, maxlen, l, c, actrue, posstrue; r= paa_1path(&cp); if (r) return r; file= fopen(cp,"r"); if (!file) return parseerrprint("unable to open file `%s' for grep: %s",cp,strerror(errno)); maxlen= 0; for (pp= pv; *pp; pp++) { l= strlen(*pp); if (l > maxlen) maxlen= l; } buf= xmalloc(maxlen+2); actrue= 0; c= 0; while (!actrue && c!=EOF) { c= getc(file); if (c==EOF) break; if (ISCHAR(isspace,c)) continue; l= maxlen+1; p= buf; while (l>0 && c!='\n' && c!=EOF) { *p++= c; l--; c= getc(file); } if (c=='\n' || c==EOF || ISCHAR(isspace,c)) { while (p>buf && ISCHAR(isspace,p[-1])) --p; *p= 0; posstrue= 0; for (pp= pv; !posstrue && *pp; pp++) if (!strcmp(*pp,buf)) posstrue= 1; } else { posstrue= 0; } if (c!='\n' && c!=EOF) { for (;;) { c= getc(file); if (c==EOF || c=='\n') break; if (!ISCHAR(isspace,c)) posstrue= 0; } } if (posstrue) actrue= 1; } if (ferror(file)) { parseerrprint("error while reading `%s' for grep: %s",cp,strerror(errno)); fclose(file); free(buf); return tokv_error; } assert(actrue || feof(file)); fclose(file); free(buf); *rtrue= actrue; return 0; } static int pa_condition(int *rtrue) { /* Scans up to and including the newline following the condition; * may scan more than one line if the condition is a multi-line * one. Returns 0 (setting *rtrue, and parsing up to and including * the last newline) or tokv_error. * Expects to scan the whitespace before its condition. */ int r, token, andor, ctrue, actrue; char **parmvalues; r= pa_mwsp(); if (r) return r; token= yylex(); if (token == tokv_error) { return token; } else if (token == tokv_not) { r= pa_condition(&ctrue); if (r) return r; *rtrue= !ctrue; return 0; } else if (token == tokv_openparen) { andor= 0; actrue= -1; for (;;) { cstate->reportlineno= cstate->lineno; r= pa_condition(&ctrue); if (r) return r; switch (andor) { case 0: assert(actrue==-1); actrue= ctrue; break; case tokv_and: assert(actrue>=0); actrue= actrue && ctrue; break; case tokv_or: assert(actrue>=0); actrue= actrue || ctrue; break; default: abort(); } do { token= yylex(); } while (token == tokv_lwsp); if (token == tokv_error) return token; if (token == tokv_closeparen) break; if (andor) { r= unexpected(token,andor,"same conjunction as before"); if (r) return r; } else { if (token != tokv_and && token != tokv_or) return unexpected(token,-1,"first conjunction inside connective"); andor= token; } } r= pa_mnl(); if (r) return r; *rtrue= actrue; return 0; } else if (token & tokt_parmcondition) { r= pa_mwsp(); if (r) return r; r= pa_parameter(&parmvalues,0); if (r) return r; r= (lr_parmcond)(token,parmvalues,rtrue); freecharparray(parmvalues); return r; } else { return unexpected(token,-1,"condition"); } } /* * Directive functions and associated `common code' functions */ /* Directives specifying the service program (execute-... and reset) */ static void execreset(void) { execute= 0; execbuiltin= 0; free(execpath); execpath= 0; freecharparray(execargs); execargs= 0; } int df_reject(int dtoken) { int r; r= pa_mnl(); if (r) return r; execreset(); execute= tokv_word_reject; return 0; } int df_executefrompath(int dtoken) { int r; r= pa_mnl(); if (r) return r; execreset(); execute= tokv_word_executefrompath; return 0; } int df_execute(int dtoken) { const char *rv; char **newargs; int r; r= paa_pathargs(&rv,&newargs); if (r) return r; execreset(); execute= tokv_word_execute; execargs= newargs; execpath= xstrsave(rv); return 0; } int df_executefromdirectory(int dtoken) { const char *p, *q, *rv; struct stat stab; char *fn, **newargs; int l, r; r= paa_pathargs(&rv,&newargs); if (r) return r; p= strrchr(service,'/'); if (p) p++; else p= service; if (!*p || !ISCHAR(isalnum,*p)) { parseerrprint("execute-from-directory requires initial char of service " "portion to be alphanumeric (service portion was `%s')", p); freecharparray(newargs); return tokv_error; } for (q=p+1; *q; q++) { if (!ISCHAR(isalnum,*q) && *q != '-') { parseerrprint("execute-from-directory requires service portion to " "contain only alphanumerics and hyphens (was `%s')", p); freecharparray(newargs); return tokv_error; } } l= strlen(rv)+1+strlen(p)+1; fn= xmalloc(l); snyprintf(fn,l,"%s/%s",rv,p); if (stat(fn,&stab)) { if (errno == ENOENT) { free(fn); freecharparray(newargs); return 0; } parseerrprint("failed to stat `%s' for execute-from-directory: %s", fn,strerror(errno)); free(fn); freecharparray(newargs); return tokv_error; } if (!S_ISREG(stab.st_mode)) { parseerrprint("file `%s' in execute-from-directory is not an ordinary file" " or link to one (mode=0%lo)",fn,(unsigned long)stab.st_mode); free(fn); freecharparray(newargs); return tokv_error; } execreset(); execute= tokv_word_executefromdirectory; execargs= newargs; execpath= fn; return 0; } /* Parsing builtin service requests (execute-builtin) */ static int bispa_none(char ***rnewargs) { return pa_mnl(); } static int bispa_parameter(char ***rnewargs) { int r, i; char **parmvalues, *name, **newargs; r= pa_mwsp(); if (r) return r; r= pa_parameter(&parmvalues,&name); if (r) return r; for (i=0; parmvalues[i]; i++); newargs= xmalloc(sizeof(char*)*(i+2)); newargs[0]= name; memcpy(newargs+1,parmvalues,sizeof(char*)*(i+1)); free(parmvalues); r= pa_mnl(); if (r) { free(newargs); return r; } *rnewargs= newargs; return 0; } int df_executebuiltin(int dtoken) { int r; builtinserviceexec_fnt *bisexec; char *newpath, **newargs; r= pa_mwsp(); if (r) return r; r= yylex(); if (r == tokv_error) return r; if (!(r & tokt_builtinservice)) return unexpected(r,-1,"builtin service name"); bisexec= lr_bisexec; newpath= xstrsave(yytext); newargs= 0; r= lr_bispa(&newargs); if (r) { free(newpath); return r; } execreset(); execute= tokv_word_executebuiltin; execbuiltin= bisexec; execpath= newpath; execargs= newargs; return 0; } /* Directives for changing other execution parameters */ int dfg_setflag(int dtoken) { int r; r= pa_mnl(); if (r) return r; *lr_flag= lr_flagval; return 0; } int df_reset(int dtoken) { int r; r= pa_mnl(); if (r) return r; r= parse_string(RESET_CONFIGURATION,"",1); return r; } int dfg_fdwant(int dtoken) { int fdmin, fdmax, r, needreadwrite, havereadwrite, fd; needreadwrite= lr_fdwant_readwrite; r= pa_mwsp(); if (r) return r; r= yylex(); if (r == tokv_error) return r; if (!(r & tokt_fdrange)) return unexpected(r,-1,"file descriptor range"); fdmin= lr_min; fdmax= lr_max; if (fdmin<0 || fdmin>MAX_ALLOW_FD || (fdmax != -1 && fdmax<0) || fdmax>MAX_ALLOW_FD) return parseerrprint("file descriptor in range is negative or far too large"); r= yylex(); if (r == tokv_error) return r; if (r == tokv_newline) { if (needreadwrite > 0) return parseerrprint("read or write is required"); havereadwrite= 0; } else if (r == tokv_lwsp) { if (needreadwrite < 0) return parseerrprint("read or write not allowed"); r= yylex(); if (r == tokv_error) return r; if (!(r & tokt_readwrite)) return unexpected(r,-1,"read or write (or perhaps newline)"); havereadwrite= r; r= pa_mnl(); if (r) return r; } else { return unexpected(r,-1,"whitespace before read or write or newline"); } ensurefdarray(fdmin); if (fdmax == -1) { if (!(dtoken == tokv_word_rejectfd || dtoken == tokv_word_ignorefd)) return parseerrprint("unspecified maximum only allowed" " with reject-fd and ignore-fd"); fdmax= fdarrayused-1; restfdwantstate= dtoken; restfdwantrw= havereadwrite; } ensurefdarray(fdmax); for (fd=fdmin; fd<=fdmax; fd++) { fdarray[fd].wantstate= dtoken; fdarray[fd].wantrw= havereadwrite; } return 0; } /* Directives for changing error handling */ int df_errorstostderr(int dtoken) { int r; r= pa_mnl(); if (r) return r; closeerrorfile(); eh.handling= dtoken; return 0; } int df_errorstosyslog(int dtoken) { int token, level, facility; facility= DEFUSERLOGFACILITY; level= DEFUSERLOGLEVEL; token= yylex(); if (token == tokv_lwsp) { token= yylex(); if (token == tokv_error) return token; if (!(token & tokt_logfacility)) return unexpected(token,-1,"syslog facility (or end of line)"); facility= lr_logfacility; token= yylex(); } if (token == tokv_lwsp) { token= yylex(); if (token == tokv_error) return token; if (!(token & tokt_loglevel)) return unexpected(token,-1,"syslog level (or end of line) after facility"); level= lr_loglevel; token= yylex(); } if (unexpected(token,tokv_newline,"end of line after errors-to-syslog")) return tokv_error; closeerrorfile(); eh.handling= tokv_word_errorstosyslog; eh.logfacility= facility; eh.loglevel= level; return 0; } int df_errorstofile(int dtoken) { const char *cp; FILE *file; int r; r= paa_1path(&cp); if (r) return r; file= fopen(cp,"a"); if (!file) return parseerrprint("unable to open error log file `%s': %s",cp,strerror(errno)); if (setvbuf(file,0,_IOLBF,MAX_ERRMSG_LEN)) { parseerrprint("unable to set line buffering on errors file: %s",strerror(errno)); fclose(file); return tokv_error; } closeerrorfile(); eh.handling= tokv_word_errorstofile; eh.file= file; eh.filename= xstrsave(cp); return 0; } /* Directives for including other files or configuration data */ int dfi_includeuserrcfile(int dtoken) { int r; r= pa_mnl(); if (r) return r; assert(userrcfile); return parse_file(userrcfile,0); } int dfi_includeclientconfig(int dtoken) { int r; r= pa_mnl(); if (r) return r; assert(overridedata); return parse_string(overridedata,"",0); } int df_include(int dtoken) { const char *cp; int r, found; r= paa_1path(&cp); if (r) return r; r= parse_file(cp,&found); if (r) return r; if (found || dtoken == tokv_word_includeifexist) return 0; return parseerrprint(dtoken == tokv_word_includesysconfig ? "system configuration file `%s' does not exist" : "included file `%s' does not exist", cp); } int df_includedirectory(int dtoken) { static char *buildbuf=0; static int buildbuflen=0; int r, cpl, tel, c, found; DIR *d; struct dirent *de; const char *p, *cpget; char *cp; r= paa_1path(&cpget); if (r) return r; d= opendir(cpget); if (!d) return parseerrprint("unable to open directory `%s': %s",cpget,strerror(errno)); cp= xstrsave(cpget); cpl= strlen(cp); while ((errno=0, de= readdir(d))) { tel= strlen(de->d_name); if (!tel) continue; p= de->d_name; if (!*p || !ISCHAR(isalnum,*p)) continue; while ((c= *++p)) if (!(ISCHAR(isalnum,c) || c=='-')) break; if (c) continue; if (makeroom(&buildbuf,&buildbuflen,cpl+1+tel+1)) { stringoverflow("pathname in directory"); r= tokv_error; goto x_err; } snyprintf(buildbuf,buildbuflen,"%s/%s",cp,de->d_name); r= parse_file(buildbuf,&found); if (r) goto x_err; if (!found) { r= parseerrprint("unable to open file `%s' in included directory `%s': %s", de->d_name,cp,strerror(errno)); goto x_err; } } if (errno) { parseerrprint("error reading directory `%s': %s",cp,strerror(errno)); closedir(d); free(cp); return tokv_error; } if (closedir(d)) { parseerrprint("error closing directory `%s': %s",cp,strerror(errno)); free(cp); return tokv_error; } free(cp); return 0; x_err: closedir(d); free(cp); return r; } static int oldquote = 0; int dfg_lookupquotemode(int dtoken) { int r; r= pa_mnl(); if (r) return r; oldquote = dtoken == tokv_word_includelookupquoteold; return r; } int df_includelookup(int dtoken) { static char *buildbuf=0; int buildbuflen=0; char **parmvalues, **pp, *p, *q, *cp; const char *cpget; struct stat stab; int r, done, thisdone, cpl, c; r= pa_mwsp(); if (r) return r; r= pa_parameter(&parmvalues,0); if (r) return r; r= paa_1path(&cpget); if (r) { freecharparray(parmvalues); return r; } if (stat(cpget,&stab)) { parseerrprint("unable to access directory `%s': %s",cpget,strerror(errno)); freecharparray(parmvalues); return tokv_error; } if (!S_ISDIR(stab.st_mode)) { parseerrprint("object `%s' is not a directory or link to one",cpget); freecharparray(parmvalues); return tokv_error; } done= 0; cp= xstrsave(cpget); cpl= strlen(cp); if (!parmvalues[0]) { if (makeroom(&buildbuf,&buildbuflen,cpl+1+sizeof(NONEINCLUDELOOKUP))) { stringoverflow("pathname in directory for lookup of undefined parameter"); r= tokv_error; goto x_err; } snyprintf(buildbuf,buildbuflen,"%s/" NONEINCLUDELOOKUP,cp); r= parse_file(buildbuf,&thisdone); if (r) goto x_err; if (thisdone) done= 1; } else { for (pp=parmvalues; *pp && (!done || dtoken == tokv_word_includelookupall); pp++) { if (makeroom(&buildbuf,&buildbuflen, cpl+1+strlen(*pp)*2+3+sizeof(EMPTYINCLUDELOOKUP)+1)) { stringoverflow("pathname in directory for lookup"); r= tokv_error; goto x_err; } strcpy(buildbuf,cp); p= *pp; q= buildbuf+cpl; *q++= '/'; if (!*p) { strcpy(q,EMPTYINCLUDELOOKUP); } else { if (*p=='.') *q++= ':'; while ((c= *p++)) { if (c=='/') { *q++= ':'; c= '-'; } else if (oldquote ? !((c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') || c == '-' || c == '_') : (c==':')) { *q++= ':'; } *q++= c; } *q++= 0; } r= parse_file(buildbuf,&thisdone); if (r) goto x_err; if (thisdone) done= 1; } } if (!done) { if (makeroom(&buildbuf,&buildbuflen, cpl+1+sizeof(DEFAULTINCLUDELOOKUP))) { stringoverflow("pathname in directory for lookup of default"); r= tokv_error; goto x_err; } snyprintf(buildbuf,buildbuflen,"%s/" DEFAULTINCLUDELOOKUP,cp); r= parse_file(buildbuf,0); if (r) goto x_err; } r= 0; x_err: freecharparray(parmvalues); free(cp); return r; } /* Control constructs */ int df_catchquit(int dtoken) { int r; r= pa_mnl(); if (r) return r; r= parser(tokv_word_catchquit); if (r == tokv_quit || r == tokv_error) { if (r == tokv_error) { r= parse_string(RESET_CONFIGURATION, "",1); assert(!r); } r= skip(tokv_word_catchquit); } if (r & tokt_controlend) { assert(r == tokv_word_hctac); r= pa_mnl(); } return r; } int df_if(int dtoken) { int r, true, done; done= 0; do { r= pa_condition(&true); if (r) return r; if (!done && true) { r= parser(tokv_word_if); done= 1; } else { r= skip(tokv_word_if); } if (!(r & tokt_controlend)) return r; } while (r == tokv_word_elif); if (r == tokv_word_else) { r= pa_mnl(); if (r) return r; cstate->reportlineno= cstate->lineno; if (done) r= skip(tokv_word_if); else r= parser(tokv_word_if); if (!(r & tokt_controlend)) return r; } if (unexpected(r,tokv_word_fi,"`fi' to end `if'")) return tokv_error; return pa_mnl(); } int df_errorspush(int dt) { struct error_handling save; int r; r= pa_mnl(); if (r) return r; save= eh; eh.filekeep= 1; r= parser(tokv_word_errorspush); closeerrorfile(); eh= save; if (r & tokt_controlend) { assert(r == tokv_word_srorre); r= pa_mnl(); } return r; } /* Miscelleanous directives */ int df_cd(int dtoken) { const char *cp; int r; r= paa_1path(&cp); if (r) return r; if (!chdir(cp)) return 0; return parseerrprint("unable to change directory to `%s': %s",cp,strerror(errno)); } int df_userrcfile(int dtoken) { const char *cp; int r; r= paa_1path(&cp); if (r) return r; free(userrcfile); userrcfile= xstrsave(cp); return 0; } int df_message(int dtoken) { const char *mp; int r; r= paa_message(&mp); if (r) return r; parseerrprint("`message' directive: %s",mp); return 0; } int df_error(int dtoken) { const char *mp; int r; r= paa_message(&mp); if (r) return r; return parseerrprint("`error' directive: %s",mp); } int df_eof(int dtoken) { int r; r= pa_mnl(); if (r) return r; return tokv_eof; } int df_quit(int dtoken) { int r; r= pa_mnl(); if (r) return r; return tokv_quit; } /* * Main parser routines */ static void parser_push(struct parser_state *usestate, const char *newfile, const struct stat *newfilestab, YY_BUFFER_STATE ybuf, int isinternal) { usestate->lineno= 1; usestate->reportlineno= 1; usestate->filename= newfile; usestate->filestab= *newfilestab; usestate->notedreferer= 0; usestate->isinternal= isinternal; usestate->ybuf= ybuf; usestate->upstate= cstate; cstate= usestate; yy_switch_to_buffer(ybuf); } static void parser_pop(void) { struct parser_state *oldstate; oldstate= cstate; cstate= cstate->upstate; if (cstate) yy_switch_to_buffer(cstate->ybuf); yy_delete_buffer(oldstate->ybuf); } int parse_string(const char *string, const char *descrip, int isinternal) { /* Returns the same things as parser, except that tokv_eof is turned * into 0. *string must be statically allocated or copied, so that * it is not overwritten while the parsing takes place (unlike with * parse_file). */ static const struct stat blankstab; struct parser_state usestate; YY_BUFFER_STATE ybuf; int r; ybuf= yy_scan_string(string); if (!ybuf) syscallerror("unable to create flex buffer for internal string"); parser_push(&usestate,descrip,&blankstab,ybuf,isinternal); r= parser(0); parser_pop(); if (r == tokv_eof) r= 0; return r; } static int parse_file(const char *string, int *didexist) { /* Returns the same things as parser, except that tokv_eof is turned * into 0. If *didexist is 0 then errno will have been set. * *string will be copied by parse_file so it may be be overwritten * during the parsing (so, for example, yytext need not be copied). */ static int fileparselevel= 0; struct parser_state usestate, *checkrecurse; YY_BUFFER_STATE ybuf; int r; FILE *file; char *filename; struct stat newstab; if (fileparselevel >= MAX_INCLUDE_NEST) return parseerrprint("too many nested levels of included files"); file= fopen(string,"r"); if (!file) { if (errno == ENOENT) { if (didexist) *didexist= 0; return 0; } return parseerrprint("unable to open config file `%s': %s",string,strerror(errno)); } r= fstat(fileno(file),&newstab); if (r) syscallerror("unable to fstat new file"); for (checkrecurse= cstate; checkrecurse; checkrecurse= checkrecurse->upstate) { if (!checkrecurse->filestab.st_mode) continue; if (newstab.st_dev==checkrecurse->filestab.st_dev && newstab.st_ino==checkrecurse->filestab.st_ino) { fclose(file); return parseerrprint("recursion detected - config file `%s' calls itself",string); } } if (didexist) *didexist= 1; ybuf= yy_create_buffer(file,YY_BUF_SIZE); if (!ybuf) syscallerror("unable to create flex buffer for file"); filename= xstrsave(string); parser_push(&usestate,filename,&newstab,ybuf,0); fileparselevel++; r= parser(0); if (ferror(file)) r= parseerrprint("error reading configuration file `%s'",string); fileparselevel--; parser_pop(); free(filename); fclose(file); if (r == tokv_eof) r= 0; return r; } static int parser(int allowce) { /* Returns: * an exception (error, eof or quit) * then rest of `file' is uninteresting * or * token if allowce was !0 and equal to token's controlend * then rest of `file' (including rest of line with the * controlend - even the whitespace) not scanned yet */ int token, r; for (;;) { /* loop over lines */ cstate->reportlineno= cstate->lineno; do { token= yylex(); } while (token == tokv_lwsp); if (token & tokt_exception) { return token; } else if (token & tokt_controlend) { if (lr_controlend == allowce) return token; else return unexpected(token,-1,"directive (not this kind of" " control structure end)"); } else if (token & tokt_directive) { if ((token & tokt_internal) && !cstate->isinternal) return unexpected(token,-1,"published directive, not internal-use-only one"); r= (lr_dir)(token); if (r) { assert(r & tokt_exception); return r; } } else if (token == tokv_newline) { /* ignore blank lines (and comment-only lines) */ } else { return unexpected(token,-1,"directive"); } } } work/process.c0000664000000000000000000005557714163725562010610 0ustar /* * userv - process.c * daemon code to process one request (is parent of service process) * * userv is copyright Ian Jackson and other contributors. * See README for full authorship information. * * 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; if not, see . */ /* * We do some horrible asynchronous stuff with signals. * * The following objects &c. are used in signal handlers and so * must be protected by calls to blocksignals if they are used in * the main program: * the syslog() family of calls, and the associated * syslogopenfacility variable * swfile (stdio stream) * * The following objects are used in the main program unprotected * and so must not be used in signal handlers: * srfile * * child and childtokill are used for communication between the * main thread and the signal handlers; none of the signal handlers * return so errno is OK too. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "config.h" #include "common.h" #include "both.h" #include "daemon.h" #include "lib.h" #include "tokens.h" /* NB: defaults for the execution state are not set here, but in * the RESET_CONFIGURATION #define in daemon.h. */ struct request_msg request_mbuf; struct keyvaluepair *defvararray; struct fdstate *fdarray; int fdarraysize, fdarrayused; int restfdwantstate= tokv_word_rejectfd, restfdwantrw; int service_ngids; char **argarray; char *serviceuser, *service, *loginname, *cwd; char *overridedata, *userrcfile; char *serviceuser_dir, *serviceuser_shell, *callinguser_shell; gid_t *calling_gids, *service_gids; uid_t serviceuser_uid=-1; const char **calling_groups, **service_groups; char *execpath, **execargs; int execute; int setenvironment, suppressargs, disconnecthup; builtinserviceexec_fnt *execbuiltin; int syslogopenfacility=-1; static FILE *swfile, *srfile; static pid_t child=-1, childtokill=-1; static pid_t mypid; /* Function shared with servexec.c: */ int synchread(int fd, int ch) { char synchmsg; int r; for (;;) { r= read(fd,&synchmsg,1); if (r==1) break; if (r==0) { errno= ECONNRESET; return -1; } assert(r<0); if (errno!=EINTR) return -1; }; assert(synchmsg==ch); return 0; } const char *defaultpath(void) { return serviceuser_uid ? DEFAULTPATH_USER : DEFAULTPATH_ROOT; } /* General-purpose functions; these do nothing special about signals */ static void blocksignals(void) { int r; sigset_t set; sigemptyset(&set); sigaddset(&set,SIGCHLD); sigaddset(&set,SIGPIPE); r= sigprocmask(SIG_BLOCK,&set,0); assert(!r); } static void xfwriteerror(void) { if (errno != EPIPE) syscallerror("writing to client"); blocksignals(); ensurelogopen(USERVD_LOGFACILITY); syslog(LOG_INFO,"client went away (broken pipe)"); disconnect(8); } static void xfwrite(const void *p, size_t sz, FILE *file) { size_t nr; nr= fwrite(p,1,sz,file); if (nr != sz) xfwriteerror(); } static void xfflush(FILE *file) { if (fflush(file)) xfwriteerror(); } /* Functions which may be called only from the main thread. These may * use main-thread objects and must block signals before using signal * handler objects. */ static void xfread(void *p, size_t sz) { size_t nr; nr= working_fread(p,sz,srfile); if (nr == sz) return; if (ferror(srfile)) syscallerror("reading from client"); blocksignals(); assert(feof(srfile)); syslog(LOG_INFO,"client went away (unexpected EOF)"); swfile= 0; disconnect(8); } static char *xfreadsetstring(int l) { char *s; assert(l<=MAX_GENERAL_STRING); s= xmalloc(l+1); xfread(s,sizeof(*s)*l); s[l]= 0; return s; } static char *xfreadstring(void) { int l; xfread(&l,sizeof(l)); return xfreadsetstring(l); } static void getevent(struct event_msg *event_r) { int fd; for (;;) { xfread(event_r,sizeof(struct event_msg)); switch (event_r->type) { case et_closereadfd: fd= event_r->data.closereadfd.fd; if (fd >= fdarrayused) { blocksignals(); syslog(LOG_ERR,"client sent bad file descriptor %d to close (max %d)", fd,fdarrayused-1); disconnect(20); } if (fdarray[fd].holdfd!=-1) { if (close(fdarray[fd].holdfd)) syscallerror("cannot close holding fd"); fdarray[fd].holdfd= -1; } break; case et_disconnect: blocksignals(); syslog(LOG_INFO,"client disconnected"); disconnect(4); default: return; } } } /* Functions which may be called either from signal handlers or from * the main thread. They block signals in case they are on the main * thread, and may only use signal handler objects. None of them * return. If they did they'd have to restore the signal mask. */ void miscerror(const char *what) { blocksignals(); syslog(LOG_ERR,"failure: %s",what); disconnect(16); } void syscallerror(const char *what) { int e; e= errno; blocksignals(); syslog(LOG_ERR,"system call failure: %s: %s",what,strerror(e)); disconnect(16); } /* Functions which may be called from signal handlers. These * may use signal-handler objects. The main program may only * call them with signals blocked, and they may not use any * main-thread objects. */ void ensurelogopen(int wantfacility) { if (syslogopenfacility==wantfacility) return; if (syslogopenfacility!=-1) closelog(); openlog(USERVD_LOGIDENT,LOG_NDELAY|LOG_PID,wantfacility); syslogopenfacility= wantfacility; } void NONRETURNING disconnect(int exitstatus) { /* This function can sometimes indirectly call itself (eg, * xfwrite, syscallerror can cause it to be called). So, all * the global variables indicating need for action are reset * before the action is taken so that if it fails it isn't * attempted again. */ struct progress_msg progress_mbuf; FILE *swfilereal; pid_t orgtokill; int r; if (childtokill!=-1 && disconnecthup) { orgtokill= childtokill; childtokill= -1; if (disconnecthup) { r= kill(-orgtokill,SIGHUP); if (r && errno!=EPERM && errno!=ESRCH) syscallerror("sending SIGHUP to service process group"); } child= -1; } if (swfile) { swfilereal= swfile; swfile= 0; memset(&progress_mbuf,0,sizeof(progress_mbuf)); progress_mbuf.magic= PROGRESS_MAGIC; progress_mbuf.type= pt_failed; xfwrite(&progress_mbuf,sizeof(progress_mbuf),swfilereal); xfflush(swfilereal); } _exit(exitstatus); } static void reporttermination(int status) { struct progress_msg progress_mbuf; memset(&progress_mbuf,0,sizeof(progress_mbuf)); progress_mbuf.magic= PROGRESS_MAGIC; progress_mbuf.type= pt_terminated; progress_mbuf.data.terminated.status= status; xfwrite(&progress_mbuf,sizeof(progress_mbuf),swfile); xfflush(swfile); } static void NONRETURNING sighandler_chld(int ignored) { int status; pid_t returned; returned= wait3(&status,WNOHANG,0); if (returned==-1) syscallerror("wait for child failed"); if (!returned) syscallerror("spurious sigchld"); if (returned!=child) syscallerror("spurious child process"); child= childtokill= -1; reporttermination(status); syslog(LOG_INFO,"service completed (status %d %d)",(status>>8)&0x0ff,status&0x0ff); _exit(0); } /* Functions which are called only during setup, before * the signal asynchronicity starts. They can do anything they like. */ void ensurefdarray(int fd) { if (fd < fdarrayused) return; if (fd >= fdarraysize) { fdarraysize= ((fd+2)<<1); fdarray= xrealloc(fdarray,sizeof(struct fdstate)*fdarraysize); } while (fd >= fdarrayused) { fdarray[fdarrayused].iswrite= -1; fdarray[fdarrayused].realfd= -1; fdarray[fdarrayused].holdfd= -1; fdarray[fdarrayused].wantstate= restfdwantstate; fdarray[fdarrayused].wantrw= restfdwantrw; fdarrayused++; } } static void NONRETURNING generalfailure(const char *prefix, int reserveerrno, int errnoval, const char *fmt, va_list al) { char errmsg[MAX_ERRMSG_LEN]; if (prefix) { strnycpy(errmsg,prefix,sizeof(errmsg)); strnytcat(errmsg,": ",sizeof(errmsg)); } else { errmsg[0]= 0; } vsnytprintfcat(errmsg,sizeof(errmsg)-reserveerrno,fmt,al); if (reserveerrno) { strnytcat(errmsg,": ",sizeof(errmsg)); strnytcat(errmsg,strerror(errnoval),sizeof(errmsg)); } senderrmsgstderr(errmsg); syslog(LOG_INFO,"service failed (%s)",errmsg); disconnect(12); } static void NONRETURNPRINTFFORMAT(1,2) failure(const char *fmt, ...) { va_list al; va_start(al,fmt); generalfailure(0,0,0,fmt,al); } static void NONRETURNPRINTFFORMAT(1,2) syscallfailure(const char *fmt, ...) { va_list al; int e; e= errno; va_start(al,fmt); generalfailure("system call failed",ERRMSG_RESERVE_ERRNO,e,fmt,al); } void senderrmsgstderr(const char *errmsg) { struct progress_msg progress_mbuf; unsigned long ul; int l; l= strlen(errmsg); memset(&progress_mbuf,0,sizeof(progress_mbuf)); progress_mbuf.magic= PROGRESS_MAGIC; progress_mbuf.type= pt_errmsg; progress_mbuf.data.errmsg.messagelen= l; xfwrite(&progress_mbuf,sizeof(progress_mbuf),swfile); xfwrite(errmsg,l,swfile); ul= PROGRESS_ERRMSG_END_MAGIC; xfwrite(&ul,sizeof(ul),swfile); xfflush(swfile); } /* The per-request main program and its subfunctions. */ static void setup_comms(int sfd) { static char swbuf[BUFSIZ]; static char srbuf[BUFSIZ]; struct sigaction sig; ensurelogopen(USERVD_LOGFACILITY); syslog(LOG_DEBUG,"call connected"); mypid= getpid(); if (mypid == -1) syscallerror("getpid"); sig.sa_handler= SIG_IGN; sigemptyset(&sig.sa_mask); sig.sa_flags= 0; if (sigaction(SIGPIPE,&sig,0)) syscallerror("cannot ignore sigpipe"); srfile= fdopen(sfd,"r"); if (!srfile) syscallerror("turn socket fd into reading FILE*"); if (setvbuf(srfile,srbuf,_IOFBF,sizeof(srbuf))) syscallerror("set buffering on socket reads"); swfile= fdopen(sfd,"w"); if (!swfile) syscallerror("turn socket fd into writing FILE*"); if (setvbuf(swfile,swbuf,_IOFBF,sizeof(swbuf))) syscallerror("set buffering on socket writes"); } static void send_opening(void) { struct opening_msg opening_mbuf; memset(&opening_mbuf,0,sizeof(opening_mbuf)); opening_mbuf.magic= OPENING_MAGIC; memcpy(opening_mbuf.protocolchecksumversion,protocolchecksumversion,PCSUMSIZE); opening_mbuf.overlordpid= overlordpid; opening_mbuf.serverpid= mypid; xfwrite(&opening_mbuf,sizeof(opening_mbuf),swfile); xfflush(swfile); } static void receive_request(void) { int i, fd; unsigned long ul; xfread(&request_mbuf,sizeof(request_mbuf)); serviceuser= xfreadsetstring(request_mbuf.serviceuserlen); service= xfreadsetstring(request_mbuf.servicelen); assert(request_mbuf.spoofed==0 || request_mbuf.spoofed==1); loginname= xfreadsetstring(request_mbuf.loginnamelen); cwd= xfreadsetstring(request_mbuf.cwdlen); if (request_mbuf.overridelen >= 0) { assert(request_mbuf.overridelen <= MAX_OVERRIDE_LEN); overridedata= xfreadsetstring(request_mbuf.overridelen); } else { assert(request_mbuf.overridelen == -1); overridedata= 0; } assert(request_mbuf.ngids <= MAX_GIDS); calling_gids= xmalloc(sizeof(gid_t)*request_mbuf.ngids); xfread(calling_gids,sizeof(gid_t)*request_mbuf.ngids); fdarraysize= 4; fdarray= xmalloc(sizeof(struct fdstate)*fdarraysize); fdarrayused= 1; fdarray[0].iswrite= -1; fdarray[0].wantstate= tokv_word_rejectfd; assert(request_mbuf.nreadfds+request_mbuf.nwritefds <= MAX_ALLOW_FD+1); for (i=0; i=request_mbuf.nreadfds); } /* fdarray[].iswrite now set; rest is still blank * (ie want reject read, no realfd holdfd). */ assert(request_mbuf.nargs <= MAX_ARGSDEFVAR); argarray= xmalloc(sizeof(char*)*(request_mbuf.nargs)); for (i=0; igr_name); } *names_r= names; } static void lookup_uidsgids(void) { struct passwd *pw; pw= getpwnam(loginname); if (!pw) miscerror("look up calling user"); assert(!strcmp(pw->pw_name,loginname)); callinguser_shell= xstrsave(pw->pw_shell); pw= getpwnam(serviceuser); if (!pw) miscerror("look up service user"); assert(!strcmp(pw->pw_name,serviceuser)); serviceuser_dir= xstrsave(nondebug_serviceuserdir(pw->pw_dir)); serviceuser_shell= xstrsave(pw->pw_shell); serviceuser_uid= pw->pw_uid; if (setregid(pw->pw_gid,pw->pw_gid)) syscallerror("setregid 1"); if (initgroups(pw->pw_name,pw->pw_gid)) syscallerror("initgroups"); if (setreuid(pw->pw_uid,pw->pw_uid)) syscallerror("setreuid 1"); if (setreuid(pw->pw_uid,pw->pw_uid)) syscallerror("setreuid 2"); if (pw->pw_uid) { if (!setreuid(pw->pw_uid,0)) miscerror("setreuid 3 unexpectedly succeeded"); if (errno != EPERM) syscallerror("setreuid 3 failed in unexpected way"); } if (setregid(pw->pw_gid,pw->pw_gid)) syscallerror("setregid 2"); service_ngids= getgroups(0,0); if (service_ngids == -1) syscallerror("getgroups(0,0)"); if (service_ngids > MAX_GIDS) miscerror("service user is in far too many groups"); service_gids= xmalloc(sizeof(gid_t)*(service_ngids+1)); service_gids[0]= pw->pw_gid; if (getgroups(service_ngids,service_gids+1) != service_ngids) syscallerror("getgroups(size,list)"); groupnames(request_mbuf.ngids,calling_gids,&calling_groups); groupnames(service_ngids,service_gids,&service_groups); } static void findinpath(char *program) { char *part, *exectry; const char *string, *delim, *nextstring; struct stat stab; int r, partsize; if (strchr(program,'/')) { r= stat(program,&stab); if (r) syscallfailure("failed check for program (containing slash) `%s'",program); execpath= program; } else { string= getenv("PATH"); if (!string) string= defaultpath(); while (string) { delim= strchr(string,':'); if (delim) { if (delim-string > MAX_GENERAL_STRING) failure("execute-from-path, but PATH component too long"); partsize= delim-string; nextstring= delim+1; } else { partsize= strlen(string); nextstring= 0; } part= xstrsubsave(string,partsize); exectry= part[0] ? xstrcat3save(part,"/",program) : xstrsave(program); free(part); r= stat(exectry,&stab); if (!r) { execpath= exectry; break; } free(exectry); string= nextstring; } if (!execpath) failure("program `%s' not found on default PATH",program); } } static void check_find_executable(void) { struct stat stab; int r; switch (execute) { case tokv_word_reject: failure("request rejected"); case tokv_word_execute: findinpath(execpath); break; case tokv_word_executefromdirectory: r= stat(execpath,&stab); if (r) syscallfailure("checking for executable in directory, `%s'",execpath); break; case tokv_word_executebuiltin: break; case tokv_word_executefrompath: findinpath(service); break; default: abort(); } } static void makenonexistentfd(int fd) { if (fdarray[fd].realfd == -1) { assert(fdarray[fd].holdfd == -1); } else { if (close(fdarray[fd].realfd)) syscallfailure("close unwanted file descriptor %d",fd); fdarray[fd].realfd= -1; if (fdarray[fd].holdfd != -1) { if (close(fdarray[fd].holdfd)) syscallfailure("close unwanted hold descriptor for %d",fd); fdarray[fd].holdfd= -1; } } } static void makenullfd(int fd) { fdarray[fd].realfd= open("/dev/null", fdarray[fd].wantrw == tokv_word_read ? O_RDONLY : fdarray[fd].wantrw == tokv_word_write ? O_WRONLY : 0); if (fdarray[fd].realfd<0) syscallfailure("cannot open /dev/null for null or allowed, unprovided fd"); } static void check_fds(void) { int fd; assert(fdarrayused>=2); if (!(fdarray[2].wantstate == tokv_word_requirefd || fdarray[2].wantstate == tokv_word_allowfd) || fdarray[2].wantrw != tokv_word_write) failure("must have stderr (fd 2), but file descriptor setup in " "configuration does not have it or not for writing"); for (fd=0; fd %s %c %s", request_mbuf.spoofed ? "spoof" : "user", loginname, serviceuser, overridedata?'!':':', service); if (overridedata) r= parse_string(TOPLEVEL_OVERRIDDEN_CONFIGURATION, "",1); else r= parse_string(TOPLEVEL_CONFIGURATION, "",1); ensurelogopen(USERVD_LOGFACILITY); if (r == tokv_error) failure("error encountered while parsing configuration"); assert(r == tokv_quit); debug_dumpexecsettings(); check_find_executable(); check_fds(); send_progress_ok(); getevent(&event_mbuf); assert(event_mbuf.type == et_confirm); if (execbuiltin == bisexec_shutdown && !serviceuser_uid) { /* The check for the uid is just so we can give a nice * error message (in the actual code for bisexec_shutdown). * If this is spoofed somehow then the unlink() will simply fail. */ r= unlink(RENDEZVOUSPATH); if (r) syscallfailure("remove rendezvous socket %s",RENDEZVOUSPATH); syslog(LOG_NOTICE,"arranging for termination, due to client request"); reporttermination(0); _exit(10); } fork_service_synch(); getevent(&event_mbuf); abort(); } work/servexec.c0000664000000000000000000002427414163725562010744 0ustar /* * userv - execserv.c * daemon code which executes actual service (ie child process) * * userv is copyright Ian Jackson and other contributors. * See README for full authorship information. * * 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; if not, see . */ #include #include #include #include #include #include #include #include #include #include #include #include "config.h" #include "common.h" #include "daemon.h" #include "lib.h" #include "both.h" #include "version.h" static void NONRETURNING serv_syscallfail(const char *msg) { fputs("uservd(service): ",stderr); perror(msg); _exit(-1); } static void NONRETURNING serv_checkstdoutexit(void) { if (ferror(stdout) || fclose(stdout)) serv_syscallfail("write stdout"); _exit(0); } void bisexec_environment(const char *const *argv) { execlp("env","env",(char*)0); serv_syscallfail("execute `env'"); } void bisexec_parameter(const char *const *argv) { always_dumpparameter(execargs[0],execargs+1); serv_checkstdoutexit(); } void bisexec_help(const char *const *argv) { const char *const *pp; fputs("recognised builtin services:\n",stdout); for (pp= builtinservicehelpstrings; *pp; pp++) printf(" %s\n",*pp); serv_checkstdoutexit(); } void bisexec_version(const char *const *argv) { const unsigned char *p; int i; printf("uservd version " VERSION VEREXT "\n" #ifdef DEBUG "DEBUGGING VERSION" #else "production version" #endif " - protocol magic number %08lx\n" "maximums: fd %-10d general string %d\n" " gids %-10d override length %d\n" " args or variables %-10d error message %d\n" " nested inclusion %-10d errno string reserve %d\n" "protocol checksum: ", BASE_MAGIC, MAX_ALLOW_FD, MAX_GENERAL_STRING, MAX_GIDS, MAX_OVERRIDE_LEN, MAX_ARGSDEFVAR, MAX_ERRMSG_LEN, MAX_INCLUDE_NEST, ERRMSG_RESERVE_ERRNO); for (i=0, p=protocolchecksumversion; i0) { putchar(' '); nspaces--; } putchar(c); lnl= 0; break; } } assert(lnl); serv_checkstdoutexit(); } void bisexec_toplevel(const char *const *argv) { dumpconfig(TOPLEVEL_CONFIGURATION); } void bisexec_override(const char *const *argv) { dumpconfig(TOPLEVEL_OVERRIDDEN_CONFIGURATION); } void bisexec_reset(const char *const *argv) { dumpconfig(RESET_CONFIGURATION); } void bisexec_execute(const char *const *argv) { always_dumpexecsettings(); serv_checkstdoutexit(); } void bisexec_shutdown(const char *const *argv) { /* This is only reached if the serviceuser_uid test in * process.c:servicerequest() fails (we have to handle the * shutdown request there, unfortunately). */ fputs("uservd: builtin service shutdown: permission denied\n",stderr); _exit(-1); } static void serv_resetsignal(int signo) { struct sigaction sig; sig.sa_handler= SIG_DFL; sigemptyset(&sig.sa_mask); sig.sa_flags= 0; if (sigaction(signo,&sig,0)) serv_syscallfail("reset signal handler"); } static const char *see_loginname(void) { return serviceuser; } static const char *see_home(void) { return serviceuser_dir; } static const char *see_shell(void) { return serviceuser_shell; } static const char *see_service(void) { return service; } static const char *see_c_cwd(void) { return cwd; } static const char *see_c_loginname(void) { return loginname; } static const char *see_c_uid(void) { static char buf[CHAR_BIT*sizeof(uid_t)/3+4]; snyprintf(buf,sizeof(buf),"%lu",(unsigned long)request_mbuf.callinguid); return buf; } static const char *see_c_list(int n, const char *(*fn)(int i)) { int l, i; char *r; for (i=0, l=1; i= 0) fdarray[fdarray[fd].realfd].holdfd= fd; } for (fd=0; fdname; sei++) if (setenv(sei->name,sei->fn(),1)) serv_syscallfail("setenv standard"); for (i=0; ienvvarbufsize) { envvarbufsize= l; envvarbuf= xrealloc(envvarbuf,l); } snyprintf(envvarbuf,l,"USERV_U_%s",defvararray[i].key); if (setenv(envvarbuf,defvararray[i].value,1)) serv_syscallfail("setenv defvar"); } nargs= 0; if (setenvironment) for (cpp= setenvpfargs; *cpp; cpp++) nargs++; nargs++; if (execargs) for (pp= execargs; *pp; pp++) nargs++; if (!suppressargs) nargs+= request_mbuf.nargs; args= xmalloc(sizeof(char*)*(nargs+1)); targ= 0; if (setenvironment) for (cpp= setenvpfargs; *cpp; cpp++) args[targ++]= *cpp; args[targ++]= execpath; if (execargs) for (pp= execargs; *pp; pp++) args[targ++]= *pp; if (!suppressargs) for (i=0; i User service daemon and client specification <author>Ian Jackson and contributors <version>1.2.1~beta2</version> <abstract> This is a specification for a Unix system facility to allow one program to invoke another when only limited trust exists between them. <copyright> <prgn/userv/ is Copyright 1996-2021 Ian Jackson; Copyright 2021 Genome Research Limited apropos work by Matthew Vernon; Copyright 2000 Ben Harris; Copyright 2016-2017 Peter Benie. <p> <prgn/userv/ 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. <p> This program is distributed in the hope that it will be useful, but <em/without any warranty/; without even the implied warranty of <em/merchantability/ or <em/fitness for a particular purpose/. See the GNU General Public License for more details. <p> You should have received a copy of the GNU General Public License along with <prgn/userv/; if not, see <tt>http://www.gnu.org/licenses/</tt>. <toc sect> <chapt id="intro">Introduction <p> There is a daemon which invokes user service programs (henceforth `services') in response to requests by callers of a companion client program (henceforth the `client') and according to rules set forth in system-wide and user-specific configuration files. The companion client program is setuid root, and negotiates with the daemon through an <prgn/AF_UNIX/ socket and associated objects in a system-wide private directory set aside for the purpose. The user who wishes the service to be performed and calls the client is called the `calling user'; the process which calls the client is called the `calling process'. <p> The daemon and the client are responsible for ensuring that information is safely carried across the security boundary between the two users, and that the processes on either side cannot interact with each other in any unexpected ways. <chapt id="client">Client program usage <p> <example> userv <var/options/ [--] <var/service-user/ <var/service-name/ [<var/argument/ ...] userv <var/options/ -B|--builtin [--] <var/builtin-service/ [<var/info-argument/ ...] </example> <p> <var/service-user/ specifies which user is to provide the service. The user must be a login name, or <tt/-/ to indicate that the service user is to be the same as the calling user. <p> The service name is interpreted by the userv<footnote><prgn/userv/ is short for `user services', and is pronounced `you-serve'.</footnote> daemon on behalf of the service user. It will often be the name of a program. <sect>Options <p> Single-letter options may be combined as is usual with Unix programs, and the value for such an option may appear in the same argument or in the next. <taglist> <tag/<tt/-B// <tag/<tt/--builtin// <item> Requests that a builtin service be provided. This is equivalent to using the <prgn/--override/ option to specify a string consisting of <prgn/execute-builtin/ followed by the <var/builtin-service/ requested, and requesting a service user of <tt/-/ (indicating the calling user). <p> If the builtin service being requested requires a <var/service-argument/ then this must be supplied to the client in the same argument as the <var/builtin-service/. See <ref id="dirs-execution"> for details of the builtin services available, and <ref id="optoverride"> for details of the <prgn/--override/ options. <p> The actual service name passed will be the <var/builtin-service/; note that this actual service name (as opposed to the override data) and the <var/info-argument/s supplied will be ignored by most builtin services; the override mechanism and <prgn/execute-builtin/ will be used to ensure that the right builtin service is called with the right <var/service-argument/s. <tag/<tt/-f<var/fd/[<var/modifiers/]=<var/filename/// <tag/<tt/--file <var/fd/[<var/modifiers/]=<var/filename/// <item> Requests that data be copied in and out of the service using pipes. For each file or descriptor this will be done by creating a pipe, one end of which is passed to the service program and the other end of which is passed to a copy of <prgn/cat/ invoked by the client; the other file descriptor passed to <prgn/cat/ will be one inherited by the client program from the caller or one opened by the client program on behalf of the caller. <p> The descriptor in the service program that should be connected must be specified as <var/fd/, either as a decimal number or as one of the strings <tt/stdin/, <tt/stdout/ or <tt/stderr/. The next argument is a filename which will be opened by the client with the privileges of the calling user. <p> <var/modifiers/ is used to specify whether the file or descriptor is to be read from or written to. It consists of a series of words separated by commas. A comma may separate the <var/modifiers/ from the <var/fd/ and is required if <var/fd/ is not numeric. <p> The modifier words are: <taglist compact> <tag/<tt/read// <item> <tt/O_RDONLY/: Allow reading and not writing. May not be used with <tt/write/ or things that imply it. <tag/<tt/write// <item> <tt/O_WRONLY/: Allow writing and not reading. <em/Doesn't truncate or create/ without <tt/truncate/ or <tt/create/. <tt/write/ or things that imply it may not be used with <tt/read/. <tag/<tt/overwrite// <item> Equivalent to <tt/write,create,truncate/. <tag/<tt/create// <tag/<tt/creat// <item> <tt/O_CREAT/: Creates the file if necessary. Implies <tt/write/. <tag/<tt/exclusive// <tag/<tt/excl// <item> <tt/O_EXCL/: Fails if the file already exists. Implies <tt/write/ and <tt/create/. May not be used with <tt/truncate/. <tag/<tt/truncate// <tag/<tt/trunc// <item> <tt/O_TRUNC/: Truncate any existing file. Implies <tt/write/. May not be used with <tt/exclusive/. <tag/<tt/append// <item> <tt/O_APPEND/: All writes will append to the file. Implies <tt/write/ (but not <tt/create/). <tag/<tt/sync// <item> <tt/O_SYNC/: Do writes synchronously. Implies <tt/write/. <tag/<tt/wait// <tag/<tt/nowait// <tag/<tt/close// <item> These modifiers control the behaviour of the client, with respect to the pipes carrying data to and from the service, when the service terminates. See below. <tag/<tt/fd// <item> The <var/filename/ is not a filename but a numeric file descriptor. One or both of <tt/read/ and <tt/write/ must be specified, and no other words are allowed. The <var/filename/ may also be <tt/stdin/, <tt/stdout/ or <tt/stderr/ for file descriptor 0, 1 or 2 respectively. </taglist> <p> If no <var/modifiers/ which imply <tt/read/ or <tt/write/ are used it is as if <tt/write/ had been specified, except that if the filedescriptor 0 of the service is being opened (either specified numerically or with <tt/stdin/) it is as if <tt/overwrite/ had been specified (or <tt/write/ if only <tt/fd/ was specified). <p> The client will also use <tt/O_NOCTTY/ when opening files specified by the caller, to avoid changing its controlling terminal. <p> By default stdin, stdout and stderr of the service will be connected to the corresponding descriptors on the client. Diagnostics from the client and daemon will also appear on stderr. <p> If <tt/wait/ is specified, the client will wait for the pipe to be closed, and only exit after this has happened. This means that either the receiving end of the pipe connection was closed while data was still available at the sending end, or that the end of file was reached on the reading file descriptor. Errors encountered reading or writing in the client at this stage will be considered a system error and cause the client to exit with status 255, but will not cause disconnection at the service side since the service has already exited. <p> If <tt/close/ is specified the client will immediately close the pipe connection by killing the relevant copy of <prgn/cat/. If the service uses the descriptor it will get <prgn/SIGPIPE/ (or <prgn/EPIPE/) for a writing descriptor or end of file for a reading one; the descriptor opened by or passed to the client will also be closed. <p> If <tt/nowait/ is specified then the client will not wait and the connection will remain open after the client terminates. Data may continue to be passed between the inheritors of the relevant descriptor on the service side and the corresponding file or descriptor on the client side until either side closes their descriptor. This should not usually be specified for stderr (or stdout if <tt/--signals stdout/ is used) since diagnostics from the service side may arrive after the client has exited and be confused with expected output. <p> The default is <tt/wait/ for writing file descriptors and <tt/close/ for reading ones. <tag/<tt/-w<var/fd/=<var/action/// <tag/<tt/--fdwait<var/fd/=<var/action/// <item> Sets the action on termination of the service for the specified file descriptor; <var/action/ must be <tt/wait/, <tt/nowait/ or <tt/close/ as described above. The file descriptor must be specified as open when this option is encountered; this option is overridden by any later <prgn/--file/ or <prgn/--fdwait/ option - even by a <prgn/--file/ which does not specify an action on termination (in this case the default will be used, as described above). <tag/<tt/-D<var/name/=<var/value/// <tag/<tt/--defvar <var/name/=<var/value/// <item> Set a user-defined variable <var/name/ to <var/value/. These user-defined variables are made available in the configuration language as the parameters <tt/u-<var/name// and are passed to the service in environment variables <tt/USERV_U_<var/name//. <var/name/ may contain only alphanumerics and underscores, and must start with a letter. If several definitions are given for the same <var/name/ then only the last is effective. <tag/<tt/-t <var/seconds/// <tag/<tt/--timeout <var/seconds/// <item> Time out the service if it takes longer than <var/seconds/ seconds (a positive integer, in decimal). Timeout will produce a diagnostic on stderr and an exit status of 255. If <var/seconds/ is zero then no timeout will be implemented (this is the default). <tag/<tt/-S/ <var/method// <tag/<tt/--signals/ <var/method// <item> Affects the handling of the exit status when the service terminates due to a signal. (The client will always finish by calling <prgn/_exit/, so that only numbers from 0 to 255 can be returned and not the full range of numbers and signal indications which can be returned by the <prgn/wait/ family of system calls.) <p> The <var/method/ may be one of the following: <taglist compact> <tag/<var/status/ <item> The client's exit status will be <var/status/. This will not be distinguishable from the service really having exited with code <var/status/. This method is the default, with a <var/status/ of 254. <tag/<tt/number// <tag/<tt/number-nocore// <item> The client's exit status will be the number of the signal which caused the termination of the service. If <tt/number/ is used rather than <tt/number-nocore/ then 128 will be added if the service dumped core. <tt/number/ is very like the exit code mangling done by the Bourne shell. <tag/<tt/highbit// <item>The client's exit status will be the number of the signal with 128 added. If the service exits normally with an exit code of greater than 127 then 127 will be returned. <tag/<tt/stdout// <item> The service's numeric wait status as two decimal numbers (high byte first) and a textual description of its meaning will be printed to the client's standard output. It will be preceded by a newline and followed by an extra newline, and the numbers are separated from each other and from the textual description by single spaces. The exit status of the client will be zero, unless a system error occurs in which case no exit status and description will be printed to stdout, and an error message will be printed to stderr as usual. </taglist> <p> Problems such as client usage errors, the service not being found or permission being denied or failure of a system call are system errors. An error message describing the problem will be printed on the client's stderr, and the client's exit status will be 255. If the client dies due to a signal this should be treated as a serious system error. <tag/<tt/-H// <tag/<tt/--hidecwd// <item> Prevents the calling process's current directory name from being passed to the service; the null string will be passed instead. <tag/<tt/-P// <tag/<tt/--sigpipe// <item> If the service program is terminated due to a <prgn/SIGPIPE/ the exit status of the client will be zero, even if it would have been something else according to the exit status method specified. This option has no effect on the code and description printed if the exit status method <tt/stdout/ is in use. <tag/<tt/-h// <tag/<tt/--help// <tag/<tt/--copyright// <item> <tt/-h/ or <tt/--help/ prints the client's usage message; <tt/--copyright/ prints the copyright and lack of warranty notice. </taglist> <sect id="optoverride">Security-overriding options <p> There are also some options which are available for debugging and to allow the system administrator to override a user's policy. These options are available only if the client is called by root or if the calling user is the same as the service user. <taglist> <tag/<tt/--override <var/configuration-data/// <tag/<tt/--override-file <var/filename/// <item> Do not read the usual configuration files. Instead, the client sends <var/configuration-data/ (followed by a newline) or the contents of <var/filename/ (which is opened in the context of the client) to the daemon and the daemon uses that data instead. The <var/configuration-data/ must all be in one argument. It will have a single newline appended so that a single directive can easily be given, but if more than one directive is required it will have to contain one or more real newlines. <tag/<tt/--spoof-user <var/user/// <item> Pretend to the service that it is being called by <var/user/ (which may be a username or a uid). This will also affect the group and supplementary groups supplied to the service; they will be the standard group and supplementary groups for <var/user/. The <tt/--spoof-user/ option will <em/not/ affect which user is chosen if the service user is specified as just <tt/-/; in this case the service user will be the real calling user. </taglist> <chapt id="envir">Execution environment of the service program <p> The daemon which is handling the service user side of things will read configuration files to decide what to do. If it decides to allow the service to be provided it will fork a subprocess to execute the service. <p> The service will have no controlling terminal, but it will be a process group leader. <p> If the client is killed or times out or a file or descriptor being read or written by the client process gets an error then the service will be disconnected from the client. The client will return an exit status of 255 and some the service's pipes may be closed at the other end. The service will become a child of <prgn/init/. The service may well not notice the disconnection, though writing to a pipe after this may produce a <prgn/SIGPIPE/ and the facility exists to have a <prgn/SIGHUP/ sent to the service on disconnection. <sect>File descriptors <p> The service program's standard filedescriptors, and possibly other file descriptors, will be connected to pipes or to <prgn>/dev/null</>. The <prgn/userv/ client/daemon pair will arrange that data is copied between the files or file descriptors specified to to the client by the caller and these these pipes. <p> Pipes which may be written to will be closed if a write error occurs on the corresponding client-side file or descriptor, which may result in a <prgn/SIGPIPE/ in the service program; pipes open for reading will get <prgn/EOF/ if the client-side file descriptor gets <prgn/EOF/ or an error. <p> If the service closes one of its reading file descriptors the writing end of the corresponding pipe will generate a <prgn/SIGPIPE/ when attempts are made by the client/daemon pair to write to it. This will not be considered an error; rather, the relevant pipe will be discarded and the corresponding file or file descriptor held by the client will be closed. <p> Likewise, if one of the file descriptors held by the client for writing by the service is a pipe whose other end is closed by the caller then the client/daemon pair will see an error when trying to copy data provided by the service. This too will not be considered an error; rather, the pipe correspondong to that descriptor will be closed and any further writes will cause the service to get a <prgn/SIGPIPE/. <p> Note that not all write errors or broken pipes on file descriptors may be visible to the service, since buffered data may be discarded by the operating system and there will be a finite interval between the error happening and the service being disconnected from the client or the next write causing a <prgn/SIGPIPE/. <p> Read errors on file descriptors (and disconnection) will only be visible to the service and distinguishable from normal end of file if <prgn/disconnect-hup/ is in effect. <p> Read and write errors (other than broken pipes, as described above) will always be visible to the caller; they are system errors, and will therefore cause the client to print an error message to stderr and return with an exit status of 255. <p> If the main service program process exits while it still has running children any file descriptors held by those children can remain open, depending on the use of <tt/wait/, <tt/nowait/ or <tt/close/ for the relevant file descriptor in the client's arguments. By default writing filedescriptors remain open and the client will wait for them to be closed at the service end, and reading file descriptors are closed immediately. These leftover child processes will not get a any <prgn/SIGHUP/ even if a read or write error occurs or the client disconnects before then. <sect>Environment <p> The service will have some information in environment variables: <taglist compact> <tag/<tt/USERV_USER// <item> The login name of the calling user. If the <prgn/LOGNAME/ variable is set (or, if that is unset, if the <prgn/USER/ variable is set) in the environment passed to the client by the caller then the password entry for that login name will be looked up; if that password entry's uid is the same as that of the calling process then that login name will be used, otherwise (or if neither <prgn/LOGNAME/ nor <prgn/USER/ is set) the calling process's uid will be looked up to determine their login name (and if this lookup fails then the service will not be invoked). <tag/<tt/USERV_UID// <item> The uid of the calling process. <tag/<tt/USERV_GID// <item> The gid and supplementary group list of the calling process: first the group in gid and then those in the supplementary group list, in decimal, separated by spaces. <tag/<tt/USERV_GROUP// <item> The group names of the calling process, listed in the same way as the ids are in <prgn/USERV_GID/. If no name can be found for any of the calling process's group(s) then the service will not be invoked. <tag/<tt/USERV_CWD// <item> The client's current working directory name (this directory may not be accessible to the service). If it could not be determined or the <prgn/--hidecwd/ flag was used then this variable will be set to an empty string (this is not considered an error). <tag/<tt/USERV_SERVICE// <item> The service name requested by the caller. <tag/<tt/USERV_U_<var/name/// <item> The value supplied to the client by the caller using -D<var/name/. </taglist> <prgn/HOME/, <prgn/PATH/, <prgn/SHELL/, <prgn/LOGNAME/ and <prgn/USER/ will be set appropriately (according to the details of the service user). <chapt id="config">Service-side configuration <p> Which services may be run by whom and under what conditions is controlled by configuration files. <p> The daemon will read these files in order. Certain directives in the files modify the daemon's execution settings for invoking the service, for example allowing certain file descriptors to be specified by the client or specifying which program to execute to provide the service. <p> The <em/last/ instance of each such setting will take effect. The directives which specify which program to execute will not stop the configuration file from being read; they will be remembered and will only take effect if they are not overridden by a later directive. <p> The daemon will first read <tt>/etc/userv/system.default</>. Then, by default (this behaviour may be modified), it will read a per-user file <tt>~/.userv/rc</>, if it exists and the service user's shell is in <tt>/etc/shells</>. Finally it will read <tt>/etc/userv/system.override</>. <p> When it has read all of these files it will act according to the currently values of of the execution settings. <sect>Configuration file syntax <p> The configuration file is a series of directives, usually one per line. The portion of a line following a hash character <tt/#/ is taken as a comment and ignored. Each directive consists of a series of tokens separated by linear whitespace (spaces and tabs); tokens may be words consisting of non-space characters, or, where a string is required, a string in double quotes. Double-quoted strings may contain the following backslash escapes: <taglist compact> <tag/<tt/\n//<item>newline <tag/<tt/\t//<item>tab <tag/<tt/\r//<item>carriage return <tag/<tt/\<var/OOO///<item>character whose octal code is <var/OOO/ <tag/<tt/\x<var/XX///<item>character whose hex code is <var/XX/ <tag/<tt/\<var/punctuation///<item>literal punctuation character (eg <tt/\\/, <tt/\"/) <tag/<tt/\<var/newline// (ie, backslash at end of line)/ <item>string continues on next line </taglist> <p> Relative pathnames in directives are relative to the service program's current directory (usually the service user's home directory). Pathnames starting with the two characters <tt>~/</> are taken to be relative to the service user's home directory. <sect id="directives">Configuration file directives <p> <sect1 id="dirs-immediate">Immediate directives <p> The following directives take effect immediately: <taglist> <tag/<tt/cd <var/pathname/// <item> Change directory in the service program. <prgn/cd/ is cumulative. It is an error if the directory cannot be changed to. <p> <prgn/cd/ should not be used between <prgn/execute-from-directory/ and the invocation of the service program, as the test for the availability of the service program would be done with the old current directory and the actual execution with the new (probably causing an error). <tag/<tt/eof// <item> Stop reading the configuration file in question, as if end of file had been reached. Any control constructs (<prgn/if/, <prgn/catch-quit/ or <prgn/errors-push/) which were started in that file will be considered finished. Parsing will continue in the file which caused the file containing the <prgn/eof/ to be read. <tag/<tt/quit// <item> Stop reading configuration files and act immediately on the current settings. The behaviour of <prgn/quit/ is subject to the <prgn/catch-quit/ control construct. <tag/<tt/include <var/filename/// <tag/<tt/include-ifexist <var/filename/// <item> Read the configuration file <var/filename/, and then return to this file and continue parsing it with the next directive. It is an error if the file cannot be opened and read, unless <prgn/include-ifexist/ is used and the file does not exist, in which case the directive is silently ignored. <tag/<tt/include-lookup <var/parameter/ <var/directory/// <tag/<tt/include-lookup-all <var/parameter/ <var/directory/// <item> Read the configuration file in <var/directory/ whose name is the value of <var/parameter/ (see the description of <prgn/if/, <ref id="dirs-control">). If <var/parameter/ has several values they will be tried in order; with <prgn/include-lookup/ this search will stop when one is found, but with <prgn/include-lookup-all/ the search will continue and any files appropriate to other values will be read too. <p> If none of the parameter's values had a corresponding file then the file <tt/:default/ will be read, if it exists. If <var/parameter/'s list of values was empty then the file <tt/:none/ will be tried first and read if it exists, otherwise <tt/:default/ will be tried. <p> It is not an error for any of the files (including <tt/:default/) not to exist, but it is an error if a file exists and cannot be read or if the directory cannot be accessed. <p> A translation will be applied to values before they are used to construct a filename, so that the lookup cannot access dotfiles or files in other directories: values starting with full stops will have a colon prepended (making <tt/:./), colons will be doubled, and each slash will be replaced with a colon followed by a hyphen <tt>:-</>. A parameter value which is the empty string will be replaced with <tt/:empty/ (note that this is different from a parameter not having any values). <p> (In older versions of userv, a different translation was applied: See <tt>https://bugs.debian.org/837391</tt>. The old translation can be requested (for subsequent directives) with <tt/include-lookup-quote-old/, which is undone by <tt/include-lookup-quote-new/ and <tt/reset/.) <tag/<tt/include-directory <var/directory/// <item> Read configuration from all files in directory <var/directory/ which are plain files whose names consist only of alphanumerics and hyphens and start with an alphanumeric. They will be read in lexical order. It is an error for the directory not to exist or for it or any of the files found not to be read successfully, or for anything with an appropriate name not to be a plain file or a symbolic link to a plain file. <tag/<tt/error <var/text .../// <item> Causes an error whose message includes the descriptive string <var/text/. <var/text/ may consist of several tokens with intervening whitespace. The whitespace will be included in the message as found in the configuration file: all the characters until the end of the line will be included verbatim, unless they are part of a double-quoted string, in which case the usual meaning of the string (i.e., after backslash escape processing) will be used. Comments and linear whitespace at the end of the line (or just before the comment) will still be ignored. <tag/<tt/message <var/text .../// <item> Causes a message including the descriptive string <var/text/ to be delivered as if it were an error message, but does not actually cause an error. </taglist> <sect1 id="dirs-delayed">Directives with delayed effect <p> The following directives have no immediate effect, but are remembered and have an effect on later processing of the configuration files. <taglist> <tag/<tt/user-rcfile <var/filename/// <item> Specifies that the file <var/filename/ should be read instead of the user's <tt>~/.userv/rc</>. This does <em/not/ happen immediately; instead, the setting is remembered and used after the <prgn/system.default/ configuration file has been read. This directive has no effect in a user's configuration file or in the <prgn/system.override/ file, as the user's configuration file has already been found and read by then and will not be re-read. <tag/<tt/errors-to-stderr// <item> Causes error messages to be delivered to the client's stderr. <tag/<tt/errors-to-file/ <var/filename// <item> Error messages will be written to <var/filename/, which will be opened in the context of and with the privileges of the service user. <tag/<tt/errors-to-syslog/ [<var/facility/ [<var/level/]]/ <item> Error messages will be delivered using <prgn/syslog/. The default <var/facility/ is <tt/user/; the default <var/level/ is <tt/error/. </taglist> <sect1 id="dirs-control">Control structure directives <p> The following directives are used to create control structures. If the end of the file is encountered before the end of any control structure which was started inside it then that control structure is considered finished. This is not an error. <taglist> <tag/<tt/if <var/condition/// <tag/<tt/elif <var/condition/// <tag/<tt/else// <tag/<tt/fi// <item> Lines following <prgn/if/ are interpreted only if the condition is true. Many conditions are properties of parameter values. Most parameters have a single string as a value; however, some may yield zero or several strings, in which case the condition is true if it is true of any of the strings individually. Parameters are described below. <p> The conditions are: <taglist compact> <tag/<tt/glob <var/parameter/ <var/glob-pattern/ ...// <item> The value of the parameter whose name is given matches one of the glob patterns (anchored at both ends; backslashes can be used to escape metacharacters). <tag/<tt/range <var/parameter/ <var/min/ <var/max/// <item> The value of the parameter is a nonnegative integer and lies within the range specified. <var/min/ or <var/max/ may be <tt/$/ to indicate no lower or upper limit, respectively. <tag/<tt/grep <var/parameter/ <var/filename/// <item> The <var/filename/ refers to a file one of whose lines is the value of the parameter (leading or trailing whitespace on each line and empty lines in the file are ignored). It is an error for the file not to be opened and read. <tag/<tt/! <var/condition/// <item> The <var/condition/ is <em/not/ true. <tag/Conjunctions: <tt/&/ and <tt/|// <item> <example> ( <var/condition/ & <var/condition/ & <var/condition/ ... ) </example> is true if all the listed conditions are true; where <tt/|/ is used it is true if any of them is true. Newlines must be used to separate one condition from the next, as shown, and the parentheses are mandatory. These conjunctions do not do lazy evaluation. </taglist> <p> The parameters are: <taglist compact> <tag/<tt/service// <item> The service name specified when the client was called. <tag/<tt/calling-user// <item> Two strings: the login name of the calling user (determined as for <prgn/USERV_USER/, above) and the calling uid (represented in decimal). <tag/<tt/calling-group// <item> Several strings: the primary and supplementary group names and gids (in decimal) of the calling process. All the group names come first, and then the gids. If the first supplementary group is the same as the primary group then it is elided. <tag/<tt/calling-user-shell// <item> The calling user's shell, as listed in the password entry for the calling login name (as determined for <prgn/USERV_USER/, above). <tag/<tt/service-user// <item> Two strings: the name of the service user (as specified to the client) and their uid (represented in decimal). <tag/<tt/service-group// <item> Several strings: the primary and supplementary group names and gids (in decimal) of the service user. <tag/<tt/service-user-shell// <item> The service user's shell, as listed in their password entry. <tag/<tt/u-<var/name/// <item> The value of the user-defined variable <var/name/ passed by the caller using the <prgn/--defvar/ command-line option to the client. If the variable was not defined then this parameter is an empty list of strings; in this case any condition which tests it will be false, and <tt/include-lookup/ on it will read the <tt/:none/ file, or <tt/:default/ if <tt/:none/ is not found. </taglist> <tag/<tt/errors-push// <tag/<tt/srorre// <item> Stacks the error handling behaviour currently in effect. Any changes to error handling will take effect only between <prgn/errors-push/ and <prgn/srorre/. <tag/<tt/catch-quit// <tag/<tt/hctac// <item> Any use of <prgn/quit/ inside <prgn/catch-quit/ will merely cause the parsing to continue at <prgn/hctac/ instead. Any control constructs started since the <prgn/catch-quit/ will be considered finished if a <prgn/quit/ is found. <p> If an error occurs inside <prgn/catch-quit/ the execution settings will be reset (as if by the <prgn/reset/ directive) and parsing will likewise continue at <prgn/hctac/. <p> If a lexical or syntax error is detected in the same configuration file as the <prgn/catch-quit/, while looking for the <prgn/hctac/ after an error or <prgn/quit/, that new error will not be caught. </taglist> <sect1 id="dirs-execution">Directives for changing execution settings <p> The following directives modify the execution settings; the server will remember the fact that the directive was encountered and act on it only after all the configuration has been parsed. The <em/last/ directive which modifies any particuar setting will take effect. <taglist> <tag/<tt/reject// <item> Reject the request. <prgn/execute/, <prgn/execute-from-directory/ and <prgn/execute-from-path/ will change this setting. <tag/<tt/execute <var/program/ [<var/argument/ ...]// <item> Execute the program <var/program/, with the arguments as specified, followed by any arguments given to the client if <prgn/no-suppress-args/ is in effect. It is an error for the execution to fail when it is attempted (after all the configuration has been parsed). If <var/program/ does not contain a slash it will be searched for on the service user's path. <tag/<tt/execute-from-directory <var/pathname/ [<var/argument/ ...]// <item> Take all the characters after the last slash of the service name specified when the client was called, and execute that program in the directory named by <var/pathname/ as if it had been specified for <var/execute/. The part of the service name used may contain only alphanumerics and hyphens and must start with an alphanumeric (and it must be non-empty), otherwise it is an error. <p> This directive is ignored if the relevant program does not exist in the directory specified; in this case the program to execute is left at its previous setting (or unset, if it was not set before). <p> It is an error for the test for the existence of the program to fail other than with a `no such file or directory' indication. It is also an error for the execution to fail if and when it is attempted (after all the configuration has been parsed). <tag/<tt/execute-from-path// <item> <var/service/ is interpreted as a program on the default <prgn/PATH/ (or as a pathname of an executable, if it contains a <tt>/</>). This directive is <em/very dangerous/, and is only provided to make the <prgn/--override/ options effective. It should not normally be used. It is an error for the execution to fail when it is attempted (after all the configuration has been parsed). <tag/<tt/execute-builtin <var/service-name/ <var/service-arguments// <item> Executes the builtin service <var/service-name/. These builtin services display information about the server and/or the request, and ignore any arguments passed from the service side except possibly to print them as part of their output. They write their results to their standard output (i.e., wherever file descriptor 1 is directed). The builtin services are: <taglist compact> <tag/<tt/execute// <item> Displays the execution settings, defined variables, arguments, etc. with which the builtin service was invoked. <tag/<tt/environment// <item> Displays the environment variable settings with which the builtin service was invoked. <tag/<tt/parameter <var/parameter/// <item> Displays the values of the service configuration language parameter specified. <tag/<tt/version// <item> Displays the version string and compilation details of the uservd server program. <tag/<tt/reset// <item> Displays the default reset configuration (evaluated when <prgn/reset/ is found in a configuration file, or when an error is caught by <prgn/catch-quit/). <tag/<tt/toplevel// <item> Displays the top-level default configuration (the configuration data, evaluated by the server, which calls all the other configuration files). <tag/<tt/override// <item> Displays the top-level override configuration (the configuration data, evaluated by the server, which causes all the other configuration data to be parsed). <tag/<tt/help// <item> Displays a list of the understood builtin service names and arguments. </taglist> In the future other builtin services may be defined which do more than just print information. <tag/<tt/set-environment// <tag/<tt/no-set-environment// <item> Runs <tt>/etc/environment</> to set the service user's environment. This adds the overhead of invoking a shell, but doesn't cause any shell (de)mangling of the service's arguments. This is achieved by invoking <example> .../program arg arg arg ... </example> as <example> /bin/sh -c '. /etc/environment; exec "$@"' - .../program arg arg arg ... </example> <prgn/no-set-environment/ cancels the effect of <prgn/set-environment/. <tag/<tt/no-suppress-args// <tag/<tt/suppress-args// <item> Include any arguments given to the client as arguments to the program invoked as a result of an <prgn/execute/, <prgn/execute-from-directory/ or <prgn/execute-from-path/ directive. <prgn/suppress-args/ undoes the effect of <prgn/no-suppress-args/. <tag/<tt/require-fd <var/fd-range/ read|write// <item> Insist that the filedescriptor(s) be opened for reading resp. writing. It is an error if any descriptor marked as required when the service is about to be invoked (after the configuration has been parsed) was not specified when the client was invoked. Each file descriptor has a separate setting, and the last one of <prgn/require-fd/, <prgn/allow-fd/, <prgn/ignore-fd/, <prgn/null-fd/ or <prgn/reject-fd/ which affected a particular file descriptor will take effect. <p> <var/fd-range/ may be a single number, two numbers separated by a hyphen, or one number followed by a hyphen (indicating all descriptors from that number onwards). It may also be one of the words <tt/stdin/, <tt/stdout/ or <tt/stderr/. Open-ended file descriptor rangers are allowed only with <prgn/reject-fd/ and <prgn/ignore-fd/, as otherwise the service program would find itself with a very large number of file descriptors open. <p> When the configuration has been parsed, and before the service is about to be executed, stderr (fd 2) must be required or allowed (<prgn/require-fd/ or <prgn/allow-fd/) for writing; this is so that the error message printed by the server's child process if it cannot <prgn/exec/ the service program is not lost. <tag/<tt/allow-fd <var/fd-range/ [read|write]// <item> Allow the descriptor(s) to be opened for reading resp. writing, or either if neither <tt/read/ nor <tt/write/ is specified. If a particular descriptor not specified by the client then it will be open onto <tt>/dev/null</> (for reading, writing, or both, depending on whether <tt/read/, <tt/write/ or neither was specified). <tag/<tt/null-fd <var/fd-range/ [read|write]// <item> Specify that the descriptor(s) be opened onto <prgn>/dev/null</> for reading resp. writing, or both if neither <tt/read/ nor <tt/write/ is specified. Any specification of these file descriptors by the client will be silently ignored; the client will see its ends of the descriptors being closed immediately. <tag/<tt/reject-fd <var/fd-range/// <item> Do not allow the descriptor(s) to be specified by the client. It is an error if any descriptor(s) marked for rejection are specified when the service is about to be invoked (after the configuration has been parsed). <tag/<tt/ignore-fd <var/fd-range/// <item> Silently ignore any specification by the client of those descriptor(s). The pipes corresponding to these descriptors will be closed just before the service is invoked. <tag/<tt/disconnect-hup// <tag/<tt/no-disconnect-hup// <item> Causes the service's process group to get a <prgn/SIGHUP/ if the client disconnects before the main service process terminates. <prgn/no-disconnect-hup/ cancels <prgn/disconnect-hup/. <p> If one of the reading descriptors specified when the client is called gets a read error, or if the service is disconnected for some other reason, then the <prgn/SIGHUP/ will be delivered <em/before/ the writing end(s) of the service's reading pipe(s) are closed, so that the client can distinguish disconnection from reading EOF on a pipe. <tag/<tt/reset// <item> Resets the execution settings to the default. This is equivalent to: <example> cd ~/ reject no-set-environment suppress-args allow-fd 0 read allow-fd 1-2 write reject-fd 3- disconnect-hup </example> </taglist> If no <prgn/execute/, <prgn/execute-from-path/, <prgn/execute-from-directory/ or <prgn/builtin/ is interpreted before all the files are read then the request is rejected. <sect id="configerrors">Errors in the configuration file <p> If a syntax error or other problem occurs when processing a configuration file then a diagnostic will be issued, to wherever the error messages are currently being sent (see the <prgn/errors-/ family of directives, above). <p> The error will cause processing of the configuration files to cease at that point, unless the error was inside a <prgn/catch-quit/ construct. In this case the settings controlling the program's execution will be reset to the defaults as if a <prgn/reset/ directive had been issued, and parsing continues after <prgn/hctac/. <sect id="defaults">Defaults <p> The default configuration processing is as if the daemon were parsing an overall configuration file whose contents were as follows: <example> reset user-rcfile ~/.userv/rc errors-to-stderr include /etc/userv/system.default if grep service-user-shell /etc/shells errors-push catch-quit include-ifexist <var/file specified by most recent user-rcfile directive/ hctac srorre fi include /etc/userv/system.override quit </example> <p> If one of the <prgn/--override/ options to the client is used then it will instead be as if the daemon were parsing an overall configuration as follows: <example> reset errors-to-stderr include <var/file containing configuration data sent by client/ quit </example> <chapt id="ipass">Information passed through the client/daemon combination <p> The information described below is the only information which passes between the caller and the service. <list> <item> The service name supplied by the caller is available in the configuration language for deciding whether and which service program to invoke, in the <prgn/service/ parameter, and is used by the <prgn/execute-from-directory/ and <prgn/execute-from-path/ configuration directives. It is usually used to select which service program to invoke. It is also passed to the service program in the <prgn/USERV_SERVICE/ environment variable. <item> File descriptors specified by the client and allowed according to the configuration language will be connected. Each file descriptor is opened for reading or writing. Communication is via pipes, one end of each pipe being open on the appropriate file descriptor in the service program (when it is invoked) and the other end being held by the client process, which will read and write files it opens on behalf of its caller or file descriptors it is passed by its caller. <p> Data may be passed into the service through reading pipes and out of it through writing pipes. These pipes can remain open only until the service and client have terminated, or can be made to stay open after the client has terminated and (if the service program forks) the main service process has exited; the behaviour is controlled by options passed to the client by its caller. <p> The caller can arrange that a writing pipe be connected to a pipe or similar object and cause attempts to write to that descriptor by the service to generate a <prgn/SIGPIPE/ (or <prgn/EPIPE/ if <prgn/SIGPIPE/ is caught or ignored) in the service. <p> Likewise, the service can close filedescriptors specified for reading, which will cause the corresponding filedescriptors passed by the caller to be closed, so that if these are pipes processes which write to them will receive <prgn/SIGPIPE/ or <prgn/EPIPE/. <item> If <prgn/no-suppress-args/ is set then arguments passed to the client by its caller will be passed on, verbatim, to the service. <item> Fatal signals and system call failures experienced by the client will result in the disconnection of the service from the client and possibly some of the communication file descriptors described above; if <prgn/disconnect-hup/ is set then the service will also be sent a <prgn/SIGHUP/. <item> The value of the <prgn/LOGNAME/ (or <prgn/USER/) environment variable as passed to the client will be used as the login name of the calling user if the uid of the calling process matches the uid corresponding to that login name. Otherwise the calling uid's password entry will be used to determine the calling user's login name. <p> This login name and the calling uid are available in the configuration language in the <prgn/calling-user/ parameter and are passed to the service program in environment variables <prgn/USERV_USER/ and <prgn/USERV_UID/. <p> The shell corresponding to that login name (according to the password entry) is available as in the configuration language's <prgn/calling-user-shell/ parameter. <p> If no relevant password entry can be found then no service will be invoked. <item> The numeric values and textual names for calling gid and supplementary group list are available in the configuration language in the <prgn/calling-group/ parameter and are passed to the service in environment variables. <p> If no name can be found for a numeric group to which the calling process belongs then no service will be invoked. <item> The name of the current working directory in which the client was invoked is passed, if available and not hidden using <prgn/--hidecwd/, to the service program in the <prgn/USERV_CWD/ variable. This grants no special access to that directory unless it is a subdirectory of a directory which is executable (searchable) but not readable by the service user. <item> Settings specified by the caller using the <tt/--defvar <var/name/=<var/value// option to the client are available in the configuration language as the corresponding <tt/u-<var/name// parameters and are passed to the service program in environment variables <tt/USERV_U_<var/name//. <item> If the calling user is root or the same as the service user then options may be given to the client which bypass the usual security features; in this case other information may pass between the caller and the service. </list> <chapt id="notes">Applications and notes on use <p> <sect id="examples">Examples <p> The companion package, <prgn/userv-utils/, contains a selection of example services, some of which are useful tools in their own right. See the <prgn/README/ in its top-level directory for details. <sect id="standards">Standard services and directory management <p> In later versions of this specification standard service names and interfaces for common services such as mail delivery and WWW CGI scripts may be specified. <p> <prgn/userv/-using applications and system services which hide <prgn/userv/ behind wrapper scripts may need to store information in the user's filespace to preserve the correct placement of the security perimiters. Such applications should usually do so in a directory (created by them) <tt>~/.userv/<var/service/</>, where <var/service/ is the service name or application in question. <p> If desired, a dot-directory inside <tt>~/.userv</> may be used to avoid the user becoming confused by finding parts of a semi-privileged application's internal state in their filespace, and/or discourage them from fiddling with and thus corrupting it. <p> However, <prgn/userv/ applications should of course not rely for their global integrity and security on the integrity of the data on the user's side of the security boundary. <sect id="reducepriv">Reducing the number of absolutely privileged subsystems <p> Currently most Unix systems have many components which need to run as root, even though most of their activity does not strictly require it. This gives rise to a large and complex body of code which must be trusted with the security of the system. <p> If they were to use <prgn/userv/, many of these subsystems would no longer need any unusual privilege. <p> <prgn/cron/ and <prgn/at/, <prgn/lpr/ and the system's mail transfer agent (<prgn/sendmail/, <prgn/smail/, <prgn/exim/ or the like) all fall into this category, though <prgn/userv/-based versions of these programs are not currently available. <sect id="noexcess">Do not give away excessive privilege to <prgn/userv/-using facilities <p> There is a danger that people reimplementing the facilities I mention above using <prgn/userv/ will discard much of the security benefit by using a naive implementation technique. This will become clearer with an example: <p> Consider the <prgn/lpr/ program. In current systems this needs to have an absolutely privileged component in order to support delayed printing without copying: when the user queues a file to be printed the filename is stored in the print queue, rather than a copy of it, and the printer daemon accesses the file directly when it is ready to print the job. In order that the user can print files which are not world-readable the daemon is given root privilege so that it can open the file in the context of the user, rather than its own. <p> A simple-minded approach to converting this scheme to use <prgn/userv/ might involve giving the printer daemon (the <prgn/lp/ user) the ability to read the file by allowing them to run <prgn/cat/ (or a special-purpose file-reading program) as any user. The <prgn/lpr/ program would use a <prgn/userv/ service to store the filename in the printer daemon's queues, and the daemon would read the file later when it felt like it. <p> However, this would allow the printer daemon to read any file on the system, whether or not someone had asked for it to be printed. Since many files will contain passwords and other security-critical information this is nearly as bad as giving the daemon root access in the first place. Any security holes in the print server which allow a user to execute commands as the <prgn/lp/ user will give the user the ability to read any file on the system. <p> Instead, it is necessary to keep a record of which files the daemon has been asked to print <em/outside/ the control of the print daemon. This record could be kept by a new root-privileged component, but this is not necessary: the record of which files a user has asked to be printed can be kept under the control of the user in question. The submission program <prgn/lpr/ will make a record in an area under the user's control before communicating with the print server, and the print server would be given the ability to run a special file-reading program which would only allow files to be read which were listed in the user's file of things they'd asked to print. <p> Now security holes in most of the printing system do not critically affect the security of the entire system: they only allow the attacker to read and interfere with print jobs. Bugs in the programs run by the print server to read users' files (and to remove entries from the list of files when it has done with them) will still be serious, but this program can be quite simple. <p> Similar considerations apply to many <prgn/userv/-based versions of facilities which currently run as root. <p> It is debatable whether the user-controlled state should be kept in the user's filespace (in dotfiles, say) or kept in a separate area set aside for the purpose; however, using the user's home directory (and possibly creating a separate subdirectory of it as a dotfile to contain subsystem state) has fewer implications for the rest of the system and makes it entirely clear where the security boundaries lie. <sect id="notreally"><prgn/userv/ can often replace <prgn/sudo/, but not <prgn/really/ <p> <prgn/userv/ is not intended as a general-purpose system administration tool with which system administrators can execute arbitrary programs like text editors as root (or other system users) when they need to. It is unsuitable for this purpose precisely because it enforces a strong separation between the calling and the called program, which is undesirable in this context. <p> However, its use when restricted to running particular programs in particular ways is very similar to many common uses of <prgn/sudo/<footnote><prgn/sudo/ is a program which allows users to execute certain programs as root, according to configuration files specified by the system administrator.</footnote>. <prgn/userv/ is generally much better than restricted <prgn/sudo/, because it protects the called program much more strongly from bad environmental conditions set up by the caller. Most programs that one might want to run via restricted <prgn/sudo/, have not been designed to run in a partially hostile environment. <prgn/userv/ allows these programs to be run in a safer environment and should be used instead. <sect id="stdinerr">Error handling and input streams (eg stdin) <p> When the service program is reading from a file descriptor connected to the calling side, the fd that the service program refers to a pipe set up by <prgn/userv/ and not to the same object as was presented by the caller. <p> Therefore if there is some kind of error it is possible for the service-side fd to give premature end of file. If it is important to tell whether all of the intended data has been received by the service program, the datastream must contain an explicit end-of-file indication of some kind. <p> For example, consider a <prgn/userv/ service for submitting a mail message, where message is supplied on the service's stdin. However, if the calling process is interrupted before it has written all of the message, the service program will get EOF on the message data. In a naive arrangement this would cause a half-complete message to be sent. To prevent this, it is necessary to adopt some kind of explicit end indication; for example, the end of the message could be signalled by a dot on a line by itself, and dots doubled, as in SMTP. Then the service program would know when the entire message had been received, and could avoid queueing incomplete messages. <sect id="nogeneral">Don't give access to general-purpose utilities <p> Do not specify general purpose programs like <prgn/mv/ or <prgn/cat/ in <prgn/execute-/ directives without careful thought about their arguments, and certainly not if <prgn/no-suppress-args/ is specified. If you do so it will give the caller much more privilige than you probably intend. <p> It is a shame that I have to say this here, but inexperienced administrators have made similar mistakes with programs like <prgn/sudo/. </book> ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������work/spec.sgml.in�����������������������������������������������������������������������������������0000664�0000000�0000000�00000153045�14163725562�011176� 0����������������������������������������������������������������������������������������������������ustar ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<!doctype debiandoc system> <book> <title>User service daemon and client specification <author>Ian Jackson and contributors <version></version> <abstract> This is a specification for a Unix system facility to allow one program to invoke another when only limited trust exists between them. <copyright> <prgn/userv/ is Copyright 1996-2021 Ian Jackson; Copyright 2021 Genome Research Limited apropos work by Matthew Vernon; Copyright 2000 Ben Harris; Copyright 2016-2017 Peter Benie. <p> <prgn/userv/ 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. <p> This program is distributed in the hope that it will be useful, but <em/without any warranty/; without even the implied warranty of <em/merchantability/ or <em/fitness for a particular purpose/. See the GNU General Public License for more details. <p> You should have received a copy of the GNU General Public License along with <prgn/userv/; if not, see <tt>http://www.gnu.org/licenses/</tt>. <toc sect> <chapt id="intro">Introduction <p> There is a daemon which invokes user service programs (henceforth `services') in response to requests by callers of a companion client program (henceforth the `client') and according to rules set forth in system-wide and user-specific configuration files. The companion client program is setuid root, and negotiates with the daemon through an <prgn/AF_UNIX/ socket and associated objects in a system-wide private directory set aside for the purpose. The user who wishes the service to be performed and calls the client is called the `calling user'; the process which calls the client is called the `calling process'. <p> The daemon and the client are responsible for ensuring that information is safely carried across the security boundary between the two users, and that the processes on either side cannot interact with each other in any unexpected ways. <chapt id="client">Client program usage <p> <example> userv <var/options/ [--] <var/service-user/ <var/service-name/ [<var/argument/ ...] userv <var/options/ -B|--builtin [--] <var/builtin-service/ [<var/info-argument/ ...] </example> <p> <var/service-user/ specifies which user is to provide the service. The user must be a login name, or <tt/-/ to indicate that the service user is to be the same as the calling user. <p> The service name is interpreted by the userv<footnote><prgn/userv/ is short for `user services', and is pronounced `you-serve'.</footnote> daemon on behalf of the service user. It will often be the name of a program. <sect>Options <p> Single-letter options may be combined as is usual with Unix programs, and the value for such an option may appear in the same argument or in the next. <taglist> <tag/<tt/-B// <tag/<tt/--builtin// <item> Requests that a builtin service be provided. This is equivalent to using the <prgn/--override/ option to specify a string consisting of <prgn/execute-builtin/ followed by the <var/builtin-service/ requested, and requesting a service user of <tt/-/ (indicating the calling user). <p> If the builtin service being requested requires a <var/service-argument/ then this must be supplied to the client in the same argument as the <var/builtin-service/. See <ref id="dirs-execution"> for details of the builtin services available, and <ref id="optoverride"> for details of the <prgn/--override/ options. <p> The actual service name passed will be the <var/builtin-service/; note that this actual service name (as opposed to the override data) and the <var/info-argument/s supplied will be ignored by most builtin services; the override mechanism and <prgn/execute-builtin/ will be used to ensure that the right builtin service is called with the right <var/service-argument/s. <tag/<tt/-f<var/fd/[<var/modifiers/]=<var/filename/// <tag/<tt/--file <var/fd/[<var/modifiers/]=<var/filename/// <item> Requests that data be copied in and out of the service using pipes. For each file or descriptor this will be done by creating a pipe, one end of which is passed to the service program and the other end of which is passed to a copy of <prgn/cat/ invoked by the client; the other file descriptor passed to <prgn/cat/ will be one inherited by the client program from the caller or one opened by the client program on behalf of the caller. <p> The descriptor in the service program that should be connected must be specified as <var/fd/, either as a decimal number or as one of the strings <tt/stdin/, <tt/stdout/ or <tt/stderr/. The next argument is a filename which will be opened by the client with the privileges of the calling user. <p> <var/modifiers/ is used to specify whether the file or descriptor is to be read from or written to. It consists of a series of words separated by commas. A comma may separate the <var/modifiers/ from the <var/fd/ and is required if <var/fd/ is not numeric. <p> The modifier words are: <taglist compact> <tag/<tt/read// <item> <tt/O_RDONLY/: Allow reading and not writing. May not be used with <tt/write/ or things that imply it. <tag/<tt/write// <item> <tt/O_WRONLY/: Allow writing and not reading. <em/Doesn't truncate or create/ without <tt/truncate/ or <tt/create/. <tt/write/ or things that imply it may not be used with <tt/read/. <tag/<tt/overwrite// <item> Equivalent to <tt/write,create,truncate/. <tag/<tt/create// <tag/<tt/creat// <item> <tt/O_CREAT/: Creates the file if necessary. Implies <tt/write/. <tag/<tt/exclusive// <tag/<tt/excl// <item> <tt/O_EXCL/: Fails if the file already exists. Implies <tt/write/ and <tt/create/. May not be used with <tt/truncate/. <tag/<tt/truncate// <tag/<tt/trunc// <item> <tt/O_TRUNC/: Truncate any existing file. Implies <tt/write/. May not be used with <tt/exclusive/. <tag/<tt/append// <item> <tt/O_APPEND/: All writes will append to the file. Implies <tt/write/ (but not <tt/create/). <tag/<tt/sync// <item> <tt/O_SYNC/: Do writes synchronously. Implies <tt/write/. <tag/<tt/wait// <tag/<tt/nowait// <tag/<tt/close// <item> These modifiers control the behaviour of the client, with respect to the pipes carrying data to and from the service, when the service terminates. See below. <tag/<tt/fd// <item> The <var/filename/ is not a filename but a numeric file descriptor. One or both of <tt/read/ and <tt/write/ must be specified, and no other words are allowed. The <var/filename/ may also be <tt/stdin/, <tt/stdout/ or <tt/stderr/ for file descriptor 0, 1 or 2 respectively. </taglist> <p> If no <var/modifiers/ which imply <tt/read/ or <tt/write/ are used it is as if <tt/write/ had been specified, except that if the filedescriptor 0 of the service is being opened (either specified numerically or with <tt/stdin/) it is as if <tt/overwrite/ had been specified (or <tt/write/ if only <tt/fd/ was specified). <p> The client will also use <tt/O_NOCTTY/ when opening files specified by the caller, to avoid changing its controlling terminal. <p> By default stdin, stdout and stderr of the service will be connected to the corresponding descriptors on the client. Diagnostics from the client and daemon will also appear on stderr. <p> If <tt/wait/ is specified, the client will wait for the pipe to be closed, and only exit after this has happened. This means that either the receiving end of the pipe connection was closed while data was still available at the sending end, or that the end of file was reached on the reading file descriptor. Errors encountered reading or writing in the client at this stage will be considered a system error and cause the client to exit with status 255, but will not cause disconnection at the service side since the service has already exited. <p> If <tt/close/ is specified the client will immediately close the pipe connection by killing the relevant copy of <prgn/cat/. If the service uses the descriptor it will get <prgn/SIGPIPE/ (or <prgn/EPIPE/) for a writing descriptor or end of file for a reading one; the descriptor opened by or passed to the client will also be closed. <p> If <tt/nowait/ is specified then the client will not wait and the connection will remain open after the client terminates. Data may continue to be passed between the inheritors of the relevant descriptor on the service side and the corresponding file or descriptor on the client side until either side closes their descriptor. This should not usually be specified for stderr (or stdout if <tt/--signals stdout/ is used) since diagnostics from the service side may arrive after the client has exited and be confused with expected output. <p> The default is <tt/wait/ for writing file descriptors and <tt/close/ for reading ones. <tag/<tt/-w<var/fd/=<var/action/// <tag/<tt/--fdwait<var/fd/=<var/action/// <item> Sets the action on termination of the service for the specified file descriptor; <var/action/ must be <tt/wait/, <tt/nowait/ or <tt/close/ as described above. The file descriptor must be specified as open when this option is encountered; this option is overridden by any later <prgn/--file/ or <prgn/--fdwait/ option - even by a <prgn/--file/ which does not specify an action on termination (in this case the default will be used, as described above). <tag/<tt/-D<var/name/=<var/value/// <tag/<tt/--defvar <var/name/=<var/value/// <item> Set a user-defined variable <var/name/ to <var/value/. These user-defined variables are made available in the configuration language as the parameters <tt/u-<var/name// and are passed to the service in environment variables <tt/USERV_U_<var/name//. <var/name/ may contain only alphanumerics and underscores, and must start with a letter. If several definitions are given for the same <var/name/ then only the last is effective. <tag/<tt/-t <var/seconds/// <tag/<tt/--timeout <var/seconds/// <item> Time out the service if it takes longer than <var/seconds/ seconds (a positive integer, in decimal). Timeout will produce a diagnostic on stderr and an exit status of 255. If <var/seconds/ is zero then no timeout will be implemented (this is the default). <tag/<tt/-S/ <var/method// <tag/<tt/--signals/ <var/method// <item> Affects the handling of the exit status when the service terminates due to a signal. (The client will always finish by calling <prgn/_exit/, so that only numbers from 0 to 255 can be returned and not the full range of numbers and signal indications which can be returned by the <prgn/wait/ family of system calls.) <p> The <var/method/ may be one of the following: <taglist compact> <tag/<var/status/ <item> The client's exit status will be <var/status/. This will not be distinguishable from the service really having exited with code <var/status/. This method is the default, with a <var/status/ of 254. <tag/<tt/number// <tag/<tt/number-nocore// <item> The client's exit status will be the number of the signal which caused the termination of the service. If <tt/number/ is used rather than <tt/number-nocore/ then 128 will be added if the service dumped core. <tt/number/ is very like the exit code mangling done by the Bourne shell. <tag/<tt/highbit// <item>The client's exit status will be the number of the signal with 128 added. If the service exits normally with an exit code of greater than 127 then 127 will be returned. <tag/<tt/stdout// <item> The service's numeric wait status as two decimal numbers (high byte first) and a textual description of its meaning will be printed to the client's standard output. It will be preceded by a newline and followed by an extra newline, and the numbers are separated from each other and from the textual description by single spaces. The exit status of the client will be zero, unless a system error occurs in which case no exit status and description will be printed to stdout, and an error message will be printed to stderr as usual. </taglist> <p> Problems such as client usage errors, the service not being found or permission being denied or failure of a system call are system errors. An error message describing the problem will be printed on the client's stderr, and the client's exit status will be 255. If the client dies due to a signal this should be treated as a serious system error. <tag/<tt/-H// <tag/<tt/--hidecwd// <item> Prevents the calling process's current directory name from being passed to the service; the null string will be passed instead. <tag/<tt/-P// <tag/<tt/--sigpipe// <item> If the service program is terminated due to a <prgn/SIGPIPE/ the exit status of the client will be zero, even if it would have been something else according to the exit status method specified. This option has no effect on the code and description printed if the exit status method <tt/stdout/ is in use. <tag/<tt/-h// <tag/<tt/--help// <tag/<tt/--copyright// <item> <tt/-h/ or <tt/--help/ prints the client's usage message; <tt/--copyright/ prints the copyright and lack of warranty notice. </taglist> <sect id="optoverride">Security-overriding options <p> There are also some options which are available for debugging and to allow the system administrator to override a user's policy. These options are available only if the client is called by root or if the calling user is the same as the service user. <taglist> <tag/<tt/--override <var/configuration-data/// <tag/<tt/--override-file <var/filename/// <item> Do not read the usual configuration files. Instead, the client sends <var/configuration-data/ (followed by a newline) or the contents of <var/filename/ (which is opened in the context of the client) to the daemon and the daemon uses that data instead. The <var/configuration-data/ must all be in one argument. It will have a single newline appended so that a single directive can easily be given, but if more than one directive is required it will have to contain one or more real newlines. <tag/<tt/--spoof-user <var/user/// <item> Pretend to the service that it is being called by <var/user/ (which may be a username or a uid). This will also affect the group and supplementary groups supplied to the service; they will be the standard group and supplementary groups for <var/user/. The <tt/--spoof-user/ option will <em/not/ affect which user is chosen if the service user is specified as just <tt/-/; in this case the service user will be the real calling user. </taglist> <chapt id="envir">Execution environment of the service program <p> The daemon which is handling the service user side of things will read configuration files to decide what to do. If it decides to allow the service to be provided it will fork a subprocess to execute the service. <p> The service will have no controlling terminal, but it will be a process group leader. <p> If the client is killed or times out or a file or descriptor being read or written by the client process gets an error then the service will be disconnected from the client. The client will return an exit status of 255 and some the service's pipes may be closed at the other end. The service will become a child of <prgn/init/. The service may well not notice the disconnection, though writing to a pipe after this may produce a <prgn/SIGPIPE/ and the facility exists to have a <prgn/SIGHUP/ sent to the service on disconnection. <sect>File descriptors <p> The service program's standard filedescriptors, and possibly other file descriptors, will be connected to pipes or to <prgn>/dev/null</>. The <prgn/userv/ client/daemon pair will arrange that data is copied between the files or file descriptors specified to to the client by the caller and these these pipes. <p> Pipes which may be written to will be closed if a write error occurs on the corresponding client-side file or descriptor, which may result in a <prgn/SIGPIPE/ in the service program; pipes open for reading will get <prgn/EOF/ if the client-side file descriptor gets <prgn/EOF/ or an error. <p> If the service closes one of its reading file descriptors the writing end of the corresponding pipe will generate a <prgn/SIGPIPE/ when attempts are made by the client/daemon pair to write to it. This will not be considered an error; rather, the relevant pipe will be discarded and the corresponding file or file descriptor held by the client will be closed. <p> Likewise, if one of the file descriptors held by the client for writing by the service is a pipe whose other end is closed by the caller then the client/daemon pair will see an error when trying to copy data provided by the service. This too will not be considered an error; rather, the pipe correspondong to that descriptor will be closed and any further writes will cause the service to get a <prgn/SIGPIPE/. <p> Note that not all write errors or broken pipes on file descriptors may be visible to the service, since buffered data may be discarded by the operating system and there will be a finite interval between the error happening and the service being disconnected from the client or the next write causing a <prgn/SIGPIPE/. <p> Read errors on file descriptors (and disconnection) will only be visible to the service and distinguishable from normal end of file if <prgn/disconnect-hup/ is in effect. <p> Read and write errors (other than broken pipes, as described above) will always be visible to the caller; they are system errors, and will therefore cause the client to print an error message to stderr and return with an exit status of 255. <p> If the main service program process exits while it still has running children any file descriptors held by those children can remain open, depending on the use of <tt/wait/, <tt/nowait/ or <tt/close/ for the relevant file descriptor in the client's arguments. By default writing filedescriptors remain open and the client will wait for them to be closed at the service end, and reading file descriptors are closed immediately. These leftover child processes will not get a any <prgn/SIGHUP/ even if a read or write error occurs or the client disconnects before then. <sect>Environment <p> The service will have some information in environment variables: <taglist compact> <tag/<tt/USERV_USER// <item> The login name of the calling user. If the <prgn/LOGNAME/ variable is set (or, if that is unset, if the <prgn/USER/ variable is set) in the environment passed to the client by the caller then the password entry for that login name will be looked up; if that password entry's uid is the same as that of the calling process then that login name will be used, otherwise (or if neither <prgn/LOGNAME/ nor <prgn/USER/ is set) the calling process's uid will be looked up to determine their login name (and if this lookup fails then the service will not be invoked). <tag/<tt/USERV_UID// <item> The uid of the calling process. <tag/<tt/USERV_GID// <item> The gid and supplementary group list of the calling process: first the group in gid and then those in the supplementary group list, in decimal, separated by spaces. <tag/<tt/USERV_GROUP// <item> The group names of the calling process, listed in the same way as the ids are in <prgn/USERV_GID/. If no name can be found for any of the calling process's group(s) then the service will not be invoked. <tag/<tt/USERV_CWD// <item> The client's current working directory name (this directory may not be accessible to the service). If it could not be determined or the <prgn/--hidecwd/ flag was used then this variable will be set to an empty string (this is not considered an error). <tag/<tt/USERV_SERVICE// <item> The service name requested by the caller. <tag/<tt/USERV_U_<var/name/// <item> The value supplied to the client by the caller using -D<var/name/. </taglist> <prgn/HOME/, <prgn/PATH/, <prgn/SHELL/, <prgn/LOGNAME/ and <prgn/USER/ will be set appropriately (according to the details of the service user). <chapt id="config">Service-side configuration <p> Which services may be run by whom and under what conditions is controlled by configuration files. <p> The daemon will read these files in order. Certain directives in the files modify the daemon's execution settings for invoking the service, for example allowing certain file descriptors to be specified by the client or specifying which program to execute to provide the service. <p> The <em/last/ instance of each such setting will take effect. The directives which specify which program to execute will not stop the configuration file from being read; they will be remembered and will only take effect if they are not overridden by a later directive. <p> The daemon will first read <tt>/etc/userv/system.default</>. Then, by default (this behaviour may be modified), it will read a per-user file <tt>~/.userv/rc</>, if it exists and the service user's shell is in <tt>/etc/shells</>. Finally it will read <tt>/etc/userv/system.override</>. <p> When it has read all of these files it will act according to the currently values of of the execution settings. <sect>Configuration file syntax <p> The configuration file is a series of directives, usually one per line. The portion of a line following a hash character <tt/#/ is taken as a comment and ignored. Each directive consists of a series of tokens separated by linear whitespace (spaces and tabs); tokens may be words consisting of non-space characters, or, where a string is required, a string in double quotes. Double-quoted strings may contain the following backslash escapes: <taglist compact> <tag/<tt/\n//<item>newline <tag/<tt/\t//<item>tab <tag/<tt/\r//<item>carriage return <tag/<tt/\<var/OOO///<item>character whose octal code is <var/OOO/ <tag/<tt/\x<var/XX///<item>character whose hex code is <var/XX/ <tag/<tt/\<var/punctuation///<item>literal punctuation character (eg <tt/\\/, <tt/\"/) <tag/<tt/\<var/newline// (ie, backslash at end of line)/ <item>string continues on next line </taglist> <p> Relative pathnames in directives are relative to the service program's current directory (usually the service user's home directory). Pathnames starting with the two characters <tt>~/</> are taken to be relative to the service user's home directory. <sect id="directives">Configuration file directives <p> <sect1 id="dirs-immediate">Immediate directives <p> The following directives take effect immediately: <taglist> <tag/<tt/cd <var/pathname/// <item> Change directory in the service program. <prgn/cd/ is cumulative. It is an error if the directory cannot be changed to. <p> <prgn/cd/ should not be used between <prgn/execute-from-directory/ and the invocation of the service program, as the test for the availability of the service program would be done with the old current directory and the actual execution with the new (probably causing an error). <tag/<tt/eof// <item> Stop reading the configuration file in question, as if end of file had been reached. Any control constructs (<prgn/if/, <prgn/catch-quit/ or <prgn/errors-push/) which were started in that file will be considered finished. Parsing will continue in the file which caused the file containing the <prgn/eof/ to be read. <tag/<tt/quit// <item> Stop reading configuration files and act immediately on the current settings. The behaviour of <prgn/quit/ is subject to the <prgn/catch-quit/ control construct. <tag/<tt/include <var/filename/// <tag/<tt/include-ifexist <var/filename/// <item> Read the configuration file <var/filename/, and then return to this file and continue parsing it with the next directive. It is an error if the file cannot be opened and read, unless <prgn/include-ifexist/ is used and the file does not exist, in which case the directive is silently ignored. <tag/<tt/include-lookup <var/parameter/ <var/directory/// <tag/<tt/include-lookup-all <var/parameter/ <var/directory/// <item> Read the configuration file in <var/directory/ whose name is the value of <var/parameter/ (see the description of <prgn/if/, <ref id="dirs-control">). If <var/parameter/ has several values they will be tried in order; with <prgn/include-lookup/ this search will stop when one is found, but with <prgn/include-lookup-all/ the search will continue and any files appropriate to other values will be read too. <p> If none of the parameter's values had a corresponding file then the file <tt/:default/ will be read, if it exists. If <var/parameter/'s list of values was empty then the file <tt/:none/ will be tried first and read if it exists, otherwise <tt/:default/ will be tried. <p> It is not an error for any of the files (including <tt/:default/) not to exist, but it is an error if a file exists and cannot be read or if the directory cannot be accessed. <p> A translation will be applied to values before they are used to construct a filename, so that the lookup cannot access dotfiles or files in other directories: values starting with full stops will have a colon prepended (making <tt/:./), colons will be doubled, and each slash will be replaced with a colon followed by a hyphen <tt>:-</>. A parameter value which is the empty string will be replaced with <tt/:empty/ (note that this is different from a parameter not having any values). <p> (In older versions of userv, a different translation was applied: See <tt>https://bugs.debian.org/837391</tt>. The old translation can be requested (for subsequent directives) with <tt/include-lookup-quote-old/, which is undone by <tt/include-lookup-quote-new/ and <tt/reset/.) <tag/<tt/include-directory <var/directory/// <item> Read configuration from all files in directory <var/directory/ which are plain files whose names consist only of alphanumerics and hyphens and start with an alphanumeric. They will be read in lexical order. It is an error for the directory not to exist or for it or any of the files found not to be read successfully, or for anything with an appropriate name not to be a plain file or a symbolic link to a plain file. <tag/<tt/error <var/text .../// <item> Causes an error whose message includes the descriptive string <var/text/. <var/text/ may consist of several tokens with intervening whitespace. The whitespace will be included in the message as found in the configuration file: all the characters until the end of the line will be included verbatim, unless they are part of a double-quoted string, in which case the usual meaning of the string (i.e., after backslash escape processing) will be used. Comments and linear whitespace at the end of the line (or just before the comment) will still be ignored. <tag/<tt/message <var/text .../// <item> Causes a message including the descriptive string <var/text/ to be delivered as if it were an error message, but does not actually cause an error. </taglist> <sect1 id="dirs-delayed">Directives with delayed effect <p> The following directives have no immediate effect, but are remembered and have an effect on later processing of the configuration files. <taglist> <tag/<tt/user-rcfile <var/filename/// <item> Specifies that the file <var/filename/ should be read instead of the user's <tt>~/.userv/rc</>. This does <em/not/ happen immediately; instead, the setting is remembered and used after the <prgn/system.default/ configuration file has been read. This directive has no effect in a user's configuration file or in the <prgn/system.override/ file, as the user's configuration file has already been found and read by then and will not be re-read. <tag/<tt/errors-to-stderr// <item> Causes error messages to be delivered to the client's stderr. <tag/<tt/errors-to-file/ <var/filename// <item> Error messages will be written to <var/filename/, which will be opened in the context of and with the privileges of the service user. <tag/<tt/errors-to-syslog/ [<var/facility/ [<var/level/]]/ <item> Error messages will be delivered using <prgn/syslog/. The default <var/facility/ is <tt/user/; the default <var/level/ is <tt/error/. </taglist> <sect1 id="dirs-control">Control structure directives <p> The following directives are used to create control structures. If the end of the file is encountered before the end of any control structure which was started inside it then that control structure is considered finished. This is not an error. <taglist> <tag/<tt/if <var/condition/// <tag/<tt/elif <var/condition/// <tag/<tt/else// <tag/<tt/fi// <item> Lines following <prgn/if/ are interpreted only if the condition is true. Many conditions are properties of parameter values. Most parameters have a single string as a value; however, some may yield zero or several strings, in which case the condition is true if it is true of any of the strings individually. Parameters are described below. <p> The conditions are: <taglist compact> <tag/<tt/glob <var/parameter/ <var/glob-pattern/ ...// <item> The value of the parameter whose name is given matches one of the glob patterns (anchored at both ends; backslashes can be used to escape metacharacters). <tag/<tt/range <var/parameter/ <var/min/ <var/max/// <item> The value of the parameter is a nonnegative integer and lies within the range specified. <var/min/ or <var/max/ may be <tt/$/ to indicate no lower or upper limit, respectively. <tag/<tt/grep <var/parameter/ <var/filename/// <item> The <var/filename/ refers to a file one of whose lines is the value of the parameter (leading or trailing whitespace on each line and empty lines in the file are ignored). It is an error for the file not to be opened and read. <tag/<tt/! <var/condition/// <item> The <var/condition/ is <em/not/ true. <tag/Conjunctions: <tt/&/ and <tt/|// <item> <example> ( <var/condition/ & <var/condition/ & <var/condition/ ... ) </example> is true if all the listed conditions are true; where <tt/|/ is used it is true if any of them is true. Newlines must be used to separate one condition from the next, as shown, and the parentheses are mandatory. These conjunctions do not do lazy evaluation. </taglist> <p> The parameters are: <taglist compact> <tag/<tt/service// <item> The service name specified when the client was called. <tag/<tt/calling-user// <item> Two strings: the login name of the calling user (determined as for <prgn/USERV_USER/, above) and the calling uid (represented in decimal). <tag/<tt/calling-group// <item> Several strings: the primary and supplementary group names and gids (in decimal) of the calling process. All the group names come first, and then the gids. If the first supplementary group is the same as the primary group then it is elided. <tag/<tt/calling-user-shell// <item> The calling user's shell, as listed in the password entry for the calling login name (as determined for <prgn/USERV_USER/, above). <tag/<tt/service-user// <item> Two strings: the name of the service user (as specified to the client) and their uid (represented in decimal). <tag/<tt/service-group// <item> Several strings: the primary and supplementary group names and gids (in decimal) of the service user. <tag/<tt/service-user-shell// <item> The service user's shell, as listed in their password entry. <tag/<tt/u-<var/name/// <item> The value of the user-defined variable <var/name/ passed by the caller using the <prgn/--defvar/ command-line option to the client. If the variable was not defined then this parameter is an empty list of strings; in this case any condition which tests it will be false, and <tt/include-lookup/ on it will read the <tt/:none/ file, or <tt/:default/ if <tt/:none/ is not found. </taglist> <tag/<tt/errors-push// <tag/<tt/srorre// <item> Stacks the error handling behaviour currently in effect. Any changes to error handling will take effect only between <prgn/errors-push/ and <prgn/srorre/. <tag/<tt/catch-quit// <tag/<tt/hctac// <item> Any use of <prgn/quit/ inside <prgn/catch-quit/ will merely cause the parsing to continue at <prgn/hctac/ instead. Any control constructs started since the <prgn/catch-quit/ will be considered finished if a <prgn/quit/ is found. <p> If an error occurs inside <prgn/catch-quit/ the execution settings will be reset (as if by the <prgn/reset/ directive) and parsing will likewise continue at <prgn/hctac/. <p> If a lexical or syntax error is detected in the same configuration file as the <prgn/catch-quit/, while looking for the <prgn/hctac/ after an error or <prgn/quit/, that new error will not be caught. </taglist> <sect1 id="dirs-execution">Directives for changing execution settings <p> The following directives modify the execution settings; the server will remember the fact that the directive was encountered and act on it only after all the configuration has been parsed. The <em/last/ directive which modifies any particuar setting will take effect. <taglist> <tag/<tt/reject// <item> Reject the request. <prgn/execute/, <prgn/execute-from-directory/ and <prgn/execute-from-path/ will change this setting. <tag/<tt/execute <var/program/ [<var/argument/ ...]// <item> Execute the program <var/program/, with the arguments as specified, followed by any arguments given to the client if <prgn/no-suppress-args/ is in effect. It is an error for the execution to fail when it is attempted (after all the configuration has been parsed). If <var/program/ does not contain a slash it will be searched for on the service user's path. <tag/<tt/execute-from-directory <var/pathname/ [<var/argument/ ...]// <item> Take all the characters after the last slash of the service name specified when the client was called, and execute that program in the directory named by <var/pathname/ as if it had been specified for <var/execute/. The part of the service name used may contain only alphanumerics and hyphens and must start with an alphanumeric (and it must be non-empty), otherwise it is an error. <p> This directive is ignored if the relevant program does not exist in the directory specified; in this case the program to execute is left at its previous setting (or unset, if it was not set before). <p> It is an error for the test for the existence of the program to fail other than with a `no such file or directory' indication. It is also an error for the execution to fail if and when it is attempted (after all the configuration has been parsed). <tag/<tt/execute-from-path// <item> <var/service/ is interpreted as a program on the default <prgn/PATH/ (or as a pathname of an executable, if it contains a <tt>/</>). This directive is <em/very dangerous/, and is only provided to make the <prgn/--override/ options effective. It should not normally be used. It is an error for the execution to fail when it is attempted (after all the configuration has been parsed). <tag/<tt/execute-builtin <var/service-name/ <var/service-arguments// <item> Executes the builtin service <var/service-name/. These builtin services display information about the server and/or the request, and ignore any arguments passed from the service side except possibly to print them as part of their output. They write their results to their standard output (i.e., wherever file descriptor 1 is directed). The builtin services are: <taglist compact> <tag/<tt/execute// <item> Displays the execution settings, defined variables, arguments, etc. with which the builtin service was invoked. <tag/<tt/environment// <item> Displays the environment variable settings with which the builtin service was invoked. <tag/<tt/parameter <var/parameter/// <item> Displays the values of the service configuration language parameter specified. <tag/<tt/version// <item> Displays the version string and compilation details of the uservd server program. <tag/<tt/reset// <item> Displays the default reset configuration (evaluated when <prgn/reset/ is found in a configuration file, or when an error is caught by <prgn/catch-quit/). <tag/<tt/toplevel// <item> Displays the top-level default configuration (the configuration data, evaluated by the server, which calls all the other configuration files). <tag/<tt/override// <item> Displays the top-level override configuration (the configuration data, evaluated by the server, which causes all the other configuration data to be parsed). <tag/<tt/help// <item> Displays a list of the understood builtin service names and arguments. </taglist> In the future other builtin services may be defined which do more than just print information. <tag/<tt/set-environment// <tag/<tt/no-set-environment// <item> Runs <tt>/etc/environment</> to set the service user's environment. This adds the overhead of invoking a shell, but doesn't cause any shell (de)mangling of the service's arguments. This is achieved by invoking <example> .../program arg arg arg ... </example> as <example> /bin/sh -c '. /etc/environment; exec "$@"' - .../program arg arg arg ... </example> <prgn/no-set-environment/ cancels the effect of <prgn/set-environment/. <tag/<tt/no-suppress-args// <tag/<tt/suppress-args// <item> Include any arguments given to the client as arguments to the program invoked as a result of an <prgn/execute/, <prgn/execute-from-directory/ or <prgn/execute-from-path/ directive. <prgn/suppress-args/ undoes the effect of <prgn/no-suppress-args/. <tag/<tt/require-fd <var/fd-range/ read|write// <item> Insist that the filedescriptor(s) be opened for reading resp. writing. It is an error if any descriptor marked as required when the service is about to be invoked (after the configuration has been parsed) was not specified when the client was invoked. Each file descriptor has a separate setting, and the last one of <prgn/require-fd/, <prgn/allow-fd/, <prgn/ignore-fd/, <prgn/null-fd/ or <prgn/reject-fd/ which affected a particular file descriptor will take effect. <p> <var/fd-range/ may be a single number, two numbers separated by a hyphen, or one number followed by a hyphen (indicating all descriptors from that number onwards). It may also be one of the words <tt/stdin/, <tt/stdout/ or <tt/stderr/. Open-ended file descriptor rangers are allowed only with <prgn/reject-fd/ and <prgn/ignore-fd/, as otherwise the service program would find itself with a very large number of file descriptors open. <p> When the configuration has been parsed, and before the service is about to be executed, stderr (fd 2) must be required or allowed (<prgn/require-fd/ or <prgn/allow-fd/) for writing; this is so that the error message printed by the server's child process if it cannot <prgn/exec/ the service program is not lost. <tag/<tt/allow-fd <var/fd-range/ [read|write]// <item> Allow the descriptor(s) to be opened for reading resp. writing, or either if neither <tt/read/ nor <tt/write/ is specified. If a particular descriptor not specified by the client then it will be open onto <tt>/dev/null</> (for reading, writing, or both, depending on whether <tt/read/, <tt/write/ or neither was specified). <tag/<tt/null-fd <var/fd-range/ [read|write]// <item> Specify that the descriptor(s) be opened onto <prgn>/dev/null</> for reading resp. writing, or both if neither <tt/read/ nor <tt/write/ is specified. Any specification of these file descriptors by the client will be silently ignored; the client will see its ends of the descriptors being closed immediately. <tag/<tt/reject-fd <var/fd-range/// <item> Do not allow the descriptor(s) to be specified by the client. It is an error if any descriptor(s) marked for rejection are specified when the service is about to be invoked (after the configuration has been parsed). <tag/<tt/ignore-fd <var/fd-range/// <item> Silently ignore any specification by the client of those descriptor(s). The pipes corresponding to these descriptors will be closed just before the service is invoked. <tag/<tt/disconnect-hup// <tag/<tt/no-disconnect-hup// <item> Causes the service's process group to get a <prgn/SIGHUP/ if the client disconnects before the main service process terminates. <prgn/no-disconnect-hup/ cancels <prgn/disconnect-hup/. <p> If one of the reading descriptors specified when the client is called gets a read error, or if the service is disconnected for some other reason, then the <prgn/SIGHUP/ will be delivered <em/before/ the writing end(s) of the service's reading pipe(s) are closed, so that the client can distinguish disconnection from reading EOF on a pipe. <tag/<tt/reset// <item> Resets the execution settings to the default. This is equivalent to: <example> cd ~/ reject no-set-environment suppress-args allow-fd 0 read allow-fd 1-2 write reject-fd 3- disconnect-hup </example> </taglist> If no <prgn/execute/, <prgn/execute-from-path/, <prgn/execute-from-directory/ or <prgn/builtin/ is interpreted before all the files are read then the request is rejected. <sect id="configerrors">Errors in the configuration file <p> If a syntax error or other problem occurs when processing a configuration file then a diagnostic will be issued, to wherever the error messages are currently being sent (see the <prgn/errors-/ family of directives, above). <p> The error will cause processing of the configuration files to cease at that point, unless the error was inside a <prgn/catch-quit/ construct. In this case the settings controlling the program's execution will be reset to the defaults as if a <prgn/reset/ directive had been issued, and parsing continues after <prgn/hctac/. <sect id="defaults">Defaults <p> The default configuration processing is as if the daemon were parsing an overall configuration file whose contents were as follows: <example> reset user-rcfile ~/.userv/rc errors-to-stderr include /etc/userv/system.default if grep service-user-shell /etc/shells errors-push catch-quit include-ifexist <var/file specified by most recent user-rcfile directive/ hctac srorre fi include /etc/userv/system.override quit </example> <p> If one of the <prgn/--override/ options to the client is used then it will instead be as if the daemon were parsing an overall configuration as follows: <example> reset errors-to-stderr include <var/file containing configuration data sent by client/ quit </example> <chapt id="ipass">Information passed through the client/daemon combination <p> The information described below is the only information which passes between the caller and the service. <list> <item> The service name supplied by the caller is available in the configuration language for deciding whether and which service program to invoke, in the <prgn/service/ parameter, and is used by the <prgn/execute-from-directory/ and <prgn/execute-from-path/ configuration directives. It is usually used to select which service program to invoke. It is also passed to the service program in the <prgn/USERV_SERVICE/ environment variable. <item> File descriptors specified by the client and allowed according to the configuration language will be connected. Each file descriptor is opened for reading or writing. Communication is via pipes, one end of each pipe being open on the appropriate file descriptor in the service program (when it is invoked) and the other end being held by the client process, which will read and write files it opens on behalf of its caller or file descriptors it is passed by its caller. <p> Data may be passed into the service through reading pipes and out of it through writing pipes. These pipes can remain open only until the service and client have terminated, or can be made to stay open after the client has terminated and (if the service program forks) the main service process has exited; the behaviour is controlled by options passed to the client by its caller. <p> The caller can arrange that a writing pipe be connected to a pipe or similar object and cause attempts to write to that descriptor by the service to generate a <prgn/SIGPIPE/ (or <prgn/EPIPE/ if <prgn/SIGPIPE/ is caught or ignored) in the service. <p> Likewise, the service can close filedescriptors specified for reading, which will cause the corresponding filedescriptors passed by the caller to be closed, so that if these are pipes processes which write to them will receive <prgn/SIGPIPE/ or <prgn/EPIPE/. <item> If <prgn/no-suppress-args/ is set then arguments passed to the client by its caller will be passed on, verbatim, to the service. <item> Fatal signals and system call failures experienced by the client will result in the disconnection of the service from the client and possibly some of the communication file descriptors described above; if <prgn/disconnect-hup/ is set then the service will also be sent a <prgn/SIGHUP/. <item> The value of the <prgn/LOGNAME/ (or <prgn/USER/) environment variable as passed to the client will be used as the login name of the calling user if the uid of the calling process matches the uid corresponding to that login name. Otherwise the calling uid's password entry will be used to determine the calling user's login name. <p> This login name and the calling uid are available in the configuration language in the <prgn/calling-user/ parameter and are passed to the service program in environment variables <prgn/USERV_USER/ and <prgn/USERV_UID/. <p> The shell corresponding to that login name (according to the password entry) is available as in the configuration language's <prgn/calling-user-shell/ parameter. <p> If no relevant password entry can be found then no service will be invoked. <item> The numeric values and textual names for calling gid and supplementary group list are available in the configuration language in the <prgn/calling-group/ parameter and are passed to the service in environment variables. <p> If no name can be found for a numeric group to which the calling process belongs then no service will be invoked. <item> The name of the current working directory in which the client was invoked is passed, if available and not hidden using <prgn/--hidecwd/, to the service program in the <prgn/USERV_CWD/ variable. This grants no special access to that directory unless it is a subdirectory of a directory which is executable (searchable) but not readable by the service user. <item> Settings specified by the caller using the <tt/--defvar <var/name/=<var/value// option to the client are available in the configuration language as the corresponding <tt/u-<var/name// parameters and are passed to the service program in environment variables <tt/USERV_U_<var/name//. <item> If the calling user is root or the same as the service user then options may be given to the client which bypass the usual security features; in this case other information may pass between the caller and the service. </list> <chapt id="notes">Applications and notes on use <p> <sect id="examples">Examples <p> The companion package, <prgn/userv-utils/, contains a selection of example services, some of which are useful tools in their own right. See the <prgn/README/ in its top-level directory for details. <sect id="standards">Standard services and directory management <p> In later versions of this specification standard service names and interfaces for common services such as mail delivery and WWW CGI scripts may be specified. <p> <prgn/userv/-using applications and system services which hide <prgn/userv/ behind wrapper scripts may need to store information in the user's filespace to preserve the correct placement of the security perimiters. Such applications should usually do so in a directory (created by them) <tt>~/.userv/<var/service/</>, where <var/service/ is the service name or application in question. <p> If desired, a dot-directory inside <tt>~/.userv</> may be used to avoid the user becoming confused by finding parts of a semi-privileged application's internal state in their filespace, and/or discourage them from fiddling with and thus corrupting it. <p> However, <prgn/userv/ applications should of course not rely for their global integrity and security on the integrity of the data on the user's side of the security boundary. <sect id="reducepriv">Reducing the number of absolutely privileged subsystems <p> Currently most Unix systems have many components which need to run as root, even though most of their activity does not strictly require it. This gives rise to a large and complex body of code which must be trusted with the security of the system. <p> If they were to use <prgn/userv/, many of these subsystems would no longer need any unusual privilege. <p> <prgn/cron/ and <prgn/at/, <prgn/lpr/ and the system's mail transfer agent (<prgn/sendmail/, <prgn/smail/, <prgn/exim/ or the like) all fall into this category, though <prgn/userv/-based versions of these programs are not currently available. <sect id="noexcess">Do not give away excessive privilege to <prgn/userv/-using facilities <p> There is a danger that people reimplementing the facilities I mention above using <prgn/userv/ will discard much of the security benefit by using a naive implementation technique. This will become clearer with an example: <p> Consider the <prgn/lpr/ program. In current systems this needs to have an absolutely privileged component in order to support delayed printing without copying: when the user queues a file to be printed the filename is stored in the print queue, rather than a copy of it, and the printer daemon accesses the file directly when it is ready to print the job. In order that the user can print files which are not world-readable the daemon is given root privilege so that it can open the file in the context of the user, rather than its own. <p> A simple-minded approach to converting this scheme to use <prgn/userv/ might involve giving the printer daemon (the <prgn/lp/ user) the ability to read the file by allowing them to run <prgn/cat/ (or a special-purpose file-reading program) as any user. The <prgn/lpr/ program would use a <prgn/userv/ service to store the filename in the printer daemon's queues, and the daemon would read the file later when it felt like it. <p> However, this would allow the printer daemon to read any file on the system, whether or not someone had asked for it to be printed. Since many files will contain passwords and other security-critical information this is nearly as bad as giving the daemon root access in the first place. Any security holes in the print server which allow a user to execute commands as the <prgn/lp/ user will give the user the ability to read any file on the system. <p> Instead, it is necessary to keep a record of which files the daemon has been asked to print <em/outside/ the control of the print daemon. This record could be kept by a new root-privileged component, but this is not necessary: the record of which files a user has asked to be printed can be kept under the control of the user in question. The submission program <prgn/lpr/ will make a record in an area under the user's control before communicating with the print server, and the print server would be given the ability to run a special file-reading program which would only allow files to be read which were listed in the user's file of things they'd asked to print. <p> Now security holes in most of the printing system do not critically affect the security of the entire system: they only allow the attacker to read and interfere with print jobs. Bugs in the programs run by the print server to read users' files (and to remove entries from the list of files when it has done with them) will still be serious, but this program can be quite simple. <p> Similar considerations apply to many <prgn/userv/-based versions of facilities which currently run as root. <p> It is debatable whether the user-controlled state should be kept in the user's filespace (in dotfiles, say) or kept in a separate area set aside for the purpose; however, using the user's home directory (and possibly creating a separate subdirectory of it as a dotfile to contain subsystem state) has fewer implications for the rest of the system and makes it entirely clear where the security boundaries lie. <sect id="notreally"><prgn/userv/ can often replace <prgn/sudo/, but not <prgn/really/ <p> <prgn/userv/ is not intended as a general-purpose system administration tool with which system administrators can execute arbitrary programs like text editors as root (or other system users) when they need to. It is unsuitable for this purpose precisely because it enforces a strong separation between the calling and the called program, which is undesirable in this context. <p> However, its use when restricted to running particular programs in particular ways is very similar to many common uses of <prgn/sudo/<footnote><prgn/sudo/ is a program which allows users to execute certain programs as root, according to configuration files specified by the system administrator.</footnote>. <prgn/userv/ is generally much better than restricted <prgn/sudo/, because it protects the called program much more strongly from bad environmental conditions set up by the caller. Most programs that one might want to run via restricted <prgn/sudo/, have not been designed to run in a partially hostile environment. <prgn/userv/ allows these programs to be run in a safer environment and should be used instead. <sect id="stdinerr">Error handling and input streams (eg stdin) <p> When the service program is reading from a file descriptor connected to the calling side, the fd that the service program refers to a pipe set up by <prgn/userv/ and not to the same object as was presented by the caller. <p> Therefore if there is some kind of error it is possible for the service-side fd to give premature end of file. If it is important to tell whether all of the intended data has been received by the service program, the datastream must contain an explicit end-of-file indication of some kind. <p> For example, consider a <prgn/userv/ service for submitting a mail message, where message is supplied on the service's stdin. However, if the calling process is interrupted before it has written all of the message, the service program will get EOF on the message data. In a naive arrangement this would cause a half-complete message to be sent. To prevent this, it is necessary to adopt some kind of explicit end indication; for example, the end of the message could be signalled by a dot on a line by itself, and dots doubled, as in SMTP. Then the service program would know when the entire message had been received, and could avoid queueing incomplete messages. <sect id="nogeneral">Don't give access to general-purpose utilities <p> Do not specify general purpose programs like <prgn/mv/ or <prgn/cat/ in <prgn/execute-/ directives without careful thought about their arguments, and certainly not if <prgn/no-suppress-args/ is specified. If you do so it will give the caller much more privilige than you probably intend. <p> It is a shame that I have to say this here, but inexperienced administrators have made similar mistakes with programs like <prgn/sudo/. </book> �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������work/system.default���������������������������������������������������������������������������������0000664�0000000�0000000�00000003200�14163725562�011630� 0����������������������������������������������������������������������������������������������������ustar ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# Generally, if you want all your users to provide a service for your # benefit but want them to be able to override your default setting, # you should put it in this file but not use quit. Eg: # if ( grep service-user-shell /etc/shells # & glob service mail-delivery # & glob calling-user mail # ) # reset # no-suppress-args # execute /usr/local/bin/procmail-wrapper # fi # (procmail-wrapper could extract envelope information from the # arguments and/or -D options and pass them to procmail.) include-directory /etc/userv/default.d include-lookup service /etc/userv/services.d # If you want to force users to provide a particular service, # then you can put it here and use `quit'. Eg: # if ( grep service-user-shell /etc/shells # & glob service cleanup-tmp # ) # reset # errors-to-syslog local4 # execute /usr/local/bin/cleanup-tmp # no-set-environment # no-disconnect-hup # null-fd 0 read # null-fd 1-2 write # quit # fi # Alternatively, you could put the same thing in system.override, with # or without the quit. In this case it's usually important to use # reset, and also to note that now users can cause error messages # which they could not do before (though due to the implied catch-quit # around the user's rc file they wouldn't stop the service being # executed). # # If you want to force all your users' services to have a particular # property you should do it in system.override. Eg, there put # set-environment # to force them to run /etc/environment to have ulimits set up, even # if they try not to. # # NB that doing this _won't_ affect things in system.default and # earlier in system.override that use `quit'. ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������work/system.override��������������������������������������������������������������������������������0000664�0000000�0000000�00000000547�14163725562�012036� 0����������������������������������������������������������������������������������������������������ustar ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# This is for subtle overriding things. Most things should go in # system.default (or default.d or services.d), so that the user can # override them if they want and so that if you want to force the user # to provide a service you don't needlessly parse their configuration # file and get the error messages from it. include-directory /etc/userv/override.d ���������������������������������������������������������������������������������������������������������������������������������������������������������work/tests/�����������������������������������������������������������������������������������������0000775�0000000�0000000�00000000000�14163725562�010105� 5����������������������������������������������������������������������������������������������������ustar ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������work/tests/lib��������������������������������������������������������������������������������������0000664�0000000�0000000�00000001751�14163725562�010602� 0����������������������������������������������������������������������������������������������������ustar ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# -*- shell-script -*- prep_tmp () { tmp="${AUTOPKGTEST_ARTIFACTS}" if [ "x$tmp" = x ]; then rm -rf tmp mkdir tmp tmp=tmp fi } expect_output () { local e_status=$1; shift local e_stdout=$1; shift set +e local g_stdout g_stdout="$( "$@" )" local g_status=$? set -e test "$g_status" = "$e_status" test "$g_stdout" = "$e_stdout" } prep_cuser () { cuser=${1-bin} cuser_uid=$(id -u $cuser) cuser_gid=$(id -g $cuser) } prep_config_t_env () { local suser="$1" local cfgdir="$2" mkdir -p "$cfgdir"/services.d cat >$cfgdir/services.d/userv-t-env <<END if ( glob calling-user $cuser & glob service-user $suser ) execute printenv fi END } check_expected_env () { local got_env="$1" for expect in \ "USERV_SERVICE=userv-t-env" \ "USERV_USER=$cuser" \ "USERV_GROUP=$cuser $cuser" \ "USERV_UID=$cuser_uid" \ "USERV_GID=$cuser_gid $cuser_gid" \ ; do egrep "^$expect\$" $got_env done } �����������������������work/tests/t-basic����������������������������������������������������������������������������������0000775�0000000�0000000�00000000164�14163725562�011356� 0����������������������������������������������������������������������������������������������������ustar ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!/bin/bash set -ex . tests/lib expect_output 0 'games' \ userv --override 'execute whoami' games spong echo ok. ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������work/tests/t-config���������������������������������������������������������������������������������0000775�0000000�0000000�00000000560�14163725562�011542� 0����������������������������������������������������������������������������������������������������ustar ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!/bin/bash set -ex . tests/lib prep_tmp prep_cuser prep_config_t_env games /etc/userv : '---------- test service invocation ----------' really -u $cuser \ userv games userv-t-env >"$tmp"/env check_expected_env "$tmp"/env : '---------- test rejection (wrong calling user) ----------' expect_output 255 '' \ really -u daemon \ userv games userv-t-env echo ok. ������������������������������������������������������������������������������������������������������������������������������������������������work/tests/t-persist��������������������������������������������������������������������������������0000775�0000000�0000000�00000000566�14163725562�011774� 0����������������������������������������������������������������������������������������������������ustar ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!/bin/bash set -ex . tests/lib coproc userv --override 'execute cat -vet' games spong stdout=${COPROC[0]} stdin=${COPROC[1]} print_expect_reply () { local m=$1 local got echo >&$stdin "$m" read <&$stdout got local exp="$(printf '%s$\n' "$m")" test "$got" = "$exp" } print_expect_reply hi service userv restart print_expect_reply ho echo ok. ������������������������������������������������������������������������������������������������������������������������������������������work/tests/t-userconfig�����������������������������������������������������������������������������0000775�0000000�0000000�00000000714�14163725562�012442� 0����������������������������������������������������������������������������������������������������ustar ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!/bin/bash set -ex . tests/lib prep_tmp prep_cuser mkdir ~root/.userv cat >~root/.userv/rc <<END include-lookup service .userv/services.d END prep_config_t_env root ~root/.userv : '---------- test service invocation ----------' really -u $cuser \ userv root userv-t-env >"$tmp"/env check_expected_env "$tmp"/env : '---------- test rejection (wrong calling user) ----------' expect_output 255 '' \ really -u daemon \ userv root userv-t-env echo ok. ����������������������������������������������������work/tokens.h���������������������������������������������������������������������������������������0000664�0000000�0000000�00000042105�14163725562�010421� 0����������������������������������������������������������������������������������������������������ustar ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * userv is copyright Ian Jackson and other contributors. * See README for full authorship information. * * 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; if not, see <http://www.gnu.org/licenses/>. */ #ifndef TOKENS_H #define TOKENS_H enum tokens { tokm_instance= 0x000000ff, tokm_repres= 0x00000f00, tokm_type= 0xfffff000, tokr_nonstring= 0x00000100, tokr_word= 0x00000200, tokr_punct= 0x00000300, tokr_string= 0x00000400, tokt_directive= 0x00001000, tokt_controlstart= 0x00002000, tokt_controlend= 0x00004000, tokt_exception= 0x00008000, tokt_parmcondition= 0x00010000, tokt_condop= 0x00020000, tokt_parameter= 0x00040000, tokt_number= 0x00080000, tokt_fdrange= 0x00100000, tokt_logfacility= 0x00200000, tokt_loglevel= 0x00400000, tokt_readwrite= 0x00800000, tokt_string= 0x01000000, tokt_execmode= 0x02000000, tokt_ehandlemode= 0x04000000, tokt_lookupquotemode= 0x08000000, tokt_builtinservice= 0x10000000, tokt_misc= 0x20000000, tokt_internal= 0x40000000, toki_word_reject= 0x00000001, toki_word_executefromdirectory= 0x00000002, toki_word_executefrompath= 0x00000003, toki_word_executebuiltin= 0x00000004, toki_word_errorstostderr= 0x00000005, toki_word_errorstosyslog= 0x00000006, toki_word_errorstofile= 0x00000007, toki_word_includelookupquoteold= 0x00000008, toki_word_includelookupquotenew= 0x00000009, toki_word_requirefd= 0x0000000a, toki_word_allowfd= 0x0000000b, toki_word_nullfd= 0x0000000c, toki_word_rejectfd= 0x0000000d, toki_word_ignorefd= 0x0000000e, toki_word_setenvironment= 0x0000000f, toki_word_nosetenvironment= 0x00000010, toki_word_suppressargs= 0x00000011, toki_word_nosuppressargs= 0x00000012, toki_word_disconnecthup= 0x00000013, toki_word_nodisconnecthup= 0x00000014, toki_word_cd= 0x00000015, toki_word_userrcfile= 0x00000016, toki_word_include= 0x00000017, toki_word_includeifexist= 0x00000018, toki_word_includelookup= 0x00000019, toki_word_includelookupall= 0x0000001a, toki_word_includedirectory= 0x0000001b, toki_word_message= 0x0000001c, toki_word_includesysconfig= 0x0000001d, toki_word_includeuserrcfile= 0x0000001e, toki_word_includeclientconfig= 0x0000001f, toki_word_quit= 0x00000020, toki_word_eof= 0x00000021, toki_word_if= 0x00000022, toki_word_catchquit= 0x00000023, toki_word_errorspush= 0x00000024, toki_word_elif= 0x00000025, toki_word_else= 0x00000026, toki_word_fi= 0x00000027, toki_word_hctac= 0x00000028, toki_word_srorre= 0x00000029, toki_word_glob= 0x0000002a, toki_word_range= 0x0000002b, toki_word_grep= 0x0000002c, toki_word_environment= 0x0000002d, toki_word_parameter= 0x0000002e, toki_word_version= 0x0000002f, toki_word_toplevel= 0x00000030, toki_word_override= 0x00000031, toki_word_shutdown= 0x00000032, toki_word_reset= 0x00000033, toki_word_execute= 0x00000034, toki_word_help= 0x00000035, toki_word_service= 0x00000036, toki_word_callinguser= 0x00000037, toki_word_callinggroup= 0x00000038, toki_word_callingusershell= 0x00000039, toki_word_serviceuser= 0x0000003a, toki_word_servicegroup= 0x0000003b, toki_word_serviceusershell= 0x0000003c, toki_syslog_debug= 0x0000003d, toki_syslog_info= 0x0000003e, toki_syslog_notice= 0x0000003f, toki_syslog_warning= 0x00000040, toki_syslog_err= 0x00000041, toki_syslog_crit= 0x00000042, toki_syslog_alert= 0x00000043, toki_syslog_emerg= 0x00000044, toki_syslog_authpriv= 0x00000045, toki_syslog_cron= 0x00000046, toki_syslog_daemon= 0x00000047, toki_syslog_kern= 0x00000048, toki_syslog_lpr= 0x00000049, toki_syslog_mail= 0x0000004a, toki_syslog_news= 0x0000004b, toki_syslog_syslog= 0x0000004c, toki_syslog_user= 0x0000004d, toki_syslog_uucp= 0x0000004e, toki_syslog_local0= 0x0000004f, toki_syslog_local1= 0x00000050, toki_syslog_local2= 0x00000051, toki_syslog_local3= 0x00000052, toki_syslog_local4= 0x00000053, toki_syslog_local5= 0x00000054, toki_syslog_local6= 0x00000055, toki_syslog_local7= 0x00000056, toki_word_read= 0x00000057, toki_word_write= 0x00000058, toki_ordinal= 0x00000059, toki_fdrange= 0x0000005a, toki_fdstoend= 0x0000005b, toki_dollar= 0x0000005c, toki_word_stdin= 0x0000005d, toki_word_stdout= 0x0000005e, toki_word_stderr= 0x0000005f, toki_lwsp= 0x00000060, toki_newline= 0x00000061, toki_barestring= 0x00000062, toki_quotedstring= 0x00000063, toki_eof= 0x00000064, toki_quit= 0x00000065, toki_error= 0x00000066, toki_openparen= 0x00000067, toki_closeparen= 0x00000068, toki_not= 0x00000069, toki_and= 0x0000006a, toki_or= 0x0000006b, toki_word_error= 0x0000006c, tokv_word_reject= tokt_directive|tokt_execmode|tokr_word|toki_word_reject, tokv_word_executefromdirectory=tokt_directive|tokt_execmode|tokr_word|toki_word_executefromdirectory, tokv_word_executefrompath= tokt_directive|tokt_execmode|tokr_word|toki_word_executefrompath, tokv_word_executebuiltin= tokt_directive|tokt_execmode|tokr_word|toki_word_executebuiltin, tokv_word_errorstostderr= tokt_directive|tokt_ehandlemode|tokr_word|toki_word_errorstostderr, tokv_word_errorstosyslog= tokt_directive|tokt_ehandlemode|tokr_word|toki_word_errorstosyslog, tokv_word_errorstofile= tokt_directive|tokt_ehandlemode|tokr_word|toki_word_errorstofile, tokv_word_includelookupquoteold=tokt_directive|tokt_lookupquotemode|tokr_word|toki_word_includelookupquoteold, tokv_word_includelookupquotenew=tokt_directive|tokt_lookupquotemode|tokr_word|toki_word_includelookupquotenew, tokv_word_requirefd= tokt_directive|tokr_word|toki_word_requirefd, tokv_word_allowfd= tokt_directive|tokr_word|toki_word_allowfd, tokv_word_nullfd= tokt_directive|tokr_word|toki_word_nullfd, tokv_word_rejectfd= tokt_directive|tokr_word|toki_word_rejectfd, tokv_word_ignorefd= tokt_directive|tokr_word|toki_word_ignorefd, tokv_word_setenvironment= tokt_directive|tokr_word|toki_word_setenvironment, tokv_word_nosetenvironment= tokt_directive|tokr_word|toki_word_nosetenvironment, tokv_word_suppressargs= tokt_directive|tokr_word|toki_word_suppressargs, tokv_word_nosuppressargs= tokt_directive|tokr_word|toki_word_nosuppressargs, tokv_word_disconnecthup= tokt_directive|tokr_word|toki_word_disconnecthup, tokv_word_nodisconnecthup= tokt_directive|tokr_word|toki_word_nodisconnecthup, tokv_word_cd= tokt_directive|tokr_word|toki_word_cd, tokv_word_userrcfile= tokt_directive|tokr_word|toki_word_userrcfile, tokv_word_include= tokt_directive|tokr_word|toki_word_include, tokv_word_includeifexist= tokt_directive|tokr_word|toki_word_includeifexist, tokv_word_includelookup= tokt_directive|tokr_word|toki_word_includelookup, tokv_word_includelookupall= tokt_directive|tokr_word|toki_word_includelookupall, tokv_word_includedirectory= tokt_directive|tokr_word|toki_word_includedirectory, tokv_word_message= tokt_directive|tokr_word|toki_word_message, tokv_word_includesysconfig= tokt_directive|tokt_internal|tokr_word|toki_word_includesysconfig, tokv_word_includeuserrcfile= tokt_directive|tokt_internal|tokr_word|toki_word_includeuserrcfile, tokv_word_includeclientconfig=tokt_directive|tokt_internal|tokr_word|toki_word_includeclientconfig, tokv_word_quit= tokt_directive|tokr_word|toki_word_quit, tokv_word_eof= tokt_directive|tokr_word|toki_word_eof, tokv_word_if= tokt_directive|tokt_controlstart|tokr_word|toki_word_if, tokv_word_catchquit= tokt_directive|tokt_controlstart|tokr_word|toki_word_catchquit, tokv_word_errorspush= tokt_directive|tokt_controlstart|tokr_word|toki_word_errorspush, tokv_word_elif= tokt_controlend|tokt_controlstart|tokr_word|toki_word_elif, tokv_word_else= tokt_controlend|tokt_controlstart|tokr_word|toki_word_else, tokv_word_fi= tokt_controlend|tokr_word|toki_word_fi, tokv_word_hctac= tokt_controlend|tokr_word|toki_word_hctac, tokv_word_srorre= tokt_controlend|tokr_word|toki_word_srorre, tokv_word_glob= tokt_parmcondition|tokr_word|toki_word_glob, tokv_word_range= tokt_parmcondition|tokr_word|toki_word_range, tokv_word_grep= tokt_parmcondition|tokr_word|toki_word_grep, tokv_word_environment= tokt_builtinservice|tokr_word|toki_word_environment, tokv_word_parameter= tokt_builtinservice|tokr_word|toki_word_parameter, tokv_word_version= tokt_builtinservice|tokr_word|toki_word_version, tokv_word_toplevel= tokt_builtinservice|tokr_word|toki_word_toplevel, tokv_word_override= tokt_builtinservice|tokr_word|toki_word_override, tokv_word_shutdown= tokt_builtinservice|tokr_word|toki_word_shutdown, tokv_word_reset= tokt_builtinservice|tokt_directive|tokr_word|toki_word_reset, tokv_word_execute= tokt_builtinservice|tokt_directive|tokt_execmode|tokr_word|toki_word_execute, tokv_word_help= tokt_builtinservice|tokr_word|toki_word_help, tokv_word_service= tokt_parameter|tokr_word|toki_word_service, tokv_word_callinguser= tokt_parameter|tokr_word|toki_word_callinguser, tokv_word_callinggroup= tokt_parameter|tokr_word|toki_word_callinggroup, tokv_word_callingusershell= tokt_parameter|tokr_word|toki_word_callingusershell, tokv_word_serviceuser= tokt_parameter|tokr_word|toki_word_serviceuser, tokv_word_servicegroup= tokt_parameter|tokr_word|toki_word_servicegroup, tokv_word_serviceusershell= tokt_parameter|tokr_word|toki_word_serviceusershell, tokv_syslog_debug= tokt_loglevel|tokr_word|toki_syslog_debug, tokv_syslog_info= tokt_loglevel|tokr_word|toki_syslog_info, tokv_syslog_notice= tokt_loglevel|tokr_word|toki_syslog_notice, tokv_syslog_warning= tokt_loglevel|tokr_word|toki_syslog_warning, tokv_syslog_err= tokt_loglevel|tokr_word|toki_syslog_err, tokv_syslog_crit= tokt_loglevel|tokr_word|toki_syslog_crit, tokv_syslog_alert= tokt_loglevel|tokr_word|toki_syslog_alert, tokv_syslog_emerg= tokt_loglevel|tokr_word|toki_syslog_emerg, tokv_syslog_authpriv= tokt_logfacility|tokr_word|toki_syslog_authpriv, tokv_syslog_cron= tokt_logfacility|tokr_word|toki_syslog_cron, tokv_syslog_daemon= tokt_logfacility|tokr_word|toki_syslog_daemon, tokv_syslog_kern= tokt_logfacility|tokr_word|toki_syslog_kern, tokv_syslog_lpr= tokt_logfacility|tokr_word|toki_syslog_lpr, tokv_syslog_mail= tokt_logfacility|tokr_word|toki_syslog_mail, tokv_syslog_news= tokt_logfacility|tokr_word|toki_syslog_news, tokv_syslog_syslog= tokt_logfacility|tokr_word|toki_syslog_syslog, tokv_syslog_user= tokt_logfacility|tokr_word|toki_syslog_user, tokv_syslog_uucp= tokt_logfacility|tokr_word|toki_syslog_uucp, tokv_syslog_local0= tokt_logfacility|tokr_word|toki_syslog_local0, tokv_syslog_local1= tokt_logfacility|tokr_word|toki_syslog_local1, tokv_syslog_local2= tokt_logfacility|tokr_word|toki_syslog_local2, tokv_syslog_local3= tokt_logfacility|tokr_word|toki_syslog_local3, tokv_syslog_local4= tokt_logfacility|tokr_word|toki_syslog_local4, tokv_syslog_local5= tokt_logfacility|tokr_word|toki_syslog_local5, tokv_syslog_local6= tokt_logfacility|tokr_word|toki_syslog_local6, tokv_syslog_local7= tokt_logfacility|tokr_word|toki_syslog_local7, tokv_word_read= tokt_readwrite|tokr_word|toki_word_read, tokv_word_write= tokt_readwrite|tokr_word|toki_word_write, tokv_ordinal= tokt_number|tokt_fdrange|tokr_word|toki_ordinal, tokv_fdrange= tokt_fdrange|tokr_punct|toki_fdrange, tokv_fdstoend= tokt_fdrange|tokr_punct|toki_fdstoend, tokv_dollar= tokt_misc|tokr_punct|toki_dollar, tokv_word_stdin= tokt_fdrange|tokr_word|toki_word_stdin, tokv_word_stdout= tokt_fdrange|tokr_word|toki_word_stdout, tokv_word_stderr= tokt_fdrange|tokr_word|toki_word_stderr, tokv_lwsp= tokt_misc|tokr_nonstring|toki_lwsp, tokv_newline= tokt_misc|tokr_nonstring|toki_newline, tokv_barestring= tokt_string|tokr_string|toki_barestring, tokv_quotedstring= tokt_string|tokr_string|toki_quotedstring, tokv_eof= tokt_exception|tokr_nonstring|toki_eof, tokv_quit= tokt_exception|tokr_nonstring|toki_quit, tokv_error= tokt_exception|tokr_nonstring|toki_error, tokv_openparen= tokt_condop|tokr_punct|toki_openparen, tokv_closeparen= tokt_condop|tokr_punct|toki_closeparen, tokv_not= tokt_condop|tokr_punct|toki_not, tokv_and= tokt_condop|tokr_punct|toki_and, tokv_or= tokt_condop|tokr_punct|toki_or, tokv_word_error= tokt_directive|tokt_loglevel|tokr_word|toki_word_error, }; #endif �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������work/tokens.h.m4������������������������������������������������������������������������������������0000664�0000000�0000000�00000002341�14163725562�010736� 0����������������������������������������������������������������������������������������������������ustar ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������dnl userv - tokens.h.m4 dnl token values, passed through m4 with defs from langauge.i4 /* * userv is copyright Ian Jackson and other contributors. * See README for full authorship information. * * 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; if not, see <http://www.gnu.org/licenses/>. */ include(language.i4) #ifndef TOKENS_H #define TOKENS_H enum tokens { tokm_instance= 0x000000ff, tokm_repres= 0x00000f00, tokm_type= 0xfffff000, tokr_nonstring= 0x00000100, tokr_word= 0x00000200, tokr_punct= 0x00000300, tokr_string= 0x00000400, undivert(4) undivert(1) undivert(2) }; #endif divert(-1) undivert �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������work/userv.1����������������������������������������������������������������������������������������0000664�0000000�0000000�00000031722�14163725562�010176� 0����������������������������������������������������������������������������������������������������ustar ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������.\" .\" This manpage is copyright, like the rest of userv, - see the .\" copyright section, below. .Dd November 3, 1999 .Dt USERV 1 .Os "userv" .Sh NAME .Nm userv .Nd request user services .Sh SYNOPSIS .Nm userv .Op Ar option ... .Op Fl - .Ar service-user .Ar service-name .Op Ar argument ... .Nm userv .Op Ar option ... .Fl B | -builtin .Op Fl - .Ar builtin-service .Bk -words .Op Ar info-argument ... .Ek .Sh DESCRIPTION .Nm userv is used to have a task performed under different userid while maintaining limited trust between caller and callee. .Pp .Ar service-user specifies which user account is to perform the task. The user may be a login name or a numeric uid, or .Ql - to indicate that the service user is to be the same as the calling user. .Pp The service name is interpreted by the userv daemon on behalf of the service user. This is controlled by configuration files in the service user's filespace; consult the userv specification for details. .Sh OPTIONS Single-letter options may be combined as is usual with Unix programs, and the value for such an option may appear in the same argument or in the next. .Bl -tag -width Fl .It Fl B | -builtin Requests that a builtin service be provided. This is equivalent to using the .Fl -override option to specify a string consisting of .Ql execute-builtin followed by the .Ar builtin-service requested, and requesting a service user of .Ql - (indicating the calling user). .Pp If the builtin service being requested requires a .Ar service-argument then this must be supplied to the client in the same argument as the .Ar builtin-service . See the specification, or the output of .Bd -literal -offset indent -compact userv -B help .Ed for details of the builtin services available, and below for details of the .Fl -override options. .Pp The actual service name passed will be the .Ar builtin-service ; note that this actual service name (as opposed to the override data) and the .Ar info-argument Ns s supplied will be ignored by most builtin services; the override mechanism and .Ql execute-builtin will be used to ensure that the right builtin service is called with the right .Ar service-argument Ns s . .It Xo .Fl f | -file .Sm off .Ar fd Oo Ar fdmodifiers Oc = Ar filename .Sm on .Xc Requests that data be copied in and out of the service using pipes. For each file or descriptor this will be done by creating a pipe, one end of which is passed to the service program and the other end of which is passed to a copy of .Nm cat invoked by the client; the other file descriptor passed to .Nm cat will be one inherited by the client program from the caller or one opened by the client program on behalf of the caller. .Pp The descriptor in the service program that should be connected must be specified as .Ar fd , either as a decimal number or as one of the strings .Ql stdin , .Ql stdout or .Ql stderr . The next argument is a filename which will be opened by the client with the privileges of the calling user. .Pp .Ar modifiers is used to specify whether the file or descriptor is to be read from or written to. It consists of a series of words separated by commas. A comma may separate the .Ar modifiers from the .Ar fd and is required if .Ar fd is not numeric. The modifier words are: .Bl -tag -width Li .It Ic read .Dv O_RDONLY : Allow reading and not writing. May not be used with .Ql write or things that imply it. .It Ic write .Dv O_WRONLY : Allow writing and not reading. .Em Doesn't truncate or create without .Ql truncate or .Ql create . .Ql write or things that imply it may not be used with .Ql read . .It Ic overwrite Equivalent to .Ql write,create,truncate . .It Ic create , creat .Dv O_CREAT : Creates the file if necessary. Implies .Ql write . .It Ic exclusive , excl .Dv O_EXCL: Fails if the file already exists. Implies write and create. May not be used with .Ql truncate . .It Ic truncate , trunc .Dv O_TRUNC: Truncate any existing file. Implies .Ql write . May not be used with .Ql exclusive . .It Ic append .Dv O_APPEND : All writes will append to the file. Implies .Ql write (but not .Ql create ) . .It Ic sync .Dv O_SYNC : Do writes synchronously. Implies .Ql write . .It Ic wait , nowait , close These modifiers control the behaviour of the client, with respect to the pipes carrying data to and from the service, when the service terminates. See below. .It Ic fd The .Ar filename is not a filename but a numeric file descriptor. One or both of .Ql read and .Ql write must be specified, and no other words are allowed. The .Ar filename may also be .Ql stdin , .Ql stdout or .Ql stderr for file descriptor 0, 1 or 2 respectively. .El .Pp If no .Ar modifiers which imply .Ql read or .Ql write are used it is as if .Ql write had been specified, except that if the filedescriptor 0 of the service is being opened (either specified numerically or with .Ql stdin ) it is as if .Ql overwrite had been specified (or .Ql write if only .Ql fd was specified). .Pp The client will also use .Dv O_NOCTTY when opening files specified by the caller, to avoid changing its controlling terminal. .Pp By default .Va stdin , .Va stdout and .Va stderr of the service will be connected to the corresponding descriptors on the client. Diagnostics from the client and daemon will also appear on .Va stderr . .Pp If .Ql wait is specified, the client will wait for the pipe to be closed, and only exit after this has happened. This means that either the receiving end of the pipe connection was closed while data was still available at the sending end, or that the end of file was reached on the reading file descriptor. Errors encountered reading or writing in the client at this stage will be considered a system error and cause the client to exit with status 255, but will not cause disconnection at the service side since the service has already exited. .Pp If .Ql close is specified the client will immediately close the pipe connection by killing the relevant copy of .Nm cat . If the service uses the descriptor it will get .Dv SIGPIPE (or .Er EPIPE ) for a writing descriptor or end of file for a reading one; the descriptor opened by or passed to the client will also be closed. .Pp If .Ql nowait is specified then the client will not wait and the connection will remain open after the client terminates. Data may continue to be passed between the inheritors of the relevant descriptor on the service side and the corresponding file or descriptor on the client side until either side closes their descriptor. This should not usually be specified for .Va stderr (or .Va stdout if .Ql "--signals stdout" is used) since diagnostics from the service side may arrive after the client has exited and be confused with expected output. .Pp The default is .Ql wait for writing file descriptors and .Ql close for reading ones. .It Xo .Fl w | -fdwait .Ar fd Ns = Ns Ar action .Xc Sets the action on termination of the service for the specified file descriptor; .Ar action must be .Ql wait , .Ql nowait or .Ql close as described above. The file descriptor must be specified as open when this option is encountered; this option is overridden by any later .Fl -file or .Fl -fdwait option - even by a .Fl -file which does not specify an action on termination (in this case the default will be used, as described above). .It Xo .Fl D | -defvar .Ar name Ns = Ns Ar value .Xc Set a user-defined variable .Ar name to .Ar value . These user-defined variables are made available in the configuration language as the parameters .Ql u- Ns Ar name and are passed to the service in environment variables .Ev USERV_U_ Ns Ar name . .Ar name may contain only alphanumerics and underscores, and must start with a letter. If several definitions are given for the same .Ar name then only the last is effective. .It Fl t | -timeout Ar seconds Time out the service if it takes longer than .Ar seconds seconds (a positive integer, in decimal). Timeout will produce a diagnostic on stderr and an exit status of 255. If .Ar seconds is zero then no timeout will be implemented (this is the default). .It Fl S | -signals Ar method Affects the handling of the exit status when the service terminates due to a signal. (The client will always finish by calling .Fn _exit , so that only numbers from 0 to 255 can be returned and not the full range of numbers and signal indications which can be returned by the .Fn wait family of system calls.) .Pp The .Ar method may be one of the following: .Bl -tag -width Li .It Ar status The client's exit status will be .Ar status . This will not be distinguishable from the service really having exited with code .Ar status . This method is the default, with a .Ar status of 254. .It Ic number , number-nocore The client's exit status will be the number of the signal which caused the termination of the service. If .Ql number is used rather than .Ql number-nocore then 128 will be added if the service dumped core. .Ql number is very like the exit code mangling done by the Bourne shell. .It Ic highbit The client's exit status will be the number of the signal with 128 added. If the service exits normally with an exit code of greater than 127 then 127 will be returned. .It Ic stdout The service's numeric wait status as two decimal numbers (high byte first) and a textual description of its meaning will be printed to the client's standard output. It will be preceded by a newline and followed by an extra newline, and the numbers are separated from each other and from the textual description by single spaces. The exit status of the client will be zero, unless a system error occurs in which case no exit status and description will be printed to .Va stdout , and an error message will be printed to .Va stderr as usual. .Pp Problems such as client usage errors, the service not being found or permission being denied or failure of a system call are system errors. An error message describing the problem will be printed on the client's .Va stderr , and the client's exit status will be 255. If the client dies due to a signal this should be treated as a serious system error. .El .It Fl H | -hidecwd Prevents the calling process's current directory name from being passed to the service; the null string will be passed instead. .It Fl P | -sigpipe If the service program is terminated due to a .Dv SIGPIPE the exit status of the client will be zero, even if it would have been something else according to the exit status method specified. This option has no effect on the code and description printed if the exit status method .Ql stdout is in use. .It Fl h | -help Prints the client's usage message. .It Fl -copyright Prints the copyright and lack of warranty notice. .El .Sh SECURITY-OVERRIDING OPTIONS There are also some options which are available for debugging and to allow the system administrator to override a user's policy. These options are available only if the client is called by root or if the calling user is the same as the service user. .Bl -tag -width Fl .It Fl -override Ar configuration-data .It Fl -override-file Ar file Do not read the usual configuration files. Instead, the client sends .Ar configuration-data (followed by a newline) or the contents of .Ar filename (which is opened in the context of the client) to the daemon and the daemon uses that data instead. The .Ar configuration-data must all be in one argument. It will have a single newline appended so that a single directive can easily be given, but if more than one directive is required it will have to contain one or more real newlines. .It Fl -spoof-user Ar user Pretend to the service that it is being called by .Ar user (which may be a username or a uid). This will also affect the group and supplementary groups supplied to the service; they will be the standard group and supplementary groups for .Ar user . The .Fl -spoof-user option will .Em not affect which user is chosen if the service user is specified as just .Ql - ; in this case the service user will be the real calling user. .El .Sh ENVIRONMENT .Bl -tag -width Ev .It Ev LOGNAME , USER These are used to determine the name of the calling user, to be passed to the service in .Ev USERV_USER . Their values will only be used if they correspond to the calling UID. .El .Sh FILES .Bl -tag -width Pa .It Pa /var/run/userv/socket .Ux Ns -domain socket used for communication between .Nm and .Nm uservd . .It Pa /var/run/userv/%x.%x.%x Pipes used for connecting file descriptors in the client and the service. .El .Sh SEE ALSO .Xr uservd 8 .Rs .%T "User service daemon and client specification" .%A Ian Jackson .Re .Sh COPYRIGHT GNU userv is copyright Ian Jackson and other contributors. See README or .Dv userv --copright for full authorship information. .Pp GNU userv is licensed under the terms of the GNU General Public Licence, version 3 or (at your option) any later version, and it comes with NO WARRANTY, not even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for details. .Pp You should have received a copy of the GNU General Public License along with userv, if not, see http://www.gnu.org/licenses/ .Sh HISTORY .Nm was initially written in 1996 by Ian Jackson. It became .Tn GNU .Nm in 1999, and version 1.0 was released in 2000. ����������������������������������������������work/userv.service����������������������������������������������������������������������������������0000664�0000000�0000000�00000000442�14163725562�011471� 0����������������������������������������������������������������������������������������������������ustar ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������[Unit] Description=User services (security boundary) daemon After=syslog.target remote-fs.target [Service] Type=forking ExecStartPre=/bin/sh -c 'test -d /var/run/userv || mkdir -m700 /var/run/userv' ExecStart=/usr/sbin/uservd -daemon KillMode=process [Install] WantedBy=multi-user.target ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������work/uservd.8���������������������������������������������������������������������������������������0000664�0000000�0000000�00000010623�14163725562�010346� 0����������������������������������������������������������������������������������������������������ustar ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������.\" .\" This manpage is copyright, like the rest of userv, - see the .\" copyright section, below. .Dd November 3, 1999 .Dt USERVD 8 .Os "userv" .Sh NAME .Nm uservd .Nd supply user services .Sh SYNOPSIS .Nm userv .Op Fl daemon .Sh DESCRIPTION .Nm uservd is the daemon called by .Nm userv to have a task performed under different userid while maintaining limited trust between caller and callee. .Sh OPTIONS There is one optional argument: .Bl -tag -width Fl .It Fl daemon Requests that the program daemonise. If this flag is supplied, .Nm uservd will fork and completely detach from the controlling terminal. If this option is not supplied, .Nm uservd will remain in its starting process group and continue to use the supplied stderr stream for any runtime system messages; this is useful for running .Nm uservd as a child of .Nm init Ns . Errors detected by .Nm uservd itself will be reported via .Nm syslog in either case. .El .Sh SYSLOG MESSAGES: .Nm uservd issues diagnostics of various kinds to syslog, with facility .Nm LOG_DAEMON Ns . The syslog levels used are: .Bl -tag -width Nm .It Nm debug Verbose messages about the activity of the userv daemon. .It Nm info Two log messages about the nature and outcome of each request. .It Nm notice Messages about the status of the daemon, including the startup message and the hourly socket check messages. .It Nm warning If the uservd exits because it believes that it no longer controls the rendezvous socket (ie, its socket has become orphaned), this level will receive messages indicating why the daemon believes this and notifying of its shutdown. .It Nm err A believed-recoverable error condition was detected by the userv server in itself, the client or the operating system (this includes resource shortages). The uservd will try to continue. .It Nm crit The uservd detected a non-recoverable error condition after startup and will exit. .It Nm alert not used. .It Nm emerg not used. .El .Pp The service configuration language has the facility to direct error and warning messages to syslog. The default facility and level is .Nm user.err Ns , but the author of the configuration file(s) can override this. .Sh EXIT STATUS The daemon's exit code will reflect how well things went: .Bl -tag -width Nm .It Nm 0 The daemon was asked to detach itself from the controlling terminal and this appears to have been done successfully. .It Nm 1* The daemon got a SIGTERM or SIGINT and shut itself down. .It Nm 2* The daemon believed that it was no longer the uservd and so exited to clean up. .It Nm 3 uservd was started with incorrect arguments. .It Nm 4 A system call failure or other environmental problem occurred during startup. .It Nm 5* There was a non-recoverable error after startup; the uservd had to exit. .It Nm 6 The daemon was asked to detach itself, but its detaching child died for some unexpected reason. .It Nm SIGABRT/SIGIOT* An unexpected internal error, usually caused by a bug in uservd. This can also occur if an attempt to block signals using sigprocmask fails. .El .Pp Outcomes marked * are not possible if the daemon is asked to detach itself - these exit statuses will be reaped by init instead and so will not usually be logged anywhere. .Pp The daemon's per-request children will report the success or otherwise of its request in their exit status. These are not usually be logged unless they indicate a serious problem. .Sh ENVIRONMENT All of the environment variables passed to .Nm uservd will be inherited by services as part of the default environment. (If the .Nm set-environment configuration directive is used, then other system configuration files can modify the environment. Consult the specification.) .Sh SEE ALSO .Xr userv 1 .Xr init 8 .Rs .%T "User service daemon and client specification" .%A Ian Jackson .Re .Sh COPYRIGHT GNU userv is copyright Ian Jackson and other contributors. See README or .Dv userv --copright for full authorship information. .Pp GNU userv is licensed under the terms of the GNU General Public Licence, version 3 or (at your option) any later version, and it comes with NO WARRANTY, not even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for details. .Pp You should have received a copy of the GNU General Public License along with userv, if not, see http://www.gnu.org/licenses/ .Sh HISTORY .Nm was initially written in 1996 by Ian Jackson. It became .Tn GNU .Nm in 1999, and version 1.0 was released in 2000. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������