cfengine-3.12.1/ 0000755 0000000 0000000 00000000000 13377750570 013370 5 ustar 00root root 0000000 0000000 cfengine-3.12.1/LICENSE 0000644 0000000 0000000 00000126244 13377750461 014405 0 ustar 00root root 0000000 0000000 This file contains a copy of:
1) The GNU General Public License version 3
1) The Commercial Open Source License (COSL)
----------------------------------------------------------------------------
CFEngine is provided under the terms of the GNU General Public License version 3
(below), with explicit permission to link with the OpenSSL library, BerkeleyDB
library and and PCRE library.
On some systems, code under the Frontier Artistic License
(/libcompat/snprintf) might become compiled. This is compatible with the
GPL.
Users of the software may, at their option, choose the COSL license
below as part of the enterprise CFEngine product.
----------------------------------------------------------------------------
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
.
------------------------------------------------------------------------------
COMMERCIAL OPEN SOURCE LICENSE
This CFEngine commercial open source license ("COSL") is entered into
between Cfengine AS, a Norwegian company, as licensor and
a) the Customer entity stipulated on a complete agreement front page (“Front page”),
b) any entity or natural person downloading, installing or taking the
Software or any part of it into use, or
c) any entity or person who otherwise has agreed to be bound by these
terms (collectively the "Licensee").
1 LICENSE
1.1 General
The Software is licensed on a consecutive basis (rental) or
perpetually, as stipulated on the Front page. See 1.2 and 1.3 below
respectively. The following shall apply to either type of license
grants.
Subject to the terms of this COSL and other agreement between the
parties, Cfengine hereby grants to Licensee a non-exclusive,
non-transferable, non-sublicensable and limited license to install,
use, study and modify the number of copies of the Software on the
number of Instances stipulated on the Front page for use within its
organization.
The number of Instances the Software may be installed on may be
changed by the Customer from time to time, provided ample notice is
given to Cfengine. See Front page for reporting.
The Licensee may modify, adapt and create derivative works based upon
the Software, for use within its organisation and for sharing between
other consecutive licensees under the COSL. Therefore, the Licensee
shall have access to the source code of the Software. However, the
Licensee shall not reproduce, distribute, resell, rent, lease or
disclose the Software in any manner or form to any other third party
not holding a COSL to the Software.
Licensee may not transfer any of its rights under this COSL without
the prior and express written consent of Cfengine.
Any CFEngine software component used by both the CFEngine enterprise
version and CFEngine community edition is licensed under the terms of
this COSL if the Licensee does not state in writing to Cfengine that
the Licensee instead wish to license the component in question under
the GNU General Public License (GPL) v.3.0 or other applicable
license.
Third party software is licensed under the license of such third
party.
1.2 Consecutive license grant (subscription)
If the license grant is agreed to be consecutive (see stipulation on
Front page), it shall be effective for the period the consecutive
license fee (subscription fee) is paid and this license is otherwise
complied to. The payment of the consecutive license fee entitles the
Customer to Updates and New versions of the Software (as stipulated in
appendix 1).
1.3 Perpetual license grant
If the license grant is agreed to be perpetual (see stipulation on
Front page), the grant is for ever, provided the license terms are
complied to. The perpetual license grant is limited to current the
version of the Software at the Effective date. Updates or New versions
of the Software are not included, unless stated on the Front page
(subject to additional fee).
2 DEFINITIONS
The following definitions shall apply to the COSL:
“Instances” means each physical or virtual computer (server or
client), onto which an installation of the Software takes place.
“New version” (of the Software) means a new edition of the Software
containing functionality or properties not present in the previous
edition of the Software.
"Software" means:
a) the CFEngine Enterprise data centre administration software
downloaded by the Licensee or otherwise given access to including
bundled documentation and other material, as described at
http://www.cfengine.com/; and
b) new versions and updates to such software provided by Cfengine, and
“Update” (of Software) means smaller adjustments of the Software with
the existing functionality, normally by way of installation of new
copy of the Software.
3 FEES
The Licensee shall pay a license fee per Instance the Software is
installed on for the license granted herein; either:
a) per time unit (as agreed) e.g. year, for consecutive license grants, or
b) once, for perpetual license grants, for the number of Instances
stated on the Front page, or any later adjustments. See the Front page
for further details.
4 INTELLECTUAL PROPERTY RIGHTS
Cfengine and its suppliers do not by this COSL transfer any
copyrights or other intellectual property rights relating to the
Software to the Licensee. Such rights are protected by intellectual
property legislation in the United States, Europe and other
jurisdictions and by international treaty provisions. Cfengine and its
suppliers retain all rights in the Software that are not expressly
granted to the Licensee through this COSL.
Licensee is not allowed to remove, alter or destroy any proprietary,
trademark or copyright markings or notices placed upon or contained
within the Software.
5 TERMINATION
Cfengine may terminate the COSL if the Licensee fails to comply with
the terms of this COSL, hereunder fails to pay the stipulated fees. In
the event of such termination, the Licensee shall immediately stop
using the Software, return any received media and documentation, and
destroy or permanently delete any installed versions of the Software,
and confirm such destruction or deletion in writing within 7 days.
6 IDEMNIFICATION
If the Software (except for third party software) during the term of
the license grant is held by a court of competent jurisdiction to
infringe any third party intellectual property rights and the Licensee
incurs loss or expense as a result of such holding, then Licenee's
sole remedy shall be, and Cfengine will, at its option: (i) obtain the
right for Licensse to continue to use the Software consistent with the
COSL; (ii) modify the Software so that it becomes non-infringing;
(iii) replace the infringing component with a non-infringing
component, or (iv) refund monies paid by Licensee under the Agreement
during the prior six (6) months to the court holding (for consecutive
license grants) or a forth of any perpetual license fee paid, and all
Licensees rights and licenses under this Agreement shall automatically
terminate.
The Licensee is aware that the Software is also comprised of third
party software, mostly open source software. Such third party software
are subject to its individual license terms, and any claims shall be
directed at the ultimate right holder to that software. Consequently
Cfengine is not liable for any defective title in such third party
software. See schedule 5 for a list of software contained by the
Software with related licenses.
7 NO WARRANTY
To the maximum extent permitted by law, Cfengine disclaims any
warranty for the Software (except as stated in clause 6). The
Software, any services and any related documentation is provided on an
"as is" basis without warranty of any kind, whether express or
implied, including, but not limited to, implied warranties of
merchantability, fitness for a particular purpose or non-infringement
(except as stated in clause 6). Hereunder the parties acknowledges
that Cfengine does not warrant for the performance of any data centre
on which the Software runs, or the absence of any errors in the
Software, and that any such errors does not constitute a contractual
defect.
8 LIABILITY
The liability of the parties in contract, tort (including negligence)
or otherwise shall for all incidents during the entire term of the
COSL be limited to a fifth of the fees paid for a perpetual license or
the annual consecutive license fees paid for the Software causing the
damage or loss, up to a maximum of NOK 100 000. Cfengine or its
suppliers shall not be liable for any special, incidental, indirect or
consequential damages whatsoever (including, without limitation,
damages for loss of business profits, lost savings, business
interruption, loss of business information, personal injury, loss of
privacy, loss of goodwill or any other financial loss) arising out of
the use of or inability to use the Software, even if advised of the
possibility of such damages.
9 THIRD-PARTY TERMS
For third-party software that is made available to the Licensee by
Cfengine, the current terms of the relevant third party software
supplier shall apply.
cfengine-3.12.1/ylwrap 0000755 0000000 0000000 00000015312 13377750517 014637 0 ustar 00root root 0000000 0000000 #! /bin/sh
# ylwrap - wrapper for lex/yacc invocations.
scriptversion=2013-01-12.17; # UTC
# Copyright (C) 1996-2013 Free Software Foundation, Inc.
#
# Written by Tom Tromey .
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
# As a special exception to the GNU General Public License, if you
# distribute this file as part of a program that contains a
# configuration script generated by Autoconf, you may include it under
# the same distribution terms that you use for the rest of that program.
# This file is maintained in Automake, please report
# bugs to or send patches to
# .
get_dirname ()
{
case $1 in
*/*|*\\*) printf '%s\n' "$1" | sed -e 's|\([\\/]\)[^\\/]*$|\1|';;
# Otherwise, we want the empty string (not ".").
esac
}
# guard FILE
# ----------
# The CPP macro used to guard inclusion of FILE.
guard ()
{
printf '%s\n' "$1" \
| sed \
-e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/' \
-e 's/[^ABCDEFGHIJKLMNOPQRSTUVWXYZ]/_/g' \
-e 's/__*/_/g'
}
# quote_for_sed [STRING]
# ----------------------
# Return STRING (or stdin) quoted to be used as a sed pattern.
quote_for_sed ()
{
case $# in
0) cat;;
1) printf '%s\n' "$1";;
esac \
| sed -e 's|[][\\.*]|\\&|g'
}
case "$1" in
'')
echo "$0: No files given. Try '$0 --help' for more information." 1>&2
exit 1
;;
--basedir)
basedir=$2
shift 2
;;
-h|--h*)
cat <<\EOF
Usage: ylwrap [--help|--version] INPUT [OUTPUT DESIRED]... -- PROGRAM [ARGS]...
Wrapper for lex/yacc invocations, renaming files as desired.
INPUT is the input file
OUTPUT is one file PROG generates
DESIRED is the file we actually want instead of OUTPUT
PROGRAM is program to run
ARGS are passed to PROG
Any number of OUTPUT,DESIRED pairs may be used.
Report bugs to .
EOF
exit $?
;;
-v|--v*)
echo "ylwrap $scriptversion"
exit $?
;;
esac
# The input.
input=$1
shift
# We'll later need for a correct munging of "#line" directives.
input_sub_rx=`get_dirname "$input" | quote_for_sed`
case $input in
[\\/]* | ?:[\\/]*)
# Absolute path; do nothing.
;;
*)
# Relative path. Make it absolute.
input=`pwd`/$input
;;
esac
input_rx=`get_dirname "$input" | quote_for_sed`
# Since DOS filename conventions don't allow two dots,
# the DOS version of Bison writes out y_tab.c instead of y.tab.c
# and y_tab.h instead of y.tab.h. Test to see if this is the case.
y_tab_nodot=false
if test -f y_tab.c || test -f y_tab.h; then
y_tab_nodot=true
fi
# The parser itself, the first file, is the destination of the .y.c
# rule in the Makefile.
parser=$1
# A sed program to s/FROM/TO/g for all the FROM/TO so that, for
# instance, we rename #include "y.tab.h" into #include "parse.h"
# during the conversion from y.tab.c to parse.c.
sed_fix_filenames=
# Also rename header guards, as Bison 2.7 for instance uses its header
# guard in its implementation file.
sed_fix_header_guards=
while test $# -ne 0; do
if test x"$1" = x"--"; then
shift
break
fi
from=$1
# Handle y_tab.c and y_tab.h output by DOS
if $y_tab_nodot; then
case $from in
"y.tab.c") from=y_tab.c;;
"y.tab.h") from=y_tab.h;;
esac
fi
shift
to=$1
shift
sed_fix_filenames="${sed_fix_filenames}s|"`quote_for_sed "$from"`"|$to|g;"
sed_fix_header_guards="${sed_fix_header_guards}s|"`guard "$from"`"|"`guard "$to"`"|g;"
done
# The program to run.
prog=$1
shift
# Make any relative path in $prog absolute.
case $prog in
[\\/]* | ?:[\\/]*) ;;
*[\\/]*) prog=`pwd`/$prog ;;
esac
dirname=ylwrap$$
do_exit="cd '`pwd`' && rm -rf $dirname > /dev/null 2>&1;"' (exit $ret); exit $ret'
trap "ret=129; $do_exit" 1
trap "ret=130; $do_exit" 2
trap "ret=141; $do_exit" 13
trap "ret=143; $do_exit" 15
mkdir $dirname || exit 1
cd $dirname
case $# in
0) "$prog" "$input" ;;
*) "$prog" "$@" "$input" ;;
esac
ret=$?
if test $ret -eq 0; then
for from in *
do
to=`printf '%s\n' "$from" | sed "$sed_fix_filenames"`
if test -f "$from"; then
# If $2 is an absolute path name, then just use that,
# otherwise prepend '../'.
case $to in
[\\/]* | ?:[\\/]*) target=$to;;
*) target=../$to;;
esac
# Do not overwrite unchanged header files to avoid useless
# recompilations. Always update the parser itself: it is the
# destination of the .y.c rule in the Makefile. Divert the
# output of all other files to a temporary file so we can
# compare them to existing versions.
if test $from != $parser; then
realtarget=$target
target=tmp-`printf '%s\n' "$target" | sed 's|.*[\\/]||g'`
fi
# Munge "#line" or "#" directives. Don't let the resulting
# debug information point at an absolute srcdir. Use the real
# output file name, not yy.lex.c for instance. Adjust the
# include guards too.
sed -e "/^#/!b" \
-e "s|$input_rx|$input_sub_rx|" \
-e "$sed_fix_filenames" \
-e "$sed_fix_header_guards" \
"$from" >"$target" || ret=$?
# Check whether files must be updated.
if test "$from" != "$parser"; then
if test -f "$realtarget" && cmp -s "$realtarget" "$target"; then
echo "$to is unchanged"
rm -f "$target"
else
echo "updating $to"
mv -f "$target" "$realtarget"
fi
fi
else
# A missing file is only an error for the parser. This is a
# blatant hack to let us support using "yacc -d". If -d is not
# specified, don't fail when the header file is "missing".
if test "$from" = "$parser"; then
ret=1
fi
fi
done
fi
# Remove the directory.
cd ..
rm -rf $dirname
exit $ret
# Local Variables:
# mode: shell-script
# sh-indentation: 2
# eval: (add-hook 'write-file-hooks 'time-stamp)
# time-stamp-start: "scriptversion="
# time-stamp-format: "%:y-%02m-%02d.%02H"
# time-stamp-time-zone: "UTC"
# time-stamp-end: "; # UTC"
# End:
cfengine-3.12.1/compile 0000755 0000000 0000000 00000016245 13377750516 014756 0 ustar 00root root 0000000 0000000 #! /bin/sh
# Wrapper for compilers which do not understand '-c -o'.
scriptversion=2012-10-14.11; # UTC
# Copyright (C) 1999-2013 Free Software Foundation, Inc.
# Written by Tom Tromey .
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
# As a special exception to the GNU General Public License, if you
# distribute this file as part of a program that contains a
# configuration script generated by Autoconf, you may include it under
# the same distribution terms that you use for the rest of that program.
# This file is maintained in Automake, please report
# bugs to or send patches to
# .
nl='
'
# We need space, tab and new line, in precisely that order. Quoting is
# there to prevent tools from complaining about whitespace usage.
IFS=" "" $nl"
file_conv=
# func_file_conv build_file lazy
# Convert a $build file to $host form and store it in $file
# Currently only supports Windows hosts. If the determined conversion
# type is listed in (the comma separated) LAZY, no conversion will
# take place.
func_file_conv ()
{
file=$1
case $file in
/ | /[!/]*) # absolute file, and not a UNC file
if test -z "$file_conv"; then
# lazily determine how to convert abs files
case `uname -s` in
MINGW*)
file_conv=mingw
;;
CYGWIN*)
file_conv=cygwin
;;
*)
file_conv=wine
;;
esac
fi
case $file_conv/,$2, in
*,$file_conv,*)
;;
mingw/*)
file=`cmd //C echo "$file " | sed -e 's/"\(.*\) " *$/\1/'`
;;
cygwin/*)
file=`cygpath -m "$file" || echo "$file"`
;;
wine/*)
file=`winepath -w "$file" || echo "$file"`
;;
esac
;;
esac
}
# func_cl_dashL linkdir
# Make cl look for libraries in LINKDIR
func_cl_dashL ()
{
func_file_conv "$1"
if test -z "$lib_path"; then
lib_path=$file
else
lib_path="$lib_path;$file"
fi
linker_opts="$linker_opts -LIBPATH:$file"
}
# func_cl_dashl library
# Do a library search-path lookup for cl
func_cl_dashl ()
{
lib=$1
found=no
save_IFS=$IFS
IFS=';'
for dir in $lib_path $LIB
do
IFS=$save_IFS
if $shared && test -f "$dir/$lib.dll.lib"; then
found=yes
lib=$dir/$lib.dll.lib
break
fi
if test -f "$dir/$lib.lib"; then
found=yes
lib=$dir/$lib.lib
break
fi
if test -f "$dir/lib$lib.a"; then
found=yes
lib=$dir/lib$lib.a
break
fi
done
IFS=$save_IFS
if test "$found" != yes; then
lib=$lib.lib
fi
}
# func_cl_wrapper cl arg...
# Adjust compile command to suit cl
func_cl_wrapper ()
{
# Assume a capable shell
lib_path=
shared=:
linker_opts=
for arg
do
if test -n "$eat"; then
eat=
else
case $1 in
-o)
# configure might choose to run compile as 'compile cc -o foo foo.c'.
eat=1
case $2 in
*.o | *.[oO][bB][jJ])
func_file_conv "$2"
set x "$@" -Fo"$file"
shift
;;
*)
func_file_conv "$2"
set x "$@" -Fe"$file"
shift
;;
esac
;;
-I)
eat=1
func_file_conv "$2" mingw
set x "$@" -I"$file"
shift
;;
-I*)
func_file_conv "${1#-I}" mingw
set x "$@" -I"$file"
shift
;;
-l)
eat=1
func_cl_dashl "$2"
set x "$@" "$lib"
shift
;;
-l*)
func_cl_dashl "${1#-l}"
set x "$@" "$lib"
shift
;;
-L)
eat=1
func_cl_dashL "$2"
;;
-L*)
func_cl_dashL "${1#-L}"
;;
-static)
shared=false
;;
-Wl,*)
arg=${1#-Wl,}
save_ifs="$IFS"; IFS=','
for flag in $arg; do
IFS="$save_ifs"
linker_opts="$linker_opts $flag"
done
IFS="$save_ifs"
;;
-Xlinker)
eat=1
linker_opts="$linker_opts $2"
;;
-*)
set x "$@" "$1"
shift
;;
*.cc | *.CC | *.cxx | *.CXX | *.[cC]++)
func_file_conv "$1"
set x "$@" -Tp"$file"
shift
;;
*.c | *.cpp | *.CPP | *.lib | *.LIB | *.Lib | *.OBJ | *.obj | *.[oO])
func_file_conv "$1" mingw
set x "$@" "$file"
shift
;;
*)
set x "$@" "$1"
shift
;;
esac
fi
shift
done
if test -n "$linker_opts"; then
linker_opts="-link$linker_opts"
fi
exec "$@" $linker_opts
exit 1
}
eat=
case $1 in
'')
echo "$0: No command. Try '$0 --help' for more information." 1>&2
exit 1;
;;
-h | --h*)
cat <<\EOF
Usage: compile [--help] [--version] PROGRAM [ARGS]
Wrapper for compilers which do not understand '-c -o'.
Remove '-o dest.o' from ARGS, run PROGRAM with the remaining
arguments, and rename the output as expected.
If you are trying to build a whole package this is not the
right script to run: please start by reading the file 'INSTALL'.
Report bugs to .
EOF
exit $?
;;
-v | --v*)
echo "compile $scriptversion"
exit $?
;;
cl | *[/\\]cl | cl.exe | *[/\\]cl.exe )
func_cl_wrapper "$@" # Doesn't return...
;;
esac
ofile=
cfile=
for arg
do
if test -n "$eat"; then
eat=
else
case $1 in
-o)
# configure might choose to run compile as 'compile cc -o foo foo.c'.
# So we strip '-o arg' only if arg is an object.
eat=1
case $2 in
*.o | *.obj)
ofile=$2
;;
*)
set x "$@" -o "$2"
shift
;;
esac
;;
*.c)
cfile=$1
set x "$@" "$1"
shift
;;
*)
set x "$@" "$1"
shift
;;
esac
fi
shift
done
if test -z "$ofile" || test -z "$cfile"; then
# If no '-o' option was seen then we might have been invoked from a
# pattern rule where we don't need one. That is ok -- this is a
# normal compilation that the losing compiler can handle. If no
# '.c' file was seen then we are probably linking. That is also
# ok.
exec "$@"
fi
# Name of file we expect compiler to create.
cofile=`echo "$cfile" | sed 's|^.*[\\/]||; s|^[a-zA-Z]:||; s/\.c$/.o/'`
# Create the lock directory.
# Note: use '[/\\:.-]' here to ensure that we don't use the same name
# that we are using for the .o file. Also, base the name on the expected
# object file name, since that is what matters with a parallel build.
lockdir=`echo "$cofile" | sed -e 's|[/\\:.-]|_|g'`.d
while true; do
if mkdir "$lockdir" >/dev/null 2>&1; then
break
fi
sleep 1
done
# FIXME: race condition here if user kills between mkdir and trap.
trap "rmdir '$lockdir'; exit 1" 1 2 15
# Run the compile.
"$@"
ret=$?
if test -f "$cofile"; then
test "$cofile" = "$ofile" || mv "$cofile" "$ofile"
elif test -f "${cofile}bj"; then
test "${cofile}bj" = "$ofile" || mv "${cofile}bj" "$ofile"
fi
rmdir "$lockdir"
exit $ret
# Local Variables:
# mode: shell-script
# sh-indentation: 2
# eval: (add-hook 'write-file-hooks 'time-stamp)
# time-stamp-start: "scriptversion="
# time-stamp-format: "%:y-%02m-%02d.%02H"
# time-stamp-time-zone: "UTC"
# time-stamp-end: "; # UTC"
# End:
cfengine-3.12.1/cf-serverd/ 0000755 0000000 0000000 00000000000 13377750570 015430 5 ustar 00root root 0000000 0000000 cfengine-3.12.1/cf-serverd/server_classic.h 0000644 0000000 0000000 00000002315 13377750461 020610 0 ustar 00root root 0000000 0000000 /*
Copyright 2018 Northern.tech AS
This file is part of CFEngine 3 - written and maintained by Northern.tech AS.
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; version 3.
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, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
To the extent this program is licensed as part of the Enterprise
versions of CFEngine, the applicable Commercial Open Source License
(COSL) may apply to this file if you as a licensee so wish it. See
included file COSL.txt.
*/
#ifndef CFENGINE_SERVER_CLASSIC_H
#define CFENGINE_SERVER_CLASSIC_H
#include
#include
#include "server.h"
extern int BusyWithClassicConnection(EvalContext *ctx, ServerConnectionState *conn);
#endif
cfengine-3.12.1/cf-serverd/strlist.h 0000644 0000000 0000000 00000007160 13377750461 017310 0 ustar 00root root 0000000 0000000 /*
Copyright 2018 Northern.tech AS
This file is part of CFEngine 3 - written and maintained by Northern.tech AS.
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; version 3.
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, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
To the extent this program is licensed as part of the Enterprise
versions of CFEngine, the applicable Commercial Open Source License
(COSL) may apply to this file if you as a licensee so wish it. See
included file COSL.txt.
*/
#ifndef CFENGINE_STRLIST_H
#define CFENGINE_STRLIST_H
#include
/**
* Simple length-aware string type. Allocate with string_New. Free
* simply with free().
*/
struct string
{
size_t len; /* str length not counting terminating-'\0' */
// size_t size; /* str allocated size */
char str[];
};
struct string *string_New(const char *s);
bool string_BoolCompare(const struct string *s1, const struct string *s2);
size_t string_MatchCount(const struct string *s1, const struct string *s2);
size_t string_ReverseMatchCount(const struct string *s1, const struct string *s2);
typedef int (*StringComparatorF)(const struct string **,
const struct string **);
int string_Compare(const struct string **s1,
const struct string **s2);
int string_CompareFromEnd(const struct string **s1,
const struct string **s2);
/**
* strlist is a list of #len strings.
*
* @note strlist can be NULL, which is equivalent to having 0 elements. In
* fact, NULL is the properly initialised strlist, it will be
* automatically allocated after using StrList_Insert() or
* StrList_Append().
*
* @note strlist can be a container for *any* kind of data, not only strings,
* as long as it is a one-piece memory block, and a struct with first
* field being "size_t len". '\0' termination is not needed at any
* point, so just insert/append your custom buffers.
* To use it like that use the Raw family of functions.
*/
typedef struct strlist
{
size_t len;
size_t alloc_len; /* for realloc() economy */
struct string *list[];
} StrList;
size_t StrList_Len(const StrList *sl);
char *StrList_At(const StrList *sl, size_t idx);
size_t StrList_Insert(StrList **sl, const char *s, size_t idx);
size_t StrList_Append(StrList **sl, const char *s);
void StrList_Finalise(StrList **sl);
void StrList_Free(StrList **sl);
void StrList_Sort(StrList *sl, StringComparatorF f);
bool StrList_BinarySearchString(const StrList *slp,
const struct string *s,
size_t *position);
bool StrList_BinarySearch(const StrList *slp, const char *s,
size_t *position);
size_t StrList_SearchLongestPrefix(const StrList *sl,
const char *s, size_t s_len,
char separator, bool direction_forward);
size_t StrList_SearchForPrefix(const StrList *sl,
const char *s, size_t s_len,
bool direction_forward);
#endif
cfengine-3.12.1/cf-serverd/cf-serverd-enterprise-stubs.c 0000644 0000000 0000000 00000007064 13377750461 023156 0 ustar 00root root 0000000 0000000 /*
Copyright 2018 Northern.tech AS
This file is part of CFEngine 3 - written and maintained by Northern.tech AS.
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; version 3.
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, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
To the extent this program is licensed as part of the Enterprise
versions of CFEngine, the applicable Commercial Open Source License
(COSL) may apply to this file if you as a licensee so wish it. See
included file COSL.txt.
*/
#include
#include
#include
ENTERPRISE_VOID_FUNC_3ARG_DEFINE_STUB(void, RegisterLiteralServerData,
ARG_UNUSED EvalContext *, ctx,
ARG_UNUSED const char *, handle,
ARG_UNUSED const Promise *, pp)
{
Log(LOG_LEVEL_VERBOSE, "Access to server literals is only available in CFEngine Enterprise");
}
ENTERPRISE_FUNC_3ARG_DEFINE_STUB(int, ReturnLiteralData, ARG_UNUSED EvalContext *, ctx, ARG_UNUSED char *, handle, ARG_UNUSED char *, ret)
{
Log(LOG_LEVEL_VERBOSE, "Access to server literals is only available in CFEngine Enterprise");
return 0;
}
ENTERPRISE_FUNC_5ARG_DEFINE_STUB(int, SetServerListenState, ARG_UNUSED EvalContext *, ctx, ARG_UNUSED size_t, queue_size,
ARG_UNUSED char *, bind_address, ARG_UNUSED bool, server_listen,
InitServerFunction, InitServerPtr)
{
if (!server_listen)
{
Log(LOG_LEVEL_VERBOSE, "Disable listening on port is only supported in CFEngine Enterprise");
}
return InitServerPtr(queue_size, bind_address);
}
ENTERPRISE_FUNC_1ARG_DEFINE_STUB(bool, ReceiveCollectCall, ARG_UNUSED ServerConnectionState *, conn)
{
return false;
}
ENTERPRISE_FUNC_3ARG_DEFINE_STUB(bool, ReturnQueryData, ARG_UNUSED ServerConnectionState *, conn, ARG_UNUSED char *, menu, ARG_UNUSED int, encrypt)
{
return false;
}
ENTERPRISE_FUNC_2ARG_DEFINE_STUB(bool, CFTestD_ReturnQueryData, ARG_UNUSED ServerConnectionState *, conn, ARG_UNUSED char *, menu)
{
return false;
}
ENTERPRISE_VOID_FUNC_1ARG_DEFINE_STUB(void, KeepReportDataSelectAccessPromise,
ARG_UNUSED const Promise *, pp)
{
Log(LOG_LEVEL_ERR, "Report data select is only available in CFEngine Enterprise");
}
ENTERPRISE_VOID_FUNC_0ARG_DEFINE_STUB(void, CleanReportBookFilterSet)
{
return;
}
ENTERPRISE_VOID_FUNC_1ARG_DEFINE_STUB(void, CollectCallStart, ARG_UNUSED int, interval)
{
}
ENTERPRISE_VOID_FUNC_0ARG_DEFINE_STUB(void, CollectCallStop)
{
}
ENTERPRISE_FUNC_0ARG_DEFINE_STUB(bool, CollectCallHasPending)
{
return false;
}
ENTERPRISE_FUNC_1ARG_DEFINE_STUB(int, CollectCallGetPending, ARG_UNUSED int *, queue_length)
{
return -1;
}
ENTERPRISE_VOID_FUNC_0ARG_DEFINE_STUB(void, CollectCallMarkProcessed)
{
}
ENTERPRISE_VOID_FUNC_1ARG_DEFINE_STUB(void, FprintAvahiCfengineTag, FILE *, fp)
{
fprintf(fp,"CFEngine Community %s Policy Server on %s \n", Version(), "%h");
}
cfengine-3.12.1/cf-serverd/strlist.c 0000644 0000000 0000000 00000051504 13377750461 017304 0 ustar 00root root 0000000 0000000 /*
Copyright 2018 Northern.tech AS
This file is part of CFEngine 3 - written and maintained by Northern.tech AS.
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; version 3.
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, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
To the extent this program is licensed as part of the Enterprise
versions of CFEngine, the applicable Commercial Open Source License
(COSL) may apply to this file if you as a licensee so wish it. See
included file COSL.txt.
*/
#include "strlist.h"
#include
#include
int memrcmp(const void *p1, const void *p2, size_t n)
{
const char *s1 = p1;
const char *s2 = p2;
while (n > 0)
{
if (*s1 != *s2)
{
return *s1 - *s2;
}
s1--;
s2--;
n--;
}
return 0;
}
/***************************** STRING ***************************************/
struct string *string_New(const char *s)
{
size_t s_len = strlen(s);
struct string *p = malloc(sizeof(*p) + s_len + 1);
if (p != NULL)
{
p->len = s_len;
/* p->size = s_len + 1; */
memcpy(p->str, s, s_len + 1);
}
return p;
}
/* Compare without ordering, returning only true or false. */
bool string_BoolCompare(const struct string *s1,
const struct string *s2)
{
int result = false;
if (s1->len == s2->len)
{
result = (memcmp(s1->str, s2->str, s1->len) == 0);
}
return result;
}
/* Compare and return -1, 0, 1 according to alphabetical order. */
int string_Compare(const struct string **sp1,
const struct string **sp2)
{
const struct string *s1 = *sp1;
const struct string *s2 = *sp2;
int result;
if (s1->len < s2->len)
{
if (s1->len == 0)
{
return -1;
}
else
{
result = memcmp(s1->str, s2->str, s1->len);
return result == 0 ? -1 : result;
}
}
else if (s1->len > s2->len)
{
if (s2->len == 0)
{
return 1;
}
else
{
result = memcmp(s1->str, s2->str, s2->len);
return result == 0 ? 1 : result;
}
}
else /* s1->len == s2->len */
{
if (s1->len == 0) /* both are zero length strings */
{
return 0;
}
else
{
return memcmp(s1->str, s2->str, s1->len);
}
}
}
/**
* Compare two strings starting from their end.
*/
int string_CompareFromEnd(const struct string **sp1,
const struct string **sp2)
{
const struct string *s1 = *sp1;
const struct string *s2 = *sp2;
int result;
/* Pointer to last char of s1 and s2. */
const char *last1 = &s1->str[s1->len - 1];
const char *last2 = &s2->str[s2->len - 1];
if (s1->len < s2->len)
{
result = memrcmp(last1, last2, s1->len);
return result == 0 ? -1 : result;
}
else if (s1->len > s2->len)
{
result = memrcmp(last1, last2, s2->len);
return result == 0 ? 1 : result;
}
else /* s1->len == s2->len */
{
return memrcmp(last1, last2, s1->len);
}
}
/**
* Compare two strings.
*
* @return the length of the substring that matches. To find out if the two
* strings match exactly you must also check if
* s1->len == s2->len == return_value.
*/
size_t string_MatchCount(const struct string *s1,
const struct string *s2)
{
size_t len = MIN(s1->len, s2->len);
size_t i = 0;
while (i < len && s1->str[i] == s2->str[i])
{
i++;
}
return i;
}
/**
* Compare two strings starting from their end.
*
* @return the length of the substring that matches. To find out if the two
* strings match exactly you must also check if
* s1->len == s2->len == return_value.
*/
size_t string_ReverseMatchCount(const struct string *s1,
const struct string *s2)
{
size_t len = MIN(s1->len, s2->len);
const char *last1 = &s1->str[s1->len - 1];
const char *last2 = &s2->str[s2->len - 1];
size_t i = 0;
while (i < len && *last1 == *last2)
{
i++;
}
return i;
}
/***************************** STRLIST **************************************/
size_t StrList_Len(const StrList *sl)
{
return (sl == NULL) ? 0 : sl->len;
}
char *StrList_At(const StrList *sl, size_t idx)
{
assert(sl != NULL);
assert(idx < sl->len);
return sl->list[idx]->str;
}
/**
* Insert s at the given index, reallocating if necessary.
*
* @return index of the newly inserted string. If -1 (i.e. MAXINT) is returned
* then something went horribly wrong.
*
* @note It is valid for sl to be NULL, which is equivalent to being empty.
*
*/
size_t StrList_Insert(StrList **sl, const char *s, size_t idx)
{
assert(s != NULL);
StrList *slp = *sl; /* for clarity only */
size_t new_alloc_len = 0; /* 0 means no reallocation is needed */
if ((slp == NULL && idx > 0) ||
(slp != NULL && idx > slp->len))
{
ProgrammingError("StrList_Insert: Out of bounds index %zu", idx);
}
if (slp == NULL)
{
slp = calloc(1, sizeof(*slp) + sizeof(*slp->list) * 1);
if (slp == NULL)
{
return (size_t) -1;
}
slp->alloc_len = 1;
*sl = slp;
}
else if (slp->alloc_len == 0)
{
assert (slp->len == 0);
new_alloc_len = 1;
}
else if (slp->len == slp->alloc_len) /* need more space */
{
new_alloc_len = slp->alloc_len * 2;
}
if (new_alloc_len > 0) /* reallocation is needed */
{
StrList *p =
realloc(slp, sizeof(*p) + sizeof (*p->list) * new_alloc_len);
if (p == NULL)
{
return (size_t) -1;
}
slp = p;
slp->alloc_len = new_alloc_len;
*sl = slp; /* Change the caller's variable */
}
struct string *str = string_New(s);
if (str == NULL)
{
/* Our list has grown but contents are the same, we can exit clean. */
return (size_t) -1;
}
assert(slp->len < slp->alloc_len);
memmove(&slp->list[idx + 1], &slp->list[idx], /* Make room */
(slp->len - idx) * sizeof(slp->list[idx]));
slp->list[idx] = str; /* Insert element */
slp->len++;
return idx;
}
/**
* Appends a string to strlist sl, reallocating if necessary. It returns NULL
* if reallocation failed, in which case the initial strlist is still valid.
* Else it returns a pointer to the newly appended string.
*
* @note It is valid for *sl to be NULL, which is equivalent to being empty.
*/
size_t StrList_Append(StrList **sl, const char *s)
{
assert(s != NULL);
size_t ret;
if (*sl == NULL)
{
ret = StrList_Insert(sl, s, 0);
}
else
{
ret = StrList_Insert(sl, s, (*sl)->len);
}
return ret;
}
/**
* Trim allocated memory to the minimum needed. Free the whole struct if
* deemed necessary. This function will never fail. In the unlikely event that
* realloc() fails to reduce the allocated amount, then we just keep the same
* memory and log an UnexpectedError.
*
* @param **sl in-out param, might become NULL if the struct was freed.
*/
void StrList_Finalise(StrList **sl)
{
StrList *slp = *sl; /* for clarity only */
if (slp == NULL)
{
return;
}
assert(slp->len <= slp->alloc_len);
if (slp->len == 0)
{
free(slp);
slp = NULL;
}
else if (slp->len < slp->alloc_len)
{
StrList *p =
realloc(slp, sizeof(*p) + sizeof (*p->list) * slp->len);
if (p == NULL)
{
UnexpectedError("realloc() returned error even though we asked to *reduce* allocated amount: %s",
GetErrorStr());
}
else
{
slp = p;
slp->alloc_len = slp->len;
}
}
*sl = slp;
}
/**
* Frees everything and sets the strlist back to NULL, i.e. empty.
*/
void StrList_Free(StrList **sl)
{
StrList *slp = *sl; /* for clarity */
if (slp == NULL)
{
return;
}
size_t i;
for (i = 0; i < slp->len; i++)
{
free(slp->list[i]);
}
free(slp);
*sl = NULL;
}
void StrList_Sort(StrList *sl, StringComparatorF comparator)
{
if (sl != NULL && sl->len > 0)
{
qsort(sl->list, sl->len, sizeof(sl->list[0]),
(int (*)(const void *, const void *)) comparator);
}
}
/**
* A different binary search, calls libc's bsearch which also means it's also
* limited by it: if element is not found only failure can be returned.
*
* @return index of match or (size_t) -1 if not found
*/
size_t StrList_bsearch(const StrList *sl,
const struct string *s,
StringComparatorF comparator)
{
if (sl != NULL && sl->len > 0)
{
struct string **ret =
bsearch(&s, sl->list, sl->len, sizeof(sl->list[0]),
(int (*)(const void *, const void *)) comparator);
struct string * const *base = &sl->list[0];
return (ret == NULL) ? (size_t) -1 : (ret - base);
}
else
{
return (size_t) -1;
}
}
/**
* Binary search for the string. Obviously the list must be sorted.
* If element not found return the position it should be inserted in.
*
* @param position returns either the index where it was found, or
* the index where it should be inserted in to keep it sorted.
*/
bool StrList_BinarySearchString(const StrList *slp,
const struct string *s,
size_t *position)
{
if (slp == NULL)
{
*position = 0;
return false;
}
size_t min = 0;
size_t max = slp->len;
/* -1 produces "Not found" if we don't iterate at all (empty list). */
int ret = -1;
size_t mid = 0;
while (min < max)
{
mid = min + (max - min) / 2;
const struct string *s_mid = slp->list[mid];
ret = string_Compare(&s, &s_mid);
if (ret == -1) /* s < list[mid] */
{
max = mid;
}
else if (ret == 1) /* s > list[mid] */
{
min = mid + 1;
}
else /* s == list[mid] */
{
break;
}
}
*position = mid;
return (ret == 0);
}
/**
* Same as previous, but accepts a raw char* pointer rather than a struct
* string.
*/
bool StrList_BinarySearch(const StrList *slp, const char *s,
size_t *position)
{
if (slp == NULL)
{
*position = 0;
return false;
}
size_t min = 0;
size_t max = slp->len;
/* -1 produces "Not found" if we don't iterate at all (empty list). */
int ret = -1;
size_t mid = 0;
while (min < max)
{
mid = min + (max - min) / 2;
ret = strcmp(s, slp->list[mid]->str);
if (ret < 0) /* s < list[mid] */
{
max = mid;
}
else if (ret > 0) /* s > list[mid] */
{
min = mid + 1;
/* insert *after* the comparison point, if we exit. */
mid++;
}
else /* s == list[mid] */
{
break;
}
}
*position = mid;
return (ret == 0);
}
/* Search a sorted strlist for string s, of s_len, in forward or backward
* direction (for the latter the strlist must be sorted with
* string_CompareFromEnd()). */
static
size_t StrList_BinarySearchExtended(const StrList *sl,
const char *s, size_t s_len,
bool direction_forward,
size_t *min, size_t *max)
{
size_t found = -1;
size_t priv_min = *min;
size_t priv_max = *max;
assert(s_len > 0);
assert(priv_min < priv_max);
assert(priv_max <= sl->len);
while (priv_min < priv_max)
{
size_t pos = (priv_max - priv_min) / 2 + priv_min;
const char *s2 = sl->list[pos]->str;
size_t s2_len = sl->list[pos]->len;
size_t min_len = MIN(s_len, s2_len);
int match;
if (direction_forward)
{
match = memcmp(s, sl->list[pos]->str, min_len);
}
else
{
match = memrcmp(s, &s2[s2_len - 1], min_len);
}
if (match == 0)
{
if (sl->list[pos]->len == s_len)
{
/* Exact match, we know the list has no duplicates so it's
* the first match. */
found = pos;
/* We might as well not search here later, when s_len is
* longer, because longer means it won't match this. */
*min = pos + 1;
break;
}
else
{
/* Prefix match, sl[pos] is superstring of s. That means
* that the exact match may be before. */
priv_max = pos;
/* However we keep this as a different case because we must
* not change *max, since that position might match a search
* later, with bigger s_len. */
}
}
else if (match < 0) /* s < sl[pos] */
{
priv_max = pos;
/* This position will never match, no matter how big s_len grows
* in later searches. Thus we change *max to avoid searching
* here. */
*max = priv_max;
}
else /* s > sl[pos] */
{
priv_min = pos + 1;
/* Same here, this position will never match even for longer s. */
*min = priv_min;
}
}
return found;
}
/**
* Find the longest string in #sl that is a prefix of #s (of length #s_len and
* not necessarily '\0'-terminated), delimited by #separator.
*
* @param #s_len can be the length of #s, since #s is not necessarily
* '\0'-terminated. Is #s_len is 0, then #s is assumed to be
* '\0'-terminated and length is computed with strlen().
* @note this means that #s can't be 0 bytes...
*
* @example if #sl is { "/a/", "/a/b/", "/a/c/" } and we are searching for
* #s="/a/d/f" with #separator='/' then this function returns 0, which
* is the index of "/a/".
*
* @example if #sl is { ".com", ".net", ".cfengine.com" } and we are searching
* for #s="cfengine.com" with #separator='.' and
* #direction_forward=false, then this function returns 0, which is
* the index of ".com".
* if we searched for #s="www.cfengine.com" then it would return 2,
* which is the index of "www.cfengine.com".
*/
size_t StrList_SearchLongestPrefix(const StrList *sl,
const char *s, size_t s_len,
char separator, bool direction_forward)
{
/* Remember, NULL strlist is equivalent to empty strlist. */
if (sl == NULL)
{
return (size_t) -1;
}
if (s_len == 0)
{
s_len = strlen(s);
}
size_t found = -1;
size_t old_found = -1;
size_t s_prefix_len = 0;
size_t min = 0;
size_t max = sl->len;
bool longer_match_possible = true;
/* Keep searching until we've searched the whole length, or until there is
* no reason to keep going. */
while (longer_match_possible && (s_prefix_len < s_len))
{
char *separator_at;
if (direction_forward)
{
/* Find next separator, skipping the previous one. */
separator_at = memchr(&s[s_prefix_len], separator,
s_len - s_prefix_len);
s_prefix_len = separator_at - &s[0] + 1;
}
else
{
/* In this case, SearchLongestPrefix should be SearchLongestSuffix.
* Find next separator from the end, skipping the previous one. */
separator_at = memrchr(s, separator,
s_len - s_prefix_len);
s_prefix_len = &s[s_len - 1] - separator_at + 1;
}
if (separator_at == NULL)
{
s_prefix_len = s_len; /* No separator found, use all string */
}
/* printf("StrList_SearchLongestPrefix %s: " */
/* "'%s' len:%zu prefix_len:%zu\n", */
/* direction_forward == true ? "forward" : "backward", */
/* s, s_len, s_prefix_len); */
assert(s_prefix_len <= s_len);
if (found != (size_t) -1)
{
/* Keep the smaller string match in case we don't match again. */
old_found = found;
}
found = StrList_BinarySearchExtended(sl,
direction_forward == true ? s : &s[s_len - 1],
s_prefix_len, direction_forward, &min, &max);
/* If not even a superstring was found then don't keep trying. */
longer_match_possible = (min < max);
}
found = (found == (size_t) -1) ? old_found : found;
/* printf("StrList_SearchLongestPrefix s:'%s' len:%zu found:'%s'\n", */
/* s, s_len, (found == -1) ? "NONE" : sl->list[found]->str); */
return found;
}
/**
* Search within the given strlist for any prefix of the string #s (or exact
* match). Not guaranteed it will return the shortest or longest prefix, just
* that it will return *fast* once a prefix or exact match is found.
*
* @param #direction_forward if set to false then search is done for suffix,
* not prefix.
* @return the index of the found string, (size_t) -1 if not found.
*/
size_t StrList_SearchForPrefix(const StrList *sl,
const char *s, size_t s_len,
bool direction_forward)
{
/* Remember, NULL strlist is equivalent to empty strlist. */
if (sl == NULL)
{
return (size_t) -1;
}
if (s_len == 0)
{
s_len = strlen(s);
}
size_t min = 0;
size_t max = sl->len;
size_t chr_idx = 0;
size_t prev_chr_idx = chr_idx;
while (min < max)
{
size_t mid = min + (max - min) / 2;
const char *s2 = sl->list[mid]->str;
size_t s2_len = sl->list[mid]->len;
size_t min_len = MIN(s_len, s2_len);
/* We didn't find a string in last iteration so now we are at a
* different position (mid) in strlist. Nobody guarantees that the
* first bytes still match, so we'll have to reset
* chr_idx. Nevertheless, we are sure that the first prev_chr_index
* bytes match, because they have already matched twice. */
size_t min_chr_idx = MIN(prev_chr_idx, chr_idx);
prev_chr_idx = chr_idx;
/* Count the matching characters. */
chr_idx = min_chr_idx;
if (direction_forward)
{
while (chr_idx < min_len &&
s[chr_idx] == s2[chr_idx])
{
chr_idx++;
}
}
else
{
while (chr_idx < min_len &&
s[s_len - 1 - chr_idx] == s2[s2_len - 1 - chr_idx])
{
chr_idx++;
}
}
if (chr_idx == s_len)
{
if (s_len == s2_len)
{
/* We found an exact match. */
return mid;
}
else
{
assert(s_len < s2_len);
/* We found a superstring of s (i.e. s is a prefix). Don't do
* anything, need to keep searching for smaller strings. */
}
}
else if (chr_idx == s2_len)
{
/* We found a prefix of s. */
return mid;
}
/* No match, need to keep searching... */
int compar = s[chr_idx] - sl->list[mid]->str[chr_idx];
if (compar < 0)
{
max = mid;
}
else
{
assert(compar > 0);
min = mid + 1;
}
}
return (size_t) -1;
}
cfengine-3.12.1/cf-serverd/server.c 0000644 0000000 0000000 00000037557 13377750461 017122 0 ustar 00root root 0000000 0000000 /*
Copyright 2018 Northern.tech AS
This file is part of CFEngine 3 - written and maintained by Northern.tech AS.
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; version 3.
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, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
To the extent this program is licensed as part of the Enterprise
versions of CFEngine, the applicable Commercial Open Source License
(COSL) may apply to this file if you as a licensee so wish it. See
included file COSL.txt.
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include /* SendTransaction,ReceiveTransaction */
#include /* TLSVerifyPeer */
#include
#include
#include
#include
#include
#include /* ServerTLS* */
#include
#include
#include
#include /* LoggingPrivSetContext */
#include
#include "server_classic.h" /* BusyWithClassicConnection */
/*
The only exported function in this file is the following, used only in
cf-serverd-functions.c.
void ServerEntryPoint(EvalContext *ctx, const char *ipaddr, ConnectionInfo *info);
TODO move this file to cf-serverd-functions.c or most probably server_common.c.
*/
//******************************************************************
// GLOBAL STATE
//******************************************************************
int ACTIVE_THREADS = 0; /* GLOBAL_X */
int CFD_MAXPROCESSES = 0; /* GLOBAL_P */
bool DENYBADCLOCKS = true; /* GLOBAL_P */
int MAXTRIES = 5; /* GLOBAL_P */
bool LOGENCRYPT = false; /* GLOBAL_P */
int COLLECT_INTERVAL = 0; /* GLOBAL_P */
int COLLECT_WINDOW = 30; /* GLOBAL_P */
bool SERVER_LISTEN = true; /* GLOBAL_P */
ServerAccess SERVER_ACCESS = { 0 }; /* GLOBAL_P */
char CFRUNCOMMAND[CF_MAXVARSIZE] = { 0 }; /* GLOBAL_P */
/******************************************************************/
static void SpawnConnection(EvalContext *ctx, const char *ipaddr, ConnectionInfo *info);
static void PurgeOldConnections(Item **list, time_t now);
static void *HandleConnection(void *conn);
static ServerConnectionState *NewConn(EvalContext *ctx, ConnectionInfo *info);
static void DeleteConn(ServerConnectionState *conn);
/****************************************************************************/
void ServerEntryPoint(EvalContext *ctx, const char *ipaddr, ConnectionInfo *info)
{
Log(LOG_LEVEL_VERBOSE,
"Obtained IP address of '%s' on socket %d from accept",
ipaddr, ConnectionInfoSocket(info));
/* TODO change nonattackerlist, attackerlist and especially connectionlist
* to binary searched lists, or remove them from the main thread! */
if (SERVER_ACCESS.nonattackerlist
&& !IsMatchItemIn(SERVER_ACCESS.nonattackerlist, ipaddr))
{
Log(LOG_LEVEL_ERR,
"Remote host '%s' not in allowconnects, denying connection",
ipaddr);
}
else if (IsMatchItemIn(SERVER_ACCESS.attackerlist, ipaddr))
{
Log(LOG_LEVEL_ERR,
"Remote host '%s' is in denyconnects, denying connection",
ipaddr);
}
else
{
time_t now = time(NULL);
if (now == -1)
{
now = 0;
}
PurgeOldConnections(&SERVER_ACCESS.connectionlist, now);
bool allow = IsMatchItemIn(SERVER_ACCESS.multiconnlist, ipaddr);
if (!allow && ThreadLock(cft_count))
{
/* At most one connection allowed for this host: */
allow = !IsItemIn(SERVER_ACCESS.connectionlist, ipaddr);
ThreadUnlock(cft_count);
if (!allow) /* Duplicate. */
{
Log(LOG_LEVEL_ERR,
"Remote host '%s' is not in allowallconnects, denying second simultaneous connection",
ipaddr);
}
}
if (allow)
{
char intime[PRINTSIZE(now)];
xsnprintf(intime, sizeof(intime), "%jd", (intmax_t) now);
if (ThreadLock(cft_count))
{
PrependItem(&SERVER_ACCESS.connectionlist, ipaddr, intime);
ThreadUnlock(cft_count);
SpawnConnection(ctx, ipaddr, info);
return; /* Success */
}
}
}
/* Tidy up on failure: */
if (info->is_call_collect)
{
CollectCallMarkProcessed();
}
cf_closesocket(ConnectionInfoSocket(info));
ConnectionInfoDestroy(&info);
}
/**********************************************************************/
static void PurgeOldConnections(Item **list, time_t now)
/* Some connections might not terminate properly. These should be cleaned
every couple of hours. That should be enough to prevent spamming. */
{
assert(list != NULL);
Log(LOG_LEVEL_DEBUG, "Purging Old Connections...");
if (ThreadLock(cft_count))
{
Item *next;
for (Item *ip = *list; ip != NULL; ip = next)
{
int then = 0;
sscanf(ip->classes, "%d", &then);
next = ip->next;
if (now > then + 2 * SECONDS_PER_HOUR)
{
Log(LOG_LEVEL_VERBOSE,
"IP address '%s' has been more than two hours in connection list, purging",
ip->name);
DeleteItem(list, ip);
}
}
ThreadUnlock(cft_count);
}
Log(LOG_LEVEL_DEBUG, "Done purging old connections");
}
/*********************************************************************/
static void SpawnConnection(EvalContext *ctx, const char *ipaddr, ConnectionInfo *info)
{
ServerConnectionState *conn = NULL;
int ret;
pthread_t tid;
pthread_attr_t threadattrs;
conn = NewConn(ctx, info); /* freed in HandleConnection */
int sd_accepted = ConnectionInfoSocket(info);
strlcpy(conn->ipaddr, ipaddr, CF_MAX_IP_LEN );
Log(LOG_LEVEL_VERBOSE,
"New connection (from %s, sd %d), spawning new thread...",
conn->ipaddr, sd_accepted);
ret = pthread_attr_init(&threadattrs);
if (ret != 0)
{
Log(LOG_LEVEL_ERR,
"SpawnConnection: Unable to initialize thread attributes (%s)",
GetErrorStr());
goto err;
}
ret = pthread_attr_setdetachstate(&threadattrs, PTHREAD_CREATE_DETACHED);
if (ret != 0)
{
Log(LOG_LEVEL_ERR,
"SpawnConnection: Unable to set thread to detached state (%s).",
GetErrorStr());
goto cleanup;
}
ret = pthread_attr_setstacksize(&threadattrs, 1024 * 1024);
if (ret != 0)
{
Log(LOG_LEVEL_WARNING,
"SpawnConnection: Unable to set thread stack size (%s).",
GetErrorStr());
/* Continue with default thread stack size. */
}
ret = pthread_create(&tid, &threadattrs, HandleConnection, conn);
if (ret != 0)
{
errno = ret;
Log(LOG_LEVEL_ERR,
"Unable to spawn worker thread. (pthread_create: %s)",
GetErrorStr());
goto cleanup;
}
cleanup:
pthread_attr_destroy(&threadattrs);
err:
if (ret != 0)
{
Log(LOG_LEVEL_WARNING, "Thread is being handled from main loop!");
HandleConnection(conn);
}
}
/*********************************************************************/
static void DisableSendDelays(int sockfd)
{
int yes = 1;
if (setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, (void *) &yes, sizeof(yes)) == -1)
{
Log(LOG_LEVEL_INFO, "Unable to disable Nagle algorithm, expect performance problems. (setsockopt(TCP_NODELAY): %s)", GetErrorStr());
}
}
/*********************************************************************/
/* TODO performance fix this to avoid the StringConcatenate() reallocations,
* if only we could set a static logging prefix. */
static char *LogHook(LoggingPrivContext *log_ctx,
ARG_UNUSED LogLevel level, const char *message)
{
const char *aligned_ipaddr = log_ctx->param;
return StringConcatenate(2, aligned_ipaddr, message);
}
/* TRIES: counts the number of consecutive connections dropped. */
static int TRIES = 0;
static void *HandleConnection(void *c)
{
ServerConnectionState *conn = c;
int ret;
/* Set logging prefix to be the IP address for all of thread's lifetime. */
/* These stack-allocated variables should be valid for all the lifetime of
* the thread. */
char aligned_ipaddr[CF_MAX_IP_LEN + 2];
LoggingPrivContext log_ctx = {
.log_hook = LogHook,
.param = aligned_ipaddr
};
strlcpy(aligned_ipaddr, conn->ipaddr, sizeof(aligned_ipaddr));
strlcat(aligned_ipaddr, "> ", sizeof(aligned_ipaddr));
/* Pad with enough spaces for IPv4 addresses to be aligned. Max chars are
* 15 for the address plus two for "> " == 17. */
size_t len;
for (len = strlen(aligned_ipaddr); len < 17; len++)
{
aligned_ipaddr[len] = ' ';
}
aligned_ipaddr[len] = '\0';
LoggingPrivSetContext(&log_ctx);
Log(LOG_LEVEL_INFO, "Accepting connection");
/* We test if number of active threads is greater than max, if so we deny
connection, if it happened too many times within a short timeframe then we
kill ourself.TODO this test should be done *before* spawning the thread. */
ret = ThreadLock(cft_server_children);
if (!ret)
{
Log(LOG_LEVEL_ERR, "Unable to thread-lock, closing connection!");
goto conndone;
}
else if (ACTIVE_THREADS > CFD_MAXPROCESSES)
{
if (TRIES > MAXTRIES)
{
/* This happens when no thread was freed while we had to drop 5
* (or maxconnections/3) consecutive connections, because none of
* the existing threads finished. */
Log(LOG_LEVEL_CRIT,
"Server seems to be paralyzed. DOS attack? "
"Committing apoptosis...");
ThreadUnlock(cft_server_children);
FatalError(conn->ctx, "Terminating");
}
TRIES++;
Log(LOG_LEVEL_ERR,
"Too many threads (%d > %d), dropping connection! "
"Increase server maxconnections?",
ACTIVE_THREADS, CFD_MAXPROCESSES);
ThreadUnlock(cft_server_children);
goto conndone;
}
ACTIVE_THREADS++;
TRIES = 0;
ThreadUnlock(cft_server_children);
DisableSendDelays(ConnectionInfoSocket(conn->conn_info));
/* 20 times the connect() timeout should be enough to avoid MD5
* computation timeouts on big files on old slow Solaris 8 machines. */
SetReceiveTimeout(ConnectionInfoSocket(conn->conn_info),
CONNTIMEOUT * 20 * 1000);
if (conn->conn_info->status != CONNECTIONINFO_STATUS_ESTABLISHED)
{
/* Decide the protocol used. */
bool success = ServerTLSPeek(conn->conn_info);
if (!success)
{
goto dethread;
}
}
ProtocolVersion protocol_version = ConnectionInfoProtocolVersion(conn->conn_info);
if (protocol_version == CF_PROTOCOL_LATEST)
{
bool established = ServerTLSSessionEstablish(conn, NULL);
if (!established)
{
goto dethread;
}
}
else if (protocol_version < CF_PROTOCOL_LATEST &&
protocol_version > CF_PROTOCOL_UNDEFINED)
{
/* This connection is legacy protocol.
* We are not allowing it by default. */
if (!IsMatchItemIn(SERVER_ACCESS.allowlegacyconnects, conn->ipaddr))
{
Log(LOG_LEVEL_INFO,
"Connection is not using latest protocol, denying");
goto dethread;
}
}
else
{
UnexpectedError("HandleConnection: ProtocolVersion %d!",
ConnectionInfoProtocolVersion(conn->conn_info));
goto dethread;
}
/* ========================= MAIN LOOPS ========================= */
if (protocol_version >= CF_PROTOCOL_TLS)
{
/* New protocol does DNS reverse look up of the connected
* IP address, to check hostname access_rules. */
if (NEED_REVERSE_LOOKUP)
{
ret = getnameinfo((const struct sockaddr *) &conn->conn_info->ss,
conn->conn_info->ss_len,
conn->revdns, sizeof(conn->revdns),
NULL, 0, NI_NAMEREQD);
if (ret != 0)
{
Log(LOG_LEVEL_INFO,
"Reverse lookup failed (getnameinfo: %s)!",
gai_strerror(ret));
}
else
{
Log(LOG_LEVEL_INFO,
"Hostname (reverse looked up): %s",
conn->revdns);
}
}
while (BusyWithNewProtocol(conn->ctx, conn))
{
}
}
else if (protocol_version == CF_PROTOCOL_CLASSIC)
{
while (BusyWithClassicConnection(conn->ctx, conn))
{
}
}
else
{
assert(!"Bogus protocol version - but we checked that already !");
}
/* ============================================================ */
Log(LOG_LEVEL_INFO, "Closing connection, terminating thread");
dethread:
ThreadLock(cft_server_children);
ACTIVE_THREADS--;
ThreadUnlock(cft_server_children);
conndone:
if (conn->conn_info->is_call_collect)
{
CollectCallMarkProcessed();
}
DeleteConn(conn);
return NULL;
}
/***************************************************************/
/* Toolkit/Class: conn */
/***************************************************************/
static ServerConnectionState *NewConn(EvalContext *ctx, ConnectionInfo *info)
{
#if 1
/* TODO: why do we do this ? We fail if getsockname() fails, but
* don't use the information it returned. Was the intent to use
* it to fill in conn->ipaddr ? */
struct sockaddr_storage addr;
socklen_t size = sizeof(addr);
if (getsockname(ConnectionInfoSocket(info), (struct sockaddr *)&addr, &size) == -1)
{
Log(LOG_LEVEL_ERR,
"Could not obtain socket address. (getsockname: '%s')",
GetErrorStr());
return NULL;
}
#endif
ServerConnectionState *conn = xcalloc(1, sizeof(*conn));
conn->ctx = ctx;
conn->conn_info = info;
conn->encryption_type = 'c';
/* Only public files (chmod o+r) accessible to non-root */
conn->uid = CF_UNKNOWN_OWNER; /* Careful, 0 is root! */
/* conn->maproot is false: only public files (chmod o+r) are accessible */
Log(LOG_LEVEL_DEBUG,
"New connection (socket %d).",
ConnectionInfoSocket(info));
return conn;
}
/**
* @note This function is thread-safe. Do NOT wrap it with mutex!
*/
static void DeleteConn(ServerConnectionState *conn)
{
int sd = ConnectionInfoSocket(conn->conn_info);
if (sd != SOCKET_INVALID)
{
cf_closesocket(sd);
}
ConnectionInfoDestroy(&conn->conn_info);
if (conn->ipaddr[0] != '\0' &&
ThreadLock(cft_count))
{
DeleteItemMatching(&SERVER_ACCESS.connectionlist, conn->ipaddr);
ThreadUnlock(cft_count);
}
*conn = (ServerConnectionState) {0};
free(conn->session_key);
free(conn);
}
cfengine-3.12.1/cf-serverd/server_transform.c 0000644 0000000 0000000 00000142441 13377750461 021202 0 ustar 00root root 0000000 0000000 /*
Copyright 2018 Northern.tech AS
This file is part of CFEngine 3 - written and maintained by Northern.tech AS.
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; version 3.
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, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
To the extent this program is licensed as part of the Enterprise
versions of CFEngine, the applicable Commercial Open Source License
(COSL) may apply to this file if you as a licensee so wish it. See
included file COSL.txt.
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include /* HashControls */
#include /* IsDirReal */
#include /* IsRegex */
#include
#include
#include
#include "server_common.h" /* PreprocessRequestPath */
#include "server_access.h"
#include "strlist.h"
#include
static PromiseResult KeepServerPromise(EvalContext *ctx, const Promise *pp, void *param);
static void InstallServerAuthPath(const char *path, Auth **list, Auth **listtail);
static void KeepServerRolePromise(EvalContext *ctx, const Promise *pp);
static void KeepPromiseBundles(EvalContext *ctx, const Policy *policy);
static void KeepControlPromises(EvalContext *ctx, const Policy *policy, GenericAgentConfig *config);
static void KeepBundlesAccessPromise(EvalContext *ctx, const Promise *pp);
static Auth *GetAuthPath(const char *path, Auth *list);
extern int COLLECT_INTERVAL;
extern int COLLECT_WINDOW;
extern bool SERVER_LISTEN;
/*******************************************************************/
/* GLOBAL VARIABLES */
/*******************************************************************/
extern int CFD_MAXPROCESSES;
extern int NO_FORK;
extern bool DENYBADCLOCKS;
extern int MAXTRIES;
extern bool LOGENCRYPT;
/*******************************************************************/
static void KeepFileAccessPromise(const EvalContext *ctx, const Promise *pp);
static void KeepLiteralAccessPromise(EvalContext *ctx, const Promise *pp, const char *type);
static void KeepQueryAccessPromise(EvalContext *ctx, const Promise *pp);
/*******************************************************************/
/* Level */
/*******************************************************************/
void Summarize()
{
Auth *ptr;
Item *ip, *ipr;
Log(LOG_LEVEL_VERBOSE, " === BEGIN summary of access promises === ");
Log(LOG_LEVEL_VERBOSE,
"Host IPs allowed connection access (allowconnects):");
for (ip = SERVER_ACCESS.nonattackerlist; ip != NULL; ip = ip->next)
{
Log(LOG_LEVEL_VERBOSE, "\tIP: %s", ip->name);
}
Log(LOG_LEVEL_VERBOSE,
"Host IPs denied connection access (denyconnects):");
for (ip = SERVER_ACCESS.attackerlist; ip != NULL; ip = ip->next)
{
Log(LOG_LEVEL_VERBOSE, "\tIP: %s", ip->name);
}
Log(LOG_LEVEL_VERBOSE,
"Host IPs allowed multiple connection access (allowallconnects):");
for (ip = SERVER_ACCESS.multiconnlist; ip != NULL; ip = ip->next)
{
Log(LOG_LEVEL_VERBOSE, "\tIP: %s", ip->name);
}
Log(LOG_LEVEL_VERBOSE,
"Host IPs whose keys we shall establish trust to (trustkeysfrom):");
for (ip = SERVER_ACCESS.trustkeylist; ip != NULL; ip = ip->next)
{
Log(LOG_LEVEL_VERBOSE, "\tIP: %s", ip->name);
}
Log(LOG_LEVEL_VERBOSE,
"Host IPs allowed legacy connections (allowlegacyconnects):");
for (ip = SERVER_ACCESS.allowlegacyconnects; ip != NULL; ip = ip->next)
{
Log(LOG_LEVEL_VERBOSE, "\tIP: %s", ip->name);
}
Log(LOG_LEVEL_VERBOSE,
"Users from whom we accept cf-runagent connections (allowusers):");
for (ip = SERVER_ACCESS.allowuserlist; ip != NULL; ip = ip->next)
{
Log(LOG_LEVEL_VERBOSE, "\tUSER: %s", ip->name);
}
Log(LOG_LEVEL_VERBOSE, "Access control lists:");
acl_Summarise(paths_acl, "Path");
acl_Summarise(classes_acl, "Class");
acl_Summarise(vars_acl, "Variable");
acl_Summarise(literals_acl, "Literal");
acl_Summarise(query_acl, "Query");
acl_Summarise(roles_acl, "Role");
acl_Summarise(bundles_acl, "Bundle");
Log(LOG_LEVEL_VERBOSE,
"Access control lists for the classic network protocol:");
for (ptr = SERVER_ACCESS.admit; ptr != NULL; ptr = ptr->next)
{
/* Don't report empty entries. */
if (ptr->maproot != NULL || ptr->accesslist != NULL)
{
Log(LOG_LEVEL_VERBOSE, "\tPath: %s", ptr->path);
}
for (ipr = ptr->maproot; ipr != NULL; ipr = ipr->next)
{
Log(LOG_LEVEL_VERBOSE, "\t\tmaproot user: %s,", ipr->name);
}
for (ip = ptr->accesslist; ip != NULL; ip = ip->next)
{
Log(LOG_LEVEL_VERBOSE, "\t\tadmit: %s", ip->name);
}
}
for (ptr = SERVER_ACCESS.deny; ptr != NULL; ptr = ptr->next)
{
/* Don't report empty entries. */
if (ptr->accesslist != NULL)
{
Log(LOG_LEVEL_VERBOSE, "\tPath: %s", ptr->path);
}
for (ip = ptr->accesslist; ip != NULL; ip = ip->next)
{
Log(LOG_LEVEL_VERBOSE, "\t\tdeny: %s", ip->name);
}
}
for (ptr = SERVER_ACCESS.varadmit; ptr != NULL; ptr = ptr->next)
{
Log(LOG_LEVEL_VERBOSE, "Object: %s", ptr->path);
for (ipr = ptr->maproot; ipr != NULL; ipr = ipr->next)
{
Log(LOG_LEVEL_VERBOSE, "%s,", ipr->name);
}
for (ip = ptr->accesslist; ip != NULL; ip = ip->next)
{
Log(LOG_LEVEL_VERBOSE, "Admit '%s' root=", ip->name);
}
}
for (ptr = SERVER_ACCESS.vardeny; ptr != NULL; ptr = ptr->next)
{
Log(LOG_LEVEL_VERBOSE, "Object %s", ptr->path);
for (ip = ptr->accesslist; ip != NULL; ip = ip->next)
{
Log(LOG_LEVEL_VERBOSE, "Deny '%s'", ip->name);
}
}
Log(LOG_LEVEL_VERBOSE, " === END summary of access promises === ");
}
void KeepPromises(EvalContext *ctx, const Policy *policy, GenericAgentConfig *config)
{
if (paths_acl != NULL || classes_acl != NULL || vars_acl != NULL ||
literals_acl != NULL || query_acl != NULL || bundles_acl != NULL ||
roles_acl != NULL || SERVER_ACCESS.path_shortcuts != NULL)
{
UnexpectedError("ACLs are not NULL - we are probably leaking memory!");
}
paths_acl = calloc(1, sizeof(*paths_acl));
classes_acl = calloc(1, sizeof(*classes_acl));
vars_acl = calloc(1, sizeof(*vars_acl));
literals_acl = calloc(1, sizeof(*literals_acl));
query_acl = calloc(1, sizeof(*query_acl));
bundles_acl = calloc(1, sizeof(*bundles_acl));
roles_acl = calloc(1, sizeof(*roles_acl));
SERVER_ACCESS.path_shortcuts = StringMapNew();
if (paths_acl == NULL || classes_acl == NULL || vars_acl == NULL ||
literals_acl == NULL || query_acl == NULL || bundles_acl == NULL ||
roles_acl == NULL || SERVER_ACCESS.path_shortcuts == NULL)
{
Log(LOG_LEVEL_CRIT, "calloc: %s", GetErrorStr());
DoCleanupAndExit(255);
}
KeepControlPromises(ctx, policy, config);
KeepPromiseBundles(ctx, policy);
}
/*******************************************************************/
static bool SetMaxOpenFiles(int n)
#ifdef HAVE_SYS_RESOURCE_H
{
const struct rlimit lim = {
.rlim_cur = n,
.rlim_max = n,
};
int ret = setrlimit(RLIMIT_NOFILE, &lim);
if (ret == -1)
{
Log(LOG_LEVEL_INFO, "Failed setting max open files limit"
" (setrlimit(NOFILE, %d): %s)", n, GetErrorStr());
Log(LOG_LEVEL_INFO,
"Please ensure that 'nofile' ulimit is at least 2x maxconnections");
return false;
}
else
{
Log(LOG_LEVEL_VERBOSE, "Setting max open files rlimit to %d", n);
return true;
}
}
#else /* MinGW */
{
Log(LOG_LEVEL_VERBOSE,
"Platform does not support setrlimit(NOFILE), max open files not set");
return false;
}
#endif /* HAVE_SYS_RESOURCE_H */
static void KeepControlPromises(EvalContext *ctx, const Policy *policy, GenericAgentConfig *config)
{
CFD_MAXPROCESSES = 30;
MAXTRIES = 5;
DENYBADCLOCKS = true;
CFRUNCOMMAND[0] = '\0';
SetChecksumUpdatesDefault(ctx, true);
/* Keep promised agent behaviour - control bodies */
Banner("Server control promises..");
PolicyResolve(ctx, policy, config);
/* Now expand */
Seq *constraints = ControlBodyConstraints(policy, AGENT_TYPE_SERVER);
#define IsControlBody(e) (strcmp(cp->lval, CFS_CONTROLBODY[e].lval) == 0)
if (constraints)
{
for (size_t i = 0; i < SeqLength(constraints); i++)
{
Constraint *cp = SeqAt(constraints, i);
if (!IsDefinedClass(ctx, cp->classes))
{
continue;
}
VarRef *ref = VarRefParseFromScope(cp->lval, "control_server");
const void *value = EvalContextVariableGet(ctx, ref, NULL);
VarRefDestroy(ref);
if (IsControlBody(SERVER_CONTROL_SERVER_FACILITY))
{
SetFacility(value);
}
else if (IsControlBody(SERVER_CONTROL_DENY_BAD_CLOCKS))
{
DENYBADCLOCKS = BooleanFromString(value);
Log(LOG_LEVEL_VERBOSE,
"Setting denybadclocks to '%s'",
DENYBADCLOCKS ? "true" : "false");
}
else if (IsControlBody(SERVER_CONTROL_LOG_ENCRYPTED_TRANSFERS))
{
LOGENCRYPT = BooleanFromString(value);
Log(LOG_LEVEL_VERBOSE,
"Setting logencrypt to '%s'",
LOGENCRYPT ? "true" : "false");
}
else if (IsControlBody(SERVER_CONTROL_LOG_ALL_CONNECTIONS))
{
SERVER_ACCESS.logconns = BooleanFromString(value);
Log(LOG_LEVEL_VERBOSE, "Setting logconns to %d", SERVER_ACCESS.logconns);
}
else if (IsControlBody(SERVER_CONTROL_MAX_CONNECTIONS))
{
CFD_MAXPROCESSES = (int) IntFromString(value);
/* Ease apoptosis limits. */
MAXTRIES = CFD_MAXPROCESSES / 3;
/* The handling of max_readers in LMDB is not ideal, but
* here is how it is right now: We know that both cf-serverd and
* cf-hub will access the lastseen database. Worst case every
* single thread and process will do it at the same time, and
* this has in fact been observed. So we add the maximum of
* those two values together to provide a safe ceiling. In
* addition, cf-agent can access the database occasionally as
* well, so add a few extra for that too. */
Log(LOG_LEVEL_VERBOSE,
"Setting maxconnections to %d", CFD_MAXPROCESSES);
DBSetMaximumConcurrentTransactions(CFD_MAXPROCESSES
+ EnterpriseGetMaxCfHubProcesses() + 10);
/* Set RLIMIT_NOFILE to be enough for all threads. */
SetMaxOpenFiles(CFD_MAXPROCESSES * 2 + 10);
}
else if (IsControlBody(SERVER_CONTROL_CALL_COLLECT_INTERVAL))
{
COLLECT_INTERVAL = (int) 60 * IntFromString(value);
Log(LOG_LEVEL_VERBOSE,
"Setting call_collect_interval to %d (seconds)",
COLLECT_INTERVAL);
}
else if (IsControlBody(SERVER_CONTROL_LISTEN))
{
SERVER_LISTEN = BooleanFromString(value);
Log(LOG_LEVEL_VERBOSE,
"Setting server listen to '%s' ",
SERVER_LISTEN ? "true" : "false");
}
else if (IsControlBody(SERVER_CONTROL_CALL_COLLECT_WINDOW))
{
COLLECT_WINDOW = (int) IntFromString(value);
Log(LOG_LEVEL_VERBOSE,
"Setting collect_window to %d (seconds)",
COLLECT_INTERVAL);
}
else if (IsControlBody(SERVER_CONTROL_CFRUNCOMMAND))
{
if (strlen(value) >= sizeof(CFRUNCOMMAND))
{
Log(LOG_LEVEL_ERR,
"cfruncommand too long (>%zu), leaving empty",
sizeof(CFRUNCOMMAND));
}
else
{
memcpy(CFRUNCOMMAND, value, strlen(value) + 1);
Log(LOG_LEVEL_VERBOSE, "Setting cfruncommand to: %s",
CFRUNCOMMAND);
}
}
else if (IsControlBody(SERVER_CONTROL_ALLOW_CONNECTS))
{
Log(LOG_LEVEL_VERBOSE, "Setting allowing connections from ...");
for (const Rlist *rp = value; rp != NULL; rp = rp->next)
{
if (!IsItemIn(SERVER_ACCESS.nonattackerlist, RlistScalarValue(rp)))
{
PrependItem(&SERVER_ACCESS.nonattackerlist, RlistScalarValue(rp), cp->classes);
}
}
}
else if (IsControlBody(SERVER_CONTROL_DENY_CONNECTS))
{
Log(LOG_LEVEL_VERBOSE, "Setting denying connections from ...");
for (const Rlist *rp = value; rp != NULL; rp = rp->next)
{
if (!IsItemIn(SERVER_ACCESS.attackerlist, RlistScalarValue(rp)))
{
PrependItem(&SERVER_ACCESS.attackerlist, RlistScalarValue(rp), cp->classes);
}
}
}
else if (IsControlBody(SERVER_CONTROL_SKIP_VERIFY))
{
/* Skip. */
}
else if (IsControlBody(SERVER_CONTROL_ALLOW_ALL_CONNECTS))
{
Log(LOG_LEVEL_VERBOSE, "Setting allowing multiple connections from ...");
for (const Rlist *rp = value; rp != NULL; rp = rp->next)
{
if (!IsItemIn(SERVER_ACCESS.multiconnlist, RlistScalarValue(rp)))
{
PrependItem(&SERVER_ACCESS.multiconnlist, RlistScalarValue(rp), cp->classes);
}
}
}
else if (IsControlBody(SERVER_CONTROL_ALLOW_USERS))
{
Log(LOG_LEVEL_VERBOSE, "SET Allowing users ...");
for (const Rlist *rp = value; rp != NULL; rp = rp->next)
{
if (!IsItemIn(SERVER_ACCESS.allowuserlist, RlistScalarValue(rp)))
{
PrependItem(&SERVER_ACCESS.allowuserlist, RlistScalarValue(rp), cp->classes);
}
}
}
else if (IsControlBody(SERVER_CONTROL_TRUST_KEYS_FROM))
{
Log(LOG_LEVEL_VERBOSE, "Setting 'trustkeysfrom' ...");
for (const Rlist *rp = value; rp != NULL; rp = rp->next)
{
if (!IsItemIn(SERVER_ACCESS.trustkeylist, RlistScalarValue(rp)))
{
PrependItem(&SERVER_ACCESS.trustkeylist, RlistScalarValue(rp), cp->classes);
}
}
}
else if (IsControlBody(SERVER_CONTROL_ALLOWLEGACYCONNECTS))
{
Log(LOG_LEVEL_VERBOSE, "Setting 'allowlegacyconnects' ...");
for (const Rlist *rp = value; rp != NULL; rp = rp->next)
{
if (!IsItemIn(SERVER_ACCESS.allowlegacyconnects, RlistScalarValue(rp)))
{
PrependItem(&SERVER_ACCESS.allowlegacyconnects, RlistScalarValue(rp), cp->classes);
}
}
}
else if (IsControlBody(SERVER_CONTROL_PORT_NUMBER))
{
bool ret = SetCfenginePort(value);
assert(ret);
}
else if (IsControlBody(SERVER_CONTROL_BIND_TO_INTERFACE))
{
SetBindInterface(value);
}
else if (IsControlBody(SERVER_CONTROL_ALLOWCIPHERS))
{
assert(SERVER_ACCESS.allowciphers == NULL); /* no leak */
SERVER_ACCESS.allowciphers = xstrdup(value);
Log(LOG_LEVEL_VERBOSE, "Setting allowciphers to: %s",
SERVER_ACCESS.allowciphers);
}
else if (IsControlBody(SERVER_CONTROL_ALLOWTLSVERSION))
{
assert(SERVER_ACCESS.allowtlsversion == NULL); /* no leak */
SERVER_ACCESS.allowtlsversion = xstrdup(value);
Log(LOG_LEVEL_VERBOSE, "Setting allowtlsversion to: %s",
SERVER_ACCESS.allowtlsversion);
}
}
#undef IsControlBody
}
const void *value = EvalContextVariableControlCommonGet(ctx, COMMON_CONTROL_SYSLOG_HOST);
if (value)
{
/* Don't resolve syslog_host now, better do it per log request. */
if (!SetSyslogHost(value))
{
Log(LOG_LEVEL_ERR, "Failed to set syslog_host, '%s' too long", (const char *)value);
}
else
{
Log(LOG_LEVEL_VERBOSE, "Setting syslog_host to '%s'", (const char *)value);
}
}
value = EvalContextVariableControlCommonGet(ctx, COMMON_CONTROL_SYSLOG_PORT);
if (value)
{
SetSyslogPort(IntFromString(value));
}
value = EvalContextVariableControlCommonGet(ctx, COMMON_CONTROL_FIPS_MODE);
if (value)
{
FIPS_MODE = BooleanFromString(value);
Log(LOG_LEVEL_VERBOSE, "Setting FIPS mode to to '%s'", FIPS_MODE ? "true" : "false");
}
value = EvalContextVariableControlCommonGet(ctx, COMMON_CONTROL_LASTSEEN_EXPIRE_AFTER);
if (value)
{
LASTSEENEXPIREAFTER = IntFromString(value) * 60;
}
value = EvalContextVariableControlCommonGet(ctx, COMMON_CONTROL_BWLIMIT);
if (value)
{
double bval;
if (DoubleFromString(value, &bval))
{
bwlimit_kbytes = (uint32_t) ( bval / 1000.0);
Log(LOG_LEVEL_VERBOSE, "Setting rate limit to %d kBytes/sec", bwlimit_kbytes);
}
}
}
/*********************************************************************/
/* Sequence in which server promise types should be evaluated */
static const char *const SERVER_TYPESEQUENCE[] =
{
"meta",
"vars",
"classes",
"roles",
"access",
NULL
};
static const char *const COMMON_TYPESEQUENCE[] =
{
"meta",
"vars",
"classes",
"reports",
NULL
};
/* Check if promise is NOT belonging to default server types
* (see SERVER_TYPESEQUENCE)*/
static bool IsPromiseTypeNotInTypeSequence(const char *promise_type,
const char * const *seq)
{
for (int type = 0; seq[type] != NULL; type++)
{
if (strcmp(promise_type, seq[type]) == 0)
{
return false;
}
}
return true;
}
static void EvaluateBundle(EvalContext *ctx, const Bundle *bp, const char * const *seq)
{
EvalContextStackPushBundleFrame(ctx, bp, NULL, false);
for (int type = 0; seq[type] != NULL; type++)
{
const PromiseType *sp = BundleGetPromiseType((Bundle *)bp, seq[type]);
/* Some promise types might not be there. */
if (!sp || SeqLength(sp->promises) == 0)
{
Log(LOG_LEVEL_DEBUG, "No promise type %s in bundle %s",
seq[type], bp->name);
continue;
}
EvalContextStackPushPromiseTypeFrame(ctx, sp);
for (size_t ppi = 0; ppi < SeqLength(sp->promises); ppi++)
{
Promise *pp = SeqAt(sp->promises, ppi);
ExpandPromise(ctx, pp, KeepServerPromise, NULL);
}
EvalContextStackPopFrame(ctx);
}
/* Check if we are having some other promise types which we
* should evaluate. THIS IS ONLY FOR BACKWARD COMPATIBILITY! */
for (size_t j = 0; j < SeqLength(bp->promise_types); j++)
{
PromiseType *sp = SeqAt(bp->promise_types, j);
/* Skipping evaluation of promise as this was evaluated in
* loop above. */
if (!IsPromiseTypeNotInTypeSequence(sp->name, seq))
{
Log(LOG_LEVEL_DEBUG, "Skipping subsequent evaluation of "
"promise type %s in bundle %s", sp->name, bp->name);
continue;
}
Log(LOG_LEVEL_WARNING, "Trying to evaluate unsupported/obsolete "
"promise type %s in %s bundle %s", sp->name, bp->type, bp->name);
EvalContextStackPushPromiseTypeFrame(ctx, sp);
for (size_t ppi = 0; ppi < SeqLength(sp->promises); ppi++)
{
Promise *pp = SeqAt(sp->promises, ppi);
ExpandPromise(ctx, pp, KeepServerPromise, NULL);
}
EvalContextStackPopFrame(ctx);
}
EvalContextStackPopFrame(ctx);
}
static void KeepPromiseBundles(EvalContext *ctx, const Policy *policy)
{
/* Dial up the generic promise expansion with a callback */
CleanReportBookFilterSet();
for (size_t i = 0; i < SeqLength(policy->bundles); i++)
{
Bundle *bp = SeqAt(policy->bundles, i);
bool server_bundle = strcmp(bp->type, CF_AGENTTYPES[AGENT_TYPE_SERVER]) == 0;
bool common_bundle = strcmp(bp->type, CF_AGENTTYPES[AGENT_TYPE_COMMON]) == 0;
if (server_bundle || common_bundle)
{
if (RlistLen(bp->args) > 0)
{
Log(LOG_LEVEL_WARNING,
"Cannot implicitly evaluate bundle '%s %s', as this bundle takes arguments.",
bp->type, bp->name);
continue;
}
}
if (server_bundle)
{
EvaluateBundle(ctx, bp, SERVER_TYPESEQUENCE);
}
else if (common_bundle)
{
EvaluateBundle(ctx, bp, COMMON_TYPESEQUENCE);
}
}
}
static PromiseResult KeepServerPromise(EvalContext *ctx, const Promise *pp, ARG_UNUSED void *param)
{
assert(!param);
PromiseBanner(ctx, pp);
if (strcmp(pp->parent_promise_type->name, "vars") == 0)
{
return VerifyVarPromise(ctx, pp, NULL);
}
if (strcmp(pp->parent_promise_type->name, "classes") == 0)
{
return VerifyClassPromise(ctx, pp, NULL);
}
/* Warn if promise locking was used with a promise that doesn't support it.
* That applies to both of the below promise types while 'vars' and
* 'classes' handle this on their own. */
int ifelapsed = PromiseGetConstraintAsInt(ctx, "ifelapsed", pp);
if (ifelapsed != CF_NOINT)
{
Log(LOG_LEVEL_WARNING,
"ifelapsed attribute specified in action body for %s promise '%s',"
" but %s promises do not support promise locking",
pp->parent_promise_type->name, pp->promiser,
pp->parent_promise_type->name);
}
int expireafter = PromiseGetConstraintAsInt(ctx, "expireafter", pp);
if (expireafter != CF_NOINT)
{
Log(LOG_LEVEL_WARNING,
"expireafter attribute specified in action body for %s promise '%s',"
" but %s promises do not support promise locking",
pp->parent_promise_type->name, pp->promiser,
pp->parent_promise_type->name);
}
if (strcmp(pp->parent_promise_type->name, "access") == 0)
{
const char *resource_type =
PromiseGetConstraintAsRval(pp, "resource_type", RVAL_TYPE_SCALAR);
/* Default resource_type in access_rules is "path" */
if (resource_type == NULL ||
strcmp(resource_type, "path") == 0)
{
KeepFileAccessPromise(ctx, pp);
return PROMISE_RESULT_NOOP;
}
else if (strcmp(resource_type, "literal") == 0)
{
KeepLiteralAccessPromise(ctx, pp, "literal");
return PROMISE_RESULT_NOOP;
}
else if (strcmp(resource_type, "variable") == 0)
{
KeepLiteralAccessPromise(ctx, pp, "variable");
return PROMISE_RESULT_NOOP;
}
else if (strcmp(resource_type, "query") == 0)
{
KeepQueryAccessPromise(ctx, pp);
KeepReportDataSelectAccessPromise(pp);
return PROMISE_RESULT_NOOP;
}
else if (strcmp(resource_type, "context") == 0)
{
KeepLiteralAccessPromise(ctx, pp, "context");
return PROMISE_RESULT_NOOP;
}
else if (strcmp(resource_type, "bundle") == 0)
{
KeepBundlesAccessPromise(ctx, pp);
return PROMISE_RESULT_NOOP;
}
}
else if (strcmp(pp->parent_promise_type->name, "roles") == 0)
{
KeepServerRolePromise(ctx, pp);
return PROMISE_RESULT_NOOP;
}
return PROMISE_RESULT_NOOP;
}
/*********************************************************************/
enum admit_type
{
ADMIT_TYPE_IP,
ADMIT_TYPE_HOSTNAME,
ADMIT_TYPE_KEY,
ADMIT_TYPE_OTHER
};
/* Check if the given string is an IP subnet, a hostname, a key, or none of
* the above. */
static enum admit_type AdmitType(const char *s)
{
if (strncmp(s, "SHA=", strlen("SHA=")) == 0 ||
strncmp(s, "MD5=", strlen("MD5=")) == 0)
{
return ADMIT_TYPE_KEY;
}
/* IPv4 or IPv6 subnet mask or regex. */
/* TODO change this to "0123456789abcdef.:/", no regex allowed. */
else if (s[strspn(s, "0123456789abcdef.:/[-]*()\\")] == '\0')
{
return ADMIT_TYPE_IP;
}
else
{
return ADMIT_TYPE_HOSTNAME;
}
}
/**
* Map old-style regex-or-hostname #host to new-style host-or-domain
* and append it to #sl.
*
* Old-style ACLs could include regexes to be matched against host
* names; but new-style ones only support sub-domain matching. If the
* old-style host regex looks like ".*\.sub\.domain\.tld" we can take
* it in as ".sub.domain.tld"; otherwise, we can only really map exact
* match hostnames. However, we know some old policy (including our
* own masterfiles) had cases of .*sub.domain.tld and it's possible
* that someone might include a new-style .sub.domain.tld by mistake
* in an (old-style) accept list; so cope with these cases, too.
*
* @param sl The string-list to which to add entries.
* @param host The name-or-regex to add to the ACL.
* @return An index at which an entry was added to the list (there may
* be another), or -1 if nothing added.
*/
static size_t StrList_AppendRegexHostname(StrList **sl, const char *host)
{
if (IsRegex(host))
{
if (host[strcspn(host, "({[|+?]})")] != '\0')
{
return -1; /* Not a regex we can sensibly massage; discard. */
}
bool skip[2] = { false, false }; /* { domain, host } passes below */
const char *name = host;
if (name[0] == '^') /* Was always implicit; but read as hint to intent. */
{
/* Default to skipping domain-form if anchored explicitly: */
skip[0] = true; /* Over-ridden below if followed by .* of course. */
name++;
}
if (StringStartsWith(name, ".*"))
{
skip[0] = false; /* Domain-form should match */
name += 2;
}
if (StringStartsWith(name, "\\."))
{
/* Skip host-form, as the regex definitely wants something
* before the given name. */
skip[1] = true;
name += 2;
}
if (strchr(name, '*') != NULL)
{
/* Can't handle a * later than the preamble. */
return (size_t) -1;
}
if (name > host ||
strchr(host, '\\') != NULL)
{
/* 2: leading '.' and final '\0' */
char copy[2 + strlen(name)], *c = copy;
c++[0] = '.'; /* For domain-form; and copy+1 gives host-form. */
/* Now copy the rest of the name, de-regex-ifying as we go: */
for (const char *p = name; p[0] != '\0'; p++)
{
if (p[0] == '\\')
{
p++;
if (p[0] != '.')
{
/* Regex includes a non-dot escape */
return (size_t) -1;
}
}
#if 0
else if (p[0] == '.')
{
/* In principle, this is a special character; but
* it may just be an unescaped dot, so let it be. */
}
#endif
c++[0] = p[0];
}
assert(c < copy + sizeof(copy));
c[0] = '\0';
/* Now, for host then domain, add entry if suitable */
int pass = 2;
size_t ret = -1;
while (pass > 0)
{
pass--;
if (!skip[pass]) /* pass 0 is domain, pass 1 is host */
{
ret = StrList_Append(sl, copy + pass);
}
}
return ret;
}
/* IsRegex() is true but we treat it just as a name! */
}
/* Just a simple host name. */
return StrList_Append(sl, host);
}
bool NEED_REVERSE_LOOKUP = false;
static void TurnOnReverseLookups()
{
if (!NEED_REVERSE_LOOKUP)
{
Log(LOG_LEVEL_INFO,
"Found hostname admit/deny in access_rules, "
"turning on reverse DNS lookups for every connection");
NEED_REVERSE_LOOKUP = true;
}
}
static size_t racl_SmartAppend(struct admitdeny_acl *ad, const char *entry)
{
size_t ret;
switch (AdmitType(entry))
{
case ADMIT_TYPE_IP:
/* TODO convert IP string to binary representation. */
ret = StrList_Append(&ad->ips, entry);
break;
case ADMIT_TYPE_KEY:
ret = StrList_Append(&ad->keys, entry);
break;
case ADMIT_TYPE_HOSTNAME:
ret = StrList_AppendRegexHostname(&ad->hostnames, entry);
/* If any hostname rule got added,
* turn on reverse DNS lookup in the new protocol. */
if (ret != (size_t) -1)
{
TurnOnReverseLookups();
}
break;
default:
Log(LOG_LEVEL_WARNING,
"Access rule 'admit: %s' is not IP, hostname or key, ignoring",
entry);
ret = (size_t) -1;
}
return ret;
}
/* Package hostname as regex, if needed.
*
* @param old The old Auth structure to which to add.
* @param host The new acl_hostnames entry to add to it.
*/
static void NewHostToOldACL(Auth *old, const char *host)
{
if (host[0] == '.') /* Domain - transform to regex: */
{
int extra = 2; /* For leading ".*" */
const char *dot = host;
do
{
do
{
dot++; /* Step over prior dot. */
} while (dot[0] == '.'); /* Treat many dots as one. */
extra++; /* For a backslash before the dot */
dot = strchr(dot, '.');
} while (dot);
char regex[strlen(host) + extra], *dst = regex;
dst++[0] = '.';
dst++[0] = '*';
dot = host;
do
{
/* Insert literal dot. */
assert(dot[0] == '.');
dst++[0] = '\\';
dst++[0] = '.';
do /* Step over prior dot(s), as before. */
{
dot++;
} while (dot[0] == '.');
/* Identify next fragment: */
const char *d = strchr(dot, '.');
size_t len = d ? d - dot : strlen(dot);
/* Copy fragment: */
memcpy(dst, dot, len);
dst += len;
/* Advance: */
dot = d;
} while (dot);
/* Terminate: */
assert(dst < regex + sizeof(regex));
dst[0] = '\0';
/* Add to list: */
PrependItem(&(old->accesslist), regex, NULL);
}
else
{
/* Simple host-name; just add it: */
PrependItem(&(old->accesslist), host, NULL);
}
}
/**
* Add access rules to the given ACL #acl according to the constraints in the
* particular access promise.
*
* For legacy reasons (non-TLS connections), build also the #ap (access Auth)
* and #dp (deny Auth), if they are not NULL.
*/
static void AccessPromise_AddAccessConstraints(const EvalContext *ctx,
const Promise *pp,
struct resource_acl *racl,
Auth *ap, Auth *dp)
{
for (size_t i = 0; i < SeqLength(pp->conlist); i++)
{
const Constraint *cp = SeqAt(pp->conlist, i);
size_t ret = -2;
if (!IsDefinedClass(ctx, cp->classes))
{
continue;
}
switch (cp->rval.type)
{
#define IsAccessBody(e) (strcmp(cp->lval, CF_REMACCESS_BODIES[e].lval) == 0)
case RVAL_TYPE_SCALAR:
if (ap != NULL &&
IsAccessBody(REMOTE_ACCESS_IFENCRYPTED))
{
ap->encrypt = BooleanFromString(cp->rval.item);
}
else if (IsAccessBody(REMOTE_ACCESS_SHORTCUT))
{
const char *shortcut = cp->rval.item;
if (strchr(shortcut, FILE_SEPARATOR) != NULL)
{
Log(LOG_LEVEL_ERR,
"slashes are forbidden in ACL shortcut: %s",
shortcut);
}
else if (StringMapHasKey(SERVER_ACCESS.path_shortcuts, shortcut))
{
Log(LOG_LEVEL_WARNING,
"Already existing shortcut for path '%s' was replaced",
pp->promiser);
}
else
{
StringMapInsert(SERVER_ACCESS.path_shortcuts,
xstrdup(shortcut), xstrdup(pp->promiser));
Log(LOG_LEVEL_DEBUG, "Added shortcut '%s' for path: %s",
shortcut, pp->promiser);
}
}
break;
case RVAL_TYPE_LIST:
for (const Rlist *rp = (const Rlist *) cp->rval.item;
rp != NULL; rp = rp->next)
{
/* TODO keys, ips, hostnames are valid such strings. */
if (IsAccessBody(REMOTE_ACCESS_ADMITIPS))
{
ret = StrList_Append(&racl->admit.ips, RlistScalarValue(rp));
if (ap != NULL)
{
PrependItem(&(ap->accesslist), RlistScalarValue(rp), NULL);
}
}
else if (IsAccessBody(REMOTE_ACCESS_DENYIPS))
{
ret = StrList_Append(&racl->deny.ips, RlistScalarValue(rp));
if (dp != NULL)
{
PrependItem(&(dp->accesslist), RlistScalarValue(rp), NULL);
}
}
else if (IsAccessBody(REMOTE_ACCESS_ADMITHOSTNAMES))
{
ret = StrList_Append(&racl->admit.hostnames, RlistScalarValue(rp));
/* If any hostname rule got added,
* turn on reverse DNS lookup in the new protocol. */
if (ret != (size_t) -1)
{
TurnOnReverseLookups();
}
if (ap != NULL)
{
NewHostToOldACL(ap, RlistScalarValue(rp));
}
}
else if (IsAccessBody(REMOTE_ACCESS_DENYHOSTNAMES))
{
ret = StrList_Append(&racl->deny.hostnames, RlistScalarValue(rp));
/* If any hostname rule got added,
* turn on reverse DNS lookup in the new protocol. */
if (ret != (size_t) -1)
{
TurnOnReverseLookups();
}
if (dp != NULL)
{
NewHostToOldACL(dp, RlistScalarValue(rp));
}
}
else if (IsAccessBody(REMOTE_ACCESS_ADMITKEYS))
{
ret = StrList_Append(&racl->admit.keys, RlistScalarValue(rp));
}
else if (IsAccessBody(REMOTE_ACCESS_DENYKEYS))
{
ret = StrList_Append(&racl->deny.keys, RlistScalarValue(rp));
}
/* Legacy stuff */
else if (IsAccessBody(REMOTE_ACCESS_ADMIT))
{
ret = racl_SmartAppend(&racl->admit, RlistScalarValue(rp));
if (ap != NULL)
{
PrependItem(&(ap->accesslist), RlistScalarValue(rp), NULL);
}
}
else if (IsAccessBody(REMOTE_ACCESS_DENY))
{
ret = racl_SmartAppend(&racl->deny, RlistScalarValue(rp));
if (dp != NULL)
{
PrependItem(&(dp->accesslist), RlistScalarValue(rp), NULL);
}
}
else if (ap != NULL && IsAccessBody(REMOTE_ACCESS_MAPROOT))
{
PrependItem(&(ap->maproot), RlistScalarValue(rp), NULL);
}
}
if (ret == (size_t) -1)
{
/* Should never happen, besides when allocation fails. */
Log(LOG_LEVEL_CRIT, "StrList_Append: %s", GetErrorStr());
DoCleanupAndExit(255);
}
break;
default:
UnexpectedError("Unknown constraint type!");
break;
#undef IsAccessBody
}
}
StrList_Finalise(&racl->admit.ips);
StrList_Sort(racl->admit.ips, string_Compare);
StrList_Finalise(&racl->admit.hostnames);
StrList_Sort(racl->admit.hostnames, string_CompareFromEnd);
StrList_Finalise(&racl->admit.keys);
StrList_Sort(racl->admit.keys, string_Compare);
StrList_Finalise(&racl->deny.ips);
StrList_Sort(racl->deny.ips, string_Compare);
StrList_Finalise(&racl->deny.hostnames);
StrList_Sort(racl->deny.hostnames, string_CompareFromEnd);
StrList_Finalise(&racl->deny.keys);
StrList_Sort(racl->deny.keys, string_Compare);
}
/* It is allowed to have duplicate handles (paths or class names or variables
* etc) in bundle server access_rules in policy files, but the lists here
* should have unique entries. This, we make sure here. */
static Auth *GetOrCreateAuth(const char *handle, Auth **authchain, Auth **authchain_tail)
{
Auth *a = GetAuthPath(handle, *authchain);
if (!a)
{
InstallServerAuthPath(handle, authchain, authchain_tail);
a = GetAuthPath(handle, *authchain);
}
return a;
}
static void KeepFileAccessPromise(const EvalContext *ctx, const Promise *pp)
{
char path[PATH_MAX];
size_t path_len = strlen(pp->promiser);
if (path_len > sizeof(path) - 1)
{
goto err_too_long;
}
memcpy(path, pp->promiser, path_len + 1);
/* Resolve symlinks and canonicalise access_rules path. */
size_t ret2 = PreprocessRequestPath(path, sizeof(path));
if (ret2 == (size_t) -1)
{
if (errno != ENOENT) /* something went wrong */
{
Log(LOG_LEVEL_ERR,
"Failed to canonicalize path '%s' in access_rules, ignoring!",
pp->promiser);
return;
}
else /* file does not exist, it doesn't matter */
{
Log(LOG_LEVEL_INFO,
"Path does not exist, it's added as-is in access rules: %s",
path);
Log(LOG_LEVEL_INFO,
"WARNING: this means that (not) having a trailing slash defines if it's (not) a directory!");
/* Legacy: convert trailing "/." to "/" */
if (path_len >= 2 &&
path[path_len - 1] == '.' &&
path[path_len - 2] == '/')
{
path[path_len - 1] = '\0';
path_len--;
}
}
}
else /* file exists, path canonicalised */
{
/* If it's a directory append trailing '/' */
path_len = ret2;
int is_dir = IsDirReal(path);
if (is_dir == 1 && path[path_len - 1] != FILE_SEPARATOR)
{
if (path_len + 2 > sizeof(path))
{
goto err_too_long;
}
PathAppendTrailingSlash(path, path_len);
path_len++;
}
}
size_t pos = acl_SortedInsert(&paths_acl, path);
if (pos == (size_t) -1)
{
/* Should never happen, besides when allocation fails. */
Log(LOG_LEVEL_CRIT, "acl_Insert: %s", GetErrorStr());
DoCleanupAndExit(255);
}
/* Legacy code */
if (path_len != 1)
{
DeleteSlash(path);
}
Auth *ap = GetOrCreateAuth(path, &SERVER_ACCESS.admit, &SERVER_ACCESS.admittail);
Auth *dp = GetOrCreateAuth(path, &SERVER_ACCESS.deny, &SERVER_ACCESS.denytail);
AccessPromise_AddAccessConstraints(ctx, pp, &paths_acl->acls[pos],
ap, dp);
return;
err_too_long:
Log(LOG_LEVEL_ERR,
"Path '%s' in access_rules is too long (%zu > %d), ignoring!",
pp->promiser, strlen(pp->promiser), PATH_MAX);
return;
}
/*********************************************************************/
void KeepLiteralAccessPromise(EvalContext *ctx, const Promise *pp, const char *type)
{
Auth *ap, *dp;
const char *handle = PromiseGetHandle(pp);
if (handle == NULL && strcmp(type, "literal") == 0)
{
Log(LOG_LEVEL_ERR, "Access to literal server data requires you to define a promise handle for reference");
return;
}
if (strcmp(type, "literal") == 0)
{
Log(LOG_LEVEL_VERBOSE,"Looking at literal access promise '%s', type '%s'", pp->promiser, type);
ap = GetOrCreateAuth(handle, &SERVER_ACCESS.varadmit, &SERVER_ACCESS.varadmittail);
dp = GetOrCreateAuth(handle, &SERVER_ACCESS.vardeny, &SERVER_ACCESS.vardenytail);
RegisterLiteralServerData(ctx, handle, pp);
ap->literal = true;
size_t pos = acl_SortedInsert(&literals_acl, handle);
if (pos == (size_t) -1)
{
/* Should never happen, besides when allocation fails. */
Log(LOG_LEVEL_CRIT, "acl_Insert: %s", GetErrorStr());
DoCleanupAndExit(255);
}
AccessPromise_AddAccessConstraints(ctx, pp, &literals_acl->acls[pos],
ap, dp);
}
else
{
Log(LOG_LEVEL_VERBOSE,"Looking at context/var access promise '%s', type '%s'", pp->promiser, type);
ap = GetOrCreateAuth(pp->promiser, &SERVER_ACCESS.varadmit, &SERVER_ACCESS.varadmittail);
dp = GetOrCreateAuth(pp->promiser, &SERVER_ACCESS.vardeny, &SERVER_ACCESS.vardenytail);
if (strcmp(type, "context") == 0)
{
ap->classpattern = true;
size_t pos = acl_SortedInsert(&classes_acl, pp->promiser);
if (pos == (size_t) -1)
{
/* Should never happen, besides when allocation fails. */
Log(LOG_LEVEL_CRIT, "acl_Insert: %s", GetErrorStr());
DoCleanupAndExit(255);
}
AccessPromise_AddAccessConstraints(ctx, pp, &classes_acl->acls[pos],
ap, dp);
}
else if (strcmp(type, "variable") == 0)
{
ap->variable = true;
size_t pos = acl_SortedInsert(&vars_acl, pp->promiser);
if (pos == (size_t) -1)
{
/* Should never happen, besides when allocation fails. */
Log(LOG_LEVEL_CRIT, "acl_Insert: %s", GetErrorStr());
DoCleanupAndExit(255);
}
AccessPromise_AddAccessConstraints(ctx, pp, &vars_acl->acls[pos],
ap, dp);
}
}
}
/*********************************************************************/
static void KeepQueryAccessPromise(EvalContext *ctx, const Promise *pp)
{
Auth *dp = GetOrCreateAuth(pp->promiser, &SERVER_ACCESS.vardeny, &SERVER_ACCESS.vardenytail),
*ap = GetOrCreateAuth(pp->promiser, &SERVER_ACCESS.varadmit, &SERVER_ACCESS.varadmittail);
RegisterLiteralServerData(ctx, pp->promiser, pp);
ap->literal = true;
size_t pos = acl_SortedInsert(&query_acl, pp->promiser);
if (pos == (size_t) -1)
{
/* Should never happen, besides when allocation fails. */
Log(LOG_LEVEL_CRIT, "acl_Insert: %s", GetErrorStr());
DoCleanupAndExit(255);
}
AccessPromise_AddAccessConstraints(ctx, pp, &query_acl->acls[pos],
ap, dp);
}
static void KeepBundlesAccessPromise(EvalContext *ctx, const Promise *pp)
{
size_t pos = acl_SortedInsert(&bundles_acl, pp->promiser);
if (pos == (size_t) -1)
{
/* Should never happen, besides when allocation fails. */
Log(LOG_LEVEL_CRIT, "acl_Insert: %s", GetErrorStr());
DoCleanupAndExit(255);
}
/* Last params are NULL because we don't have
* old-school Auth type ACLs here. */
AccessPromise_AddAccessConstraints(ctx, pp, &bundles_acl->acls[pos],
NULL, NULL);
}
/*********************************************************************/
/**
* The "roles" access promise is for remote class activation by means of
* cf-runagent -D:
*
* pp->promiser is a regex to match classes.
* pp->conlist is an slist of usernames.
*/
static void KeepServerRolePromise(EvalContext *ctx, const Promise *pp)
{
size_t pos = acl_SortedInsert(&roles_acl, pp->promiser);
if (pos == (size_t) -1)
{
/* Should never happen, besides when allocation fails. */
Log(LOG_LEVEL_CRIT, "acl_Insert: %s", GetErrorStr());
DoCleanupAndExit(255);
}
size_t i = SeqLength(pp->conlist);
while (i > 0)
{
i--;
Constraint *cp = SeqAt(pp->conlist, i);
char const * const authorizer =
CF_REMROLE_BODIES[REMOTE_ROLE_AUTHORIZE].lval;
if (strcmp(cp->lval, authorizer) == 0)
{
if (cp->rval.type != RVAL_TYPE_LIST)
{
Log(LOG_LEVEL_ERR,
"Right-hand side of authorize promise for '%s' should be a list",
pp->promiser);
}
else if (IsDefinedClass(ctx, cp->classes))
{
for (const Rlist *rp = cp->rval.item; rp != NULL; rp = rp->next)
{
/* The "roles" access promise currently only supports
* listing usernames to admit access to, nothing more. */
struct resource_acl *racl = &roles_acl->acls[pos];
size_t zret = StrList_Append(&racl->admit.usernames,
RlistScalarValue(rp));
if (zret == (size_t) -1)
{
/* Should never happen, besides when allocation fails. */
Log(LOG_LEVEL_CRIT, "StrList_Append: %s", GetErrorStr());
DoCleanupAndExit(255);
}
}
}
}
else if (strcmp(cp->lval, "comment") != 0 &&
strcmp(cp->lval, "handle") != 0 &&
/* Are there other known list constraints ? if not, skip this: */
cp->rval.type != RVAL_TYPE_LIST)
{
Log(LOG_LEVEL_WARNING,
"Unrecognised promise '%s' for %s",
cp->lval, pp->promiser);
}
}
}
static void InstallServerAuthPath(const char *path, Auth **list, Auth **listtail)
{
Auth **nextp = *listtail ? &((*listtail)->next) : list;
assert(*nextp == NULL);
*listtail = *nextp = xcalloc(1, sizeof(Auth));
(*nextp)->path = xstrdup(path);
#ifdef __MINGW32__
for (char *p = (*nextp)->path; *p != '\0'; p++)
{
*p = ToLower(*p);
}
#endif /* __MINGW32__ */
}
static Auth *GetAuthPath(const char *path, Auth *list)
{
size_t path_len = strlen(path);
char unslashed_path[path_len + 1];
memcpy(unslashed_path, path, path_len + 1);
#ifdef __MINGW32__
ToLowerStrInplace(unslashed_path);
#endif
if (path_len != 1)
{
DeleteSlash(unslashed_path);
}
for (Auth *ap = list; ap != NULL; ap = ap->next)
{
if (strcmp(ap->path, unslashed_path) == 0)
{
return ap;
}
}
return NULL;
}
cfengine-3.12.1/cf-serverd/cf-serverd-functions.c 0000644 0000000 0000000 00000061546 13377750461 021655 0 ustar 00root root 0000000 0000000 /*
Copyright 2018 Northern.tech AS
This file is part of CFEngine 3 - written and maintained by Northern.tech AS.
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; version 3.
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, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
To the extent this program is licensed as part of the Enterprise
versions of CFEngine, the applicable Commercial Open Source License
(COSL) may apply to this file if you as a licensee so wish it. See
included file COSL.txt.
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include /* ServerTLSInitialize */
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define WAIT_INCOMING_TIMEOUT 10
/* see man:listen(3) */
#define DEFAULT_LISTEN_QUEUE_SIZE 128
#define MAX_LISTEN_QUEUE_SIZE 2048
int NO_FORK = false; /* GLOBAL_A */
/*******************************************************************/
/* Command line option parsing */
/*******************************************************************/
static const char *const CF_SERVERD_SHORT_DESCRIPTION = "CFEngine file server daemon";
static const char *const CF_SERVERD_MANPAGE_LONG_DESCRIPTION =
"cf-serverd is a socket listening daemon providing two services: it acts as a file server for remote file copying "
"and it allows an authorized cf-runagent to start a cf-agent run. cf-agent typically connects to a "
"cf-serverd instance to request updated policy code, but may also request additional files for download. "
"cf-serverd employs role based access control (defined in policy code) to authorize requests.";
static const struct option OPTIONS[] =
{
{"help", no_argument, 0, 'h'},
{"log-level", required_argument, 0, 'g'},
{"debug", no_argument, 0, 'd'},
{"verbose", no_argument, 0, 'v'},
{"version", no_argument, 0, 'V'},
{"file", required_argument, 0, 'f'},
{"define", required_argument, 0, 'D'},
{"negate", required_argument, 0, 'N'},
{"no-lock", no_argument, 0, 'K'},
{"inform", no_argument, 0, 'I'},
{"diagnostic", no_argument, 0, 'x'},
{"no-fork", no_argument, 0, 'F'},
{"ld-library-path", required_argument, 0, 'L'},
{"generate-avahi-conf", no_argument, 0, 'A'},
{"color", optional_argument, 0, 'C'},
{"timestamp", no_argument, 0, 'l'},
{NULL, 0, 0, '\0'}
};
static const char *const HINTS[] =
{
"Print the help message",
"Specify how detailed logs should be. Possible values: 'error', 'warning', 'notice', 'info', 'verbose', 'debug'",
"Enable debugging output",
"Output verbose information about the behaviour of the agent",
"Output the version of the software",
"Specify an alternative input file than the default. This option is overridden by FILE if supplied as argument.",
"Define a list of comma separated classes to be defined at the start of execution",
"Define a list of comma separated classes to be undefined at the start of execution",
"Ignore locking constraints during execution (ifelapsed/expireafter) if \"too soon\" to run",
"Print basic information about changes made to the system, i.e. promises repaired",
"Activate internal diagnostics (developers only)",
"Run as a foreground processes (do not fork)",
"Set the internal value of LD_LIBRARY_PATH for child processes",
"Generates avahi configuration file to enable policy server to be discovered in the network",
"Enable colorized output. Possible values: 'always', 'auto', 'never'. If option is used, the default value is 'auto'",
"Log timestamps on each line of log output",
NULL
};
#ifdef HAVE_AVAHI_CLIENT_CLIENT_H
#ifdef HAVE_AVAHI_COMMON_ADDRESS_H
static int GenerateAvahiConfig(const char *path)
{
FILE *fout;
Writer *writer = NULL;
fout = safe_fopen(path, "w+");
if (fout == NULL)
{
Log(LOG_LEVEL_ERR, "Unable to open '%s'", path);
return -1;
}
writer = FileWriter(fout);
fprintf(fout, "\n");
fprintf(fout, "\n");
XmlComment(writer, "This file has been automatically generated by cf-serverd.");
XmlStartTag(writer, "service-group", 0);
FprintAvahiCfengineTag(fout);
XmlStartTag(writer, "service", 0);
XmlTag(writer, "type", "_cfenginehub._tcp",0);
DetermineCfenginePort();
XmlStartTag(writer, "port", 0);
WriterWriteF(writer, "%d", CFENGINE_PORT);
XmlEndTag(writer, "port");
XmlEndTag(writer, "service");
XmlEndTag(writer, "service-group");
fclose(fout);
return 0;
}
#define SUPPORT_AVAHI_CONFIG
#endif
#endif
GenericAgentConfig *CheckOpts(int argc, char **argv)
{
extern char *optarg;
int c;
GenericAgentConfig *config = GenericAgentConfigNewDefault(AGENT_TYPE_SERVER, GetTTYInteractive());
while ((c = getopt_long(argc, argv, "dvIKf:g:D:N:VSxLFMhAC::l",
OPTIONS, NULL))
!= -1)
{
switch (c)
{
case 'f':
GenericAgentConfigSetInputFile(config, GetInputDir(), optarg);
MINUSF = true;
break;
case 'd':
LogSetGlobalLevel(LOG_LEVEL_DEBUG);
NO_FORK = true;
break;
case 'K':
config->ignore_locks = true;
break;
case 'D':
{
StringSet *defined_classes = StringSetFromString(optarg, ',');
if (! config->heap_soft)
{
config->heap_soft = defined_classes;
}
else
{
StringSetJoin(config->heap_soft, defined_classes);
free(defined_classes);
}
}
break;
case 'N':
{
StringSet *negated_classes = StringSetFromString(optarg, ',');
if (! config->heap_negated)
{
config->heap_negated = negated_classes;
}
else
{
StringSetJoin(config->heap_negated, negated_classes);
free(negated_classes);
}
}
break;
case 'I':
LogSetGlobalLevel(LOG_LEVEL_INFO);
break;
case 'v':
LogSetGlobalLevel(LOG_LEVEL_VERBOSE);
NO_FORK = true;
break;
case 'g':
LogSetGlobalLevelArgOrExit(optarg);
break;
case 'F':
NO_FORK = true;
break;
case 'L':
{
static char ld_library_path[CF_BUFSIZE]; /* GLOBAL_A */
Log(LOG_LEVEL_VERBOSE, "Setting LD_LIBRARY_PATH to '%s'", optarg);
snprintf(ld_library_path, CF_BUFSIZE - 1, "LD_LIBRARY_PATH=%s", optarg);
putenv(ld_library_path);
break;
}
case 'V':
{
Writer *w = FileWriter(stdout);
GenericAgentWriteVersion(w);
FileWriterDetach(w);
}
DoCleanupAndExit(EXIT_SUCCESS);
case 'h':
{
Writer *w = FileWriter(stdout);
WriterWriteHelp(w, "cf-serverd", OPTIONS, HINTS, true, NULL);
FileWriterDetach(w);
}
DoCleanupAndExit(EXIT_SUCCESS);
case 'M':
{
Writer *out = FileWriter(stdout);
ManPageWrite(out, "cf-serverd", time(NULL),
CF_SERVERD_SHORT_DESCRIPTION,
CF_SERVERD_MANPAGE_LONG_DESCRIPTION,
OPTIONS, HINTS,
true);
FileWriterDetach(out);
DoCleanupAndExit(EXIT_SUCCESS);
}
case 'x':
Log(LOG_LEVEL_ERR, "Self-diagnostic functionality is retired.");
DoCleanupAndExit(EXIT_SUCCESS);
case 'A':
#ifdef SUPPORT_AVAHI_CONFIG
Log(LOG_LEVEL_NOTICE, "Generating Avahi configuration file.");
if (GenerateAvahiConfig("/etc/avahi/services/cfengine-hub.service") != 0)
{
DoCleanupAndExit(EXIT_FAILURE);
}
cf_popen("/etc/init.d/avahi-daemon restart", "r", true);
Log(LOG_LEVEL_NOTICE, "Avahi configuration file generated successfully.");
#else
Log(LOG_LEVEL_ERR, "Generating avahi configuration can only be done when avahi-daemon and libavahi are installed on the machine.");
#endif
DoCleanupAndExit(EXIT_SUCCESS);
case 'C':
if (!GenericAgentConfigParseColor(config, optarg))
{
DoCleanupAndExit(EXIT_FAILURE);
}
break;
case 'l':
LoggingEnableTimestamps(true);
break;
default:
{
Writer *w = FileWriter(stdout);
WriterWriteHelp(w, "cf-serverd", OPTIONS, HINTS, true, NULL);
FileWriterDetach(w);
}
DoCleanupAndExit(EXIT_FAILURE);
}
}
if (!GenericAgentConfigParseArguments(config, argc - optind, argv + optind))
{
Log(LOG_LEVEL_ERR, "Too many arguments");
DoCleanupAndExit(EXIT_FAILURE);
}
return config;
}
/*********************************************************************/
/* Policy Reloading */
/*********************************************************************/
static void DeleteAuthList(Auth **list, Auth **list_tail)
{
Auth *ap = *list;
while (ap != NULL)
{
Auth *ap_next = ap->next;
DeleteItemList(ap->accesslist);
DeleteItemList(ap->maproot);
free(ap->path);
free(ap);
/* Just make sure the tail was consistent. */
if (ap_next == NULL)
assert(ap == *list_tail);
ap = ap_next;
}
*list = NULL;
*list_tail = NULL;
}
/* Must not be called unless ACTIVE_THREADS is zero: */
static void ClearAuthAndACLs(void)
{
/* Must have no currently open connections to free the ACLs. */
assert(SERVER_ACCESS.connectionlist == NULL);
/* Bundle server access_rules legacy ACLs */
DeleteAuthList(&SERVER_ACCESS.admit, &SERVER_ACCESS.admittail);
DeleteAuthList(&SERVER_ACCESS.deny, &SERVER_ACCESS.denytail);
DeleteAuthList(&SERVER_ACCESS.varadmit, &SERVER_ACCESS.varadmittail);
DeleteAuthList(&SERVER_ACCESS.vardeny, &SERVER_ACCESS.vardenytail);
/* body server control ACLs */
DeleteItemList(SERVER_ACCESS.trustkeylist); SERVER_ACCESS.trustkeylist = NULL;
DeleteItemList(SERVER_ACCESS.attackerlist); SERVER_ACCESS.attackerlist = NULL;
DeleteItemList(SERVER_ACCESS.nonattackerlist); SERVER_ACCESS.nonattackerlist = NULL;
DeleteItemList(SERVER_ACCESS.allowuserlist); SERVER_ACCESS.allowuserlist = NULL;
DeleteItemList(SERVER_ACCESS.multiconnlist); SERVER_ACCESS.multiconnlist = NULL;
DeleteItemList(SERVER_ACCESS.allowuserlist); SERVER_ACCESS.allowuserlist = NULL;
DeleteItemList(SERVER_ACCESS.allowlegacyconnects); SERVER_ACCESS.allowlegacyconnects = NULL;
StringMapDestroy(SERVER_ACCESS.path_shortcuts); SERVER_ACCESS.path_shortcuts = NULL;
free(SERVER_ACCESS.allowciphers); SERVER_ACCESS.allowciphers = NULL;
free(SERVER_ACCESS.allowtlsversion); SERVER_ACCESS.allowtlsversion = NULL;
/* body server control new ACLs */
NEED_REVERSE_LOOKUP = false;
acl_Free(paths_acl); paths_acl = NULL;
acl_Free(classes_acl); classes_acl = NULL;
acl_Free(vars_acl); vars_acl = NULL;
acl_Free(literals_acl); literals_acl = NULL;
acl_Free(query_acl); query_acl = NULL;
acl_Free(bundles_acl); bundles_acl = NULL;
acl_Free(roles_acl); roles_acl = NULL;
}
static void CheckFileChanges(EvalContext *ctx, Policy **policy, GenericAgentConfig *config)
{
Log(LOG_LEVEL_DEBUG, "Checking file updates for input file '%s'",
config->input_file);
time_t validated_at = ReadTimestampFromPolicyValidatedFile(config, NULL);
bool reload_config = false;
if (config->agent_specific.daemon.last_validated_at < validated_at)
{
Log(LOG_LEVEL_VERBOSE, "New promises detected...");
reload_config = true;
}
if (ReloadConfigRequested())
{
Log(LOG_LEVEL_VERBOSE, "Force reload of inputs files...");
reload_config = true;
}
if (reload_config)
{
ClearRequestReloadConfig();
/* Rereading policies now, so update timestamp. */
config->agent_specific.daemon.last_validated_at = validated_at;
if (GenericAgentArePromisesValid(config))
{
Log(LOG_LEVEL_NOTICE, "Rereading policy file '%s'",
config->input_file);
/* STEP 1: Free everything */
EvalContextClear(ctx);
strcpy(VDOMAIN, "undefined.domain");
ClearAuthAndACLs();
PolicyDestroy(*policy); *policy = NULL;
/* STEP 2: Set Environment, Parse and Evaluate policy */
/*
* TODO why is this done separately here? What's the difference to
* calling the same steps as in cf-serverd.c:main()? Those are:
* GenericAgentConfigApply(); // not here!
* GenericAgentDiscoverContext(); // not here!
* EvalContextClassPutHard("server"); // only here!
* if (GenericAgentCheckPolicy()) // not here!
* policy = LoadPolicy();
* ThisAgentInit(); // not here, only calls umask()
* ReloadHAConfig(); // only here!
* KeepPromises();
* Summarize();
* Plus the following from within StartServer() which is only
* called during startup:
* InitSignals(); // not here
* ServerTLSInitialize(); // not here
* SetServerListenState(); // not here
* InitServer() // not here
* PolicyNew()+AcquireServerLock() // not here
* PrepareServer(sd); // not here
* CollectCallStart(); // both
*/
EvalContextSetPolicyServerFromFile(ctx, GetWorkDir());
UpdateLastPolicyUpdateTime(ctx);
DetectEnvironment(ctx);
GenericAgentDiscoverContext(ctx, config);
/* During startup this is done in GenericAgentDiscoverContext(). */
EvalContextClassPutHard(ctx, CF_AGENTTYPES[AGENT_TYPE_SERVER], "cfe_internal,source=agent");
time_t t = SetReferenceTime();
UpdateTimeClasses(ctx, t);
/* TODO BUG: this modifies config, but previous config has not
* been reset/free'd. Ideally we would want LoadPolicy to not
* modify config at all, but only modify ctx. */
*policy = LoadPolicy(ctx, config);
/* Reload HA related configuration */
ReloadHAConfig();
KeepPromises(ctx, *policy, config);
Summarize();
}
else
{
Log(LOG_LEVEL_INFO, "File changes contain errors -- ignoring");
}
}
else
{
Log(LOG_LEVEL_DEBUG, "No new promises found");
}
}
/* Set up standard signal-handling. */
static void InitSignals()
{
MakeSignalPipe();
signal(SIGINT, HandleSignalsForDaemon);
signal(SIGTERM, HandleSignalsForDaemon);
signal(SIGHUP, HandleSignalsForDaemon);
signal(SIGPIPE, SIG_IGN);
signal(SIGUSR1, HandleSignalsForDaemon);
signal(SIGUSR2, HandleSignalsForDaemon);
}
/* Prepare synthetic agent promise and lock it. */
static CfLock AcquireServerLock(EvalContext *ctx,
GenericAgentConfig *config,
Policy *server_policy)
{
Promise *pp = NULL;
{
Bundle *bp = PolicyAppendBundle(server_policy, NamespaceDefault(),
"server_cfengine_bundle", "agent",
NULL, NULL);
PromiseType *tp = BundleAppendPromiseType(bp, "server_cfengine");
pp = PromiseTypeAppendPromise(tp, config->input_file,
(Rval) { NULL, RVAL_TYPE_NOPROMISEE },
NULL, NULL);
}
assert(pp);
TransactionContext tc = {
.ifelapsed = 0,
.expireafter = 1,
};
return AcquireLock(ctx, pp->promiser, VUQNAME, CFSTARTTIME, tc, pp, false);
}
/* Final preparations for running as server */
static void PrepareServer(int sd)
{
if (sd != -1)
{
Log(LOG_LEVEL_VERBOSE,
"Listening for connections on socket descriptor %d ...", sd);
}
if (!NO_FORK)
#ifdef __MINGW32__
{
Log(LOG_LEVEL_VERBOSE,
"Windows does not support starting processes in the background - running in foreground");
}
#else
{
if (fork() != 0) /* parent */
{
_exit(EXIT_SUCCESS);
}
ActAsDaemon();
}
#endif
/* Close sd on exec, needed for not passing the socket to cf-runagent
* spawned commands. */
SetCloseOnExec(sd, true);
Log(LOG_LEVEL_NOTICE, "Server is starting...");
WritePID("cf-serverd.pid"); /* Arranges for cleanup() to tidy it away */
}
/* Wait for connection-handler threads to finish their work.
*
* @return Number of live threads remaining after waiting.
*/
static int WaitOnThreads()
{
int result = 1;
for (int i = 2; i > 0; i--)
{
if (ThreadLock(cft_server_children))
{
result = ACTIVE_THREADS;
ThreadUnlock(cft_server_children);
}
if (result == 0)
{
break;
}
Log(LOG_LEVEL_VERBOSE,
"Waiting %ds for %d connection threads to finish",
i, result);
sleep(1);
}
if (result > 0)
{
Log(LOG_LEVEL_VERBOSE,
"There are %d connection threads left, exiting anyway",
result);
}
else
{
assert(result == 0);
Log(LOG_LEVEL_VERBOSE,
"All threads are done, cleaning up allocations");
ClearAuthAndACLs();
ServerTLSDeInitialize(NULL, NULL, NULL);
}
return result;
}
static void CollectCallIfDue(EvalContext *ctx)
{
/* Check whether we have established peering with a hub */
if (CollectCallHasPending())
{
extern int COLLECT_WINDOW;
int waiting_queue = 0;
int new_client = CollectCallGetPending(&waiting_queue);
assert(new_client >= 0);
if (waiting_queue > COLLECT_WINDOW)
{
Log(LOG_LEVEL_INFO,
"Abandoning collect call attempt with queue longer than collect_window [%d > %d]",
waiting_queue, COLLECT_WINDOW);
cf_closesocket(new_client);
CollectCallMarkProcessed();
}
else
{
ConnectionInfo *info = ConnectionInfoNew();
assert(info);
ConnectionInfoSetSocket(info, new_client);
info->is_call_collect = true; /* Mark processed when done. */
ServerEntryPoint(ctx, PolicyServerGetIP(), info);
}
}
}
/* Check for new policy just before spawning a thread.
*
* Server reconfiguration can only happen when no threads are active,
* so this is a good time to do it; but we do still have to check for
* running threads. */
static void PolicyUpdateIfSafe(EvalContext *ctx, Policy **policy,
GenericAgentConfig *config)
{
if (ThreadLock(cft_server_children))
{
int prior = COLLECT_INTERVAL;
if (ACTIVE_THREADS == 0)
{
CheckFileChanges(ctx, policy, config);
}
ThreadUnlock(cft_server_children);
/* Check for change in call-collect interval: */
if (prior != COLLECT_INTERVAL)
{
/* Start, stop or change schedule, as appropriate. */
CollectCallStart(COLLECT_INTERVAL);
}
}
}
/* Try to accept a connection; handle if we get one. */
static void AcceptAndHandle(EvalContext *ctx, int sd)
{
/* TODO embed ConnectionInfo into ServerConnectionState. */
ConnectionInfo *info = ConnectionInfoNew(); /* Uses xcalloc() */
info->ss_len = sizeof(info->ss);
info->sd = accept(sd, (struct sockaddr *) &info->ss, &info->ss_len);
if (info->sd == -1)
{
Log(LOG_LEVEL_INFO, "Error accepting connection (%s)", GetErrorStr());
ConnectionInfoDestroy(&info);
return;
}
Log(LOG_LEVEL_DEBUG, "Socket descriptor returned from accept(): %d",
info->sd);
/* Just convert IP address to string, no DNS lookup. */
char ipaddr[CF_MAX_IP_LEN] = "";
getnameinfo((const struct sockaddr *) &info->ss, info->ss_len,
ipaddr, sizeof(ipaddr),
NULL, 0, NI_NUMERICHOST);
/* IPv4 mapped addresses (e.g. "::ffff:192.168.1.2") are
* hereby represented with their IPv4 counterpart. */
ServerEntryPoint(ctx, MapAddress(ipaddr), info);
}
static size_t GetListenQueueSize(void)
{
const char *const queue_size_var = getenv("CF_SERVERD_LISTEN_QUEUE_SIZE");
if (queue_size_var != NULL)
{
long queue_size;
int ret = StringToLong(queue_size_var, &queue_size);
if ((ret == 0) && (queue_size > 0) && (queue_size <= MAX_LISTEN_QUEUE_SIZE))
{
return (size_t) queue_size;
}
Log(LOG_LEVEL_WARNING,
"$CF_SERVERD_LISTEN_QUEUE_SIZE = '%s' doesn't specify a valid number for listen queue size, "
"falling back to default (%d).",
queue_size_var, DEFAULT_LISTEN_QUEUE_SIZE);
}
return DEFAULT_LISTEN_QUEUE_SIZE;
}
/**
* @retval >0 Number of threads still working
* @retval 0 All threads are done
* @retval -1 Server didn't run
*/
int StartServer(EvalContext *ctx, Policy **policy, GenericAgentConfig *config)
{
InitSignals();
bool tls_init_ok = ServerTLSInitialize(NULL, NULL, NULL);
if (!tls_init_ok)
{
return -1;
}
size_t queue_size = GetListenQueueSize();
int sd = SetServerListenState(ctx, queue_size, NULL, SERVER_LISTEN, &InitServer);
/* Necessary for our use of select() to work in WaitForIncoming(): */
assert(sd < sizeof(fd_set) * CHAR_BIT &&
GetSignalPipe() < sizeof(fd_set) * CHAR_BIT);
Policy *server_cfengine_policy = PolicyNew();
CfLock thislock = AcquireServerLock(ctx, config, server_cfengine_policy);
if (thislock.lock == NULL)
{
PolicyDestroy(server_cfengine_policy);
if (sd >= 0)
{
cf_closesocket(sd);
}
return -1;
}
PrepareServer(sd);
CollectCallStart(COLLECT_INTERVAL);
while (!IsPendingTermination())
{
CollectCallIfDue(ctx);
int selected = WaitForIncoming(sd, WAIT_INCOMING_TIMEOUT);
Log(LOG_LEVEL_DEBUG, "select(): %d", selected);
if (selected == -1)
{
Log(LOG_LEVEL_ERR,
"Error while waiting for connections. (select: %s)",
GetErrorStr());
break;
}
else if (selected >= 0) /* timeout or success */
{
PolicyUpdateIfSafe(ctx, policy, config);
/* Is there a new connection pending at our listening socket? */
if (selected > 0)
{
AcceptAndHandle(ctx, sd);
}
} /* else: interrupted, maybe pending termination. */
}
Log(LOG_LEVEL_NOTICE, "Cleaning up and exiting...");
CollectCallStop();
if (sd != -1)
{
Log(LOG_LEVEL_VERBOSE, "Closing listening socket");
cf_closesocket(sd); /* Close listening socket */
}
/* This is a graceful exit, give 2 seconds chance to threads. */
int threads_left = WaitOnThreads();
YieldCurrentLock(thislock);
PolicyDestroy(server_cfengine_policy);
return threads_left;
}
cfengine-3.12.1/cf-serverd/server_common.c 0000644 0000000 0000000 00000161000 13377750461 020447 0 ustar 00root root 0000000 0000000 /*
Copyright 2018 Northern.tech AS
This file is part of CFEngine 3 - written and maintained by Northern.tech AS.
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; version 3.
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, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
To the extent this program is licensed as part of the Enterprise
versions of CFEngine, the applicable Commercial Open Source License
(COSL) may apply to this file if you as a licensee so wish it. See
included file COSL.txt.
*/
static const int CF_NOSIZE = -1;
#include
#include /* ItemList2CSV_bound */
#include /* ToLower,StrCatDelim */
#include /* StringMatchFull */
#include /* EncryptString */
#include
#include
#include
#include
#include
#include
#include
#include /* IsRegexItemIn */
#include
#include /* SendSocketStream */
#include /* SendTransaction,ReceiveTransaction */
#include /* ERR_get_error */
#include /* TLSSend */
#include
#include
#include
#include /* UnexpectedError */
#include /* NovaWin_UserNameToSid */
#include /* ThreadLock */
#include /* struct Stat */
#include "server_access.h"
/* NOTE: Always Log(LOG_LEVEL_INFO) before calling RefuseAccess(), so that
* some clue is printed in the cf-serverd logs. */
void RefuseAccess(ServerConnectionState *conn, char *errmesg)
{
SendTransaction(conn->conn_info, CF_FAILEDSTR, 0, CF_DONE);
/* TODO remove logging, it's done elsewhere. */
Log(LOG_LEVEL_VERBOSE, "REFUSAL to user='%s' of request: %s",
NULL_OR_EMPTY(conn->username) ? "?" : conn->username,
errmesg);
}
bool IsUserNameValid(const char *username)
{
/* Add whatever characters are considered invalid in username */
const char *invalid_username_characters = "\\/";
if (strpbrk(username, invalid_username_characters) == NULL)
{
return true;
}
return false;
}
int AllowedUser(char *user)
{
if (IsItemIn(SERVER_ACCESS.allowuserlist, user))
{
Log(LOG_LEVEL_DEBUG, "User %s granted connection privileges", user);
return true;
}
Log(LOG_LEVEL_DEBUG, "User %s is not allowed on this server", user);
return false;
}
Item *ListPersistentClasses()
{
Log(LOG_LEVEL_VERBOSE, "Scanning for all persistent classes");
CF_DB *dbp;
CF_DBC *dbcp;
if (!OpenDB(&dbp, dbid_state))
{
char *db_path = DBIdToPath(dbid_state);
Log(LOG_LEVEL_ERR, "Unable to open persistent classes database '%s'", db_path);
free(db_path);
return NULL;
}
if (!NewDBCursor(dbp, &dbcp))
{
char *db_path = DBIdToPath(dbid_state);
Log(LOG_LEVEL_ERR, "Unable to get cursor for persistent classes database '%s'", db_path);
free(db_path);
CloseDB(dbp);
return NULL;
}
const PersistentClassInfo *value;
int ksize, vsize;
char *key;
size_t count = 0;
time_t now = time(NULL);
Item *persistent_classes = NULL;
while (NextDB(dbcp, &key, &ksize, (void **)&value, &vsize))
{
if (now > value->expires)
{
Log(LOG_LEVEL_DEBUG,
"Persistent class %s expired, removing from database", key);
DBCursorDeleteEntry(dbcp);
}
else
{
count++;
PrependItem(&persistent_classes, key, NULL);
}
}
DeleteDBCursor(dbcp);
CloseDB(dbp);
if (LogGetGlobalLevel() >= LOG_LEVEL_VERBOSE)
{
char logbuf[CF_BUFSIZE];
ItemList2CSV_bound(persistent_classes, logbuf, sizeof(logbuf), ' ');
Log(LOG_LEVEL_VERBOSE,
"Found %zu valid persistent classes in state database: %s",
count, logbuf);
}
return persistent_classes;
}
static void ReplyNothing(ServerConnectionState *conn)
{
char buffer[CF_BUFSIZE];
snprintf(buffer, CF_BUFSIZE, "Hello %s (%s), nothing relevant to do here...\n\n", conn->hostname, conn->ipaddr);
if (SendTransaction(conn->conn_info, buffer, 0, CF_DONE) == -1)
{
Log(LOG_LEVEL_ERR, "Unable to send transaction. (send: %s)", GetErrorStr());
}
}
/* Used only in EXEC protocol command, to check if any of the received classes
* is defined in the server. */
int MatchClasses(const EvalContext *ctx, ServerConnectionState *conn)
{
char recvbuffer[CF_BUFSIZE];
Item *classlist = NULL, *ip;
int count = 0;
while (true && (count < 10)) /* arbitrary check to avoid infinite loop, DoS attack */
{
count++;
if (ReceiveTransaction(conn->conn_info, recvbuffer, NULL) == -1)
{
Log(LOG_LEVEL_VERBOSE, "Unable to read data from network. (ReceiveTransaction: %s)", GetErrorStr());
return false;
}
if (strncmp(recvbuffer, CFD_TERMINATOR, strlen(CFD_TERMINATOR)) == 0)
{
Log(LOG_LEVEL_DEBUG, "Got CFD_TERMINATOR");
if (count == 1)
{
/* This is the common case, that cf-runagent had no
"-s class1,class2" argument. */
Log(LOG_LEVEL_DEBUG, "No classes were sent, assuming no restrictions...");
return true;
}
break;
}
Log(LOG_LEVEL_DEBUG, "Got class buffer: %s", recvbuffer);
classlist = SplitStringAsItemList(recvbuffer, ' ');
for (ip = classlist; ip != NULL; ip = ip->next)
{
Log(LOG_LEVEL_VERBOSE, "Checking whether class %s can be identified as me...", ip->name);
if (IsDefinedClass(ctx, ip->name))
{
Log(LOG_LEVEL_DEBUG, "Class '%s' matched, accepting...", ip->name);
DeleteItemList(classlist);
return true;
}
{
/* What the heck are we doing here? */
/* Hmmm so we iterate over all classes to see if the regex
* received (ip->name) matches (StringMatchFull) to any local
* class (expr)... SLOW! Change the spec! Don't accept
* regexes! How many will be affected if a specific class has
* to be set to run command, instead of matching a pattern?
* It's safer anyway... */
ClassTableIterator *iter = EvalContextClassTableIteratorNewGlobal(ctx, NULL, true, true);
Class *cls = NULL;
while ((cls = ClassTableIteratorNext(iter)))
{
char *expr = ClassRefToString(cls->ns, cls->name);
/* FIXME: review this strcmp. Moved out from StringMatch */
bool match = (strcmp(ip->name, expr) == 0 ||
StringMatchFull(ip->name, expr));
free(expr);
if (match)
{
Log(LOG_LEVEL_DEBUG, "Class matched regular expression '%s', accepting...", ip->name);
DeleteItemList(classlist);
return true;
}
}
ClassTableIteratorDestroy(iter);
}
if (strncmp(ip->name, CFD_TERMINATOR, strlen(CFD_TERMINATOR)) == 0)
{
Log(LOG_LEVEL_VERBOSE, "No classes matched, rejecting....");
ReplyNothing(conn);
DeleteItemList(classlist);
return false;
}
}
}
ReplyNothing(conn);
Log(LOG_LEVEL_VERBOSE, "No classes matched, rejecting....");
DeleteItemList(classlist);
return false;
}
/* TODO deprecate this function, only a simple SendTransaction(CFD_TERMINATOR)
* should be enough, without even error printing (it's already done in
* SendTransaction()). */
void Terminate(ConnectionInfo *connection)
{
/* We send a trailing NULL in this transaction packet. TODO WHY? */
if (SendTransaction(connection, CFD_TERMINATOR,
strlen(CFD_TERMINATOR) + 1, CF_DONE) == -1)
{
Log(LOG_LEVEL_VERBOSE, "Unable to reply with terminator. (send: %s)",
GetErrorStr());
}
}
static int TransferRights(const ServerConnectionState *conn,
const char *filename, const struct stat *sb)
{
Log(LOG_LEVEL_DEBUG, "Checking ownership of file: %s", filename);
/* Don't do any check if connected user claims to be "root" or if
* "maproot" in access_rules contains the connecting IP address. */
if ((conn->uid == 0) || (conn->maproot))
{
Log(LOG_LEVEL_DEBUG, "Access granted because %s",
(conn->uid == 0) ? "remote user is root"
: "of maproot");
return true; /* access granted */
}
#ifdef __MINGW32__
SECURITY_DESCRIPTOR *secDesc;
SID *ownerSid;
if (GetNamedSecurityInfo(
filename, SE_FILE_OBJECT, OWNER_SECURITY_INFORMATION,
(PSID *) &ownerSid, NULL, NULL, NULL, (void **) &secDesc)
!= ERROR_SUCCESS)
{
Log(LOG_LEVEL_ERR,
"Could not retrieve owner of file '%s' "
"(GetNamedSecurityInfo: %s)",
filename, GetErrorStr());
return false;
}
LocalFree(secDesc);
if (!IsValidSid(conn->sid) ||
!EqualSid(ownerSid, conn->sid))
{
/* If "maproot" we've already granted access. */
assert(!conn->maproot);
Log(LOG_LEVEL_INFO,
"Remote user '%s' is not the owner of the file, access denied, "
"consider maproot", conn->username);
return false;
}
Log(LOG_LEVEL_DEBUG,
"User '%s' is the owner of the file, access granted",
conn->username);
#else /* UNIX systems - common path */
if (sb->st_uid != conn->uid) /* does not own the file */
{
if (!(sb->st_mode & S_IROTH)) /* file not world readable */
{
Log(LOG_LEVEL_INFO,
"Remote user '%s' is not owner of the file, access denied, "
"consider maproot or making file world-readable",
conn->username);
return false;
}
else
{
Log(LOG_LEVEL_DEBUG,
"Remote user '%s' is not the owner of the file, "
"but file is world readable, access granted",
conn->username); /* access granted */
}
}
else
{
Log(LOG_LEVEL_DEBUG,
"User '%s' is the owner of the file, access granted",
conn->username); /* access granted */
}
/* ADMIT ACCESS, to summarise the following condition is now true: */
/* Remote user is root, where "user" is just a string in the protocol, he
* might claim whatever he wants but will be able to login only if the
* user-key.pub key is found, */
assert((conn->uid == 0) ||
/* OR remote IP has maproot in the file's access_rules, */
(conn->maproot == true) ||
/* OR file is owned by the same username the user claimed - useless or
* even dangerous outside NIS, KERBEROS or LDAP authenticated domains, */
(sb->st_uid == conn->uid) ||
/* OR file is readable by everyone */
(sb->st_mode & S_IROTH));
#endif
return true;
}
static void AbortTransfer(ConnectionInfo *connection, char *filename)
{
Log(LOG_LEVEL_VERBOSE, "Aborting transfer of file due to source changes");
char sendbuffer[CF_BUFSIZE];
snprintf(sendbuffer, CF_BUFSIZE, "%s%s: %s",
CF_CHANGEDSTR1, CF_CHANGEDSTR2, filename);
if (SendTransaction(connection, sendbuffer, 0, CF_DONE) == -1)
{
Log(LOG_LEVEL_VERBOSE, "Send failed in GetFile. (send: %s)",
GetErrorStr());
}
}
static void FailedTransfer(ConnectionInfo *connection)
{
Log(LOG_LEVEL_VERBOSE, "Transfer failure");
char sendbuffer[CF_BUFSIZE];
snprintf(sendbuffer, CF_BUFSIZE, "%s", CF_FAILEDSTR);
if (SendTransaction(connection, sendbuffer, 0, CF_DONE) == -1)
{
Log(LOG_LEVEL_VERBOSE, "Send failed in GetFile. (send: %s)",
GetErrorStr());
}
}
void CfGetFile(ServerFileGetState *args)
{
int fd;
off_t n_read, total = 0, sendlen = 0, count = 0;
char sendbuffer[CF_BUFSIZE + 256], filename[CF_BUFSIZE];
struct stat sb;
int blocksize = 2048;
ConnectionInfo *conn_info = args->conn->conn_info;
TranslatePath(filename, args->replyfile);
stat(filename, &sb);
Log(LOG_LEVEL_DEBUG, "CfGetFile('%s'), size = %jd",
filename, (intmax_t) sb.st_size);
/* Now check to see if we have remote permission */
if (!TransferRights(args->conn, filename, &sb))
{
Log(LOG_LEVEL_INFO, "REFUSE access to file: %s", filename);
RefuseAccess(args->conn, args->replyfile);
snprintf(sendbuffer, CF_BUFSIZE, "%s", CF_FAILEDSTR);
if (ConnectionInfoProtocolVersion(conn_info) == CF_PROTOCOL_CLASSIC)
{
SendSocketStream(ConnectionInfoSocket(conn_info), sendbuffer, args->buf_size);
}
else if (ConnectionInfoProtocolVersion(conn_info) == CF_PROTOCOL_TLS)
{
TLSSend(ConnectionInfoSSL(conn_info), sendbuffer, args->buf_size);
}
return;
}
/* File transfer */
if ((fd = safe_open(filename, O_RDONLY)) == -1)
{
Log(LOG_LEVEL_ERR, "Open error of file '%s'. (open: %s)",
filename, GetErrorStr());
snprintf(sendbuffer, CF_BUFSIZE, "%s", CF_FAILEDSTR);
if (ConnectionInfoProtocolVersion(conn_info) == CF_PROTOCOL_CLASSIC)
{
SendSocketStream(ConnectionInfoSocket(conn_info), sendbuffer, args->buf_size);
}
else if (ConnectionInfoProtocolVersion(conn_info) == CF_PROTOCOL_TLS)
{
TLSSend(ConnectionInfoSSL(conn_info), sendbuffer, args->buf_size);
}
}
else
{
int div = 3;
if (sb.st_size > 10485760L) /* File larger than 10 MB, checks every 64kB */
{
div = 32;
}
while (true)
{
memset(sendbuffer, 0, CF_BUFSIZE);
Log(LOG_LEVEL_DEBUG, "Now reading from disk...");
if ((n_read = read(fd, sendbuffer, blocksize)) == -1)
{
Log(LOG_LEVEL_ERR, "Read failed in GetFile. (read: %s)", GetErrorStr());
break;
}
if (n_read == 0)
{
break;
}
else
{
off_t savedlen = sb.st_size;
/* check the file is not changing at source */
if (count++ % div == 0) /* Don't do this too often */
{
if (stat(filename, &sb))
{
Log(LOG_LEVEL_ERR, "Cannot stat file '%s'. (stat: %s)",
filename, GetErrorStr());
break;
}
}
if (sb.st_size != savedlen)
{
snprintf(sendbuffer, CF_BUFSIZE, "%s%s: %s", CF_CHANGEDSTR1, CF_CHANGEDSTR2, filename);
if (ConnectionInfoProtocolVersion(conn_info) == CF_PROTOCOL_CLASSIC)
{
if (SendSocketStream(ConnectionInfoSocket(conn_info), sendbuffer, blocksize) == -1)
{
Log(LOG_LEVEL_VERBOSE, "Send failed in GetFile. (send: %s)", GetErrorStr());
}
}
else if (ConnectionInfoProtocolVersion(conn_info) == CF_PROTOCOL_TLS)
{
if (TLSSend(ConnectionInfoSSL(conn_info), sendbuffer, blocksize) == -1)
{
Log(LOG_LEVEL_VERBOSE, "Send failed in GetFile. (send: %s)", GetErrorStr());
}
}
Log(LOG_LEVEL_DEBUG,
"Aborting transfer after %jd: file is changing rapidly at source.",
(intmax_t) total);
break;
}
if ((savedlen - total) / blocksize > 0)
{
sendlen = blocksize;
}
else if (savedlen != 0)
{
sendlen = (savedlen - total);
}
}
total += n_read;
if (ConnectionInfoProtocolVersion(conn_info) == CF_PROTOCOL_CLASSIC)
{
if (SendSocketStream(ConnectionInfoSocket(conn_info), sendbuffer, sendlen) == -1)
{
Log(LOG_LEVEL_VERBOSE, "Send failed in GetFile. (send: %s)", GetErrorStr());
break;
}
}
else if (ConnectionInfoProtocolVersion(conn_info) == CF_PROTOCOL_TLS)
{
if (TLSSend(ConnectionInfoSSL(conn_info), sendbuffer, sendlen) == -1)
{
Log(LOG_LEVEL_VERBOSE, "Send failed in GetFile. (send: %s)", GetErrorStr());
break;
}
}
}
close(fd);
}
}
void CfEncryptGetFile(ServerFileGetState *args)
/* Because the stream doesn't end for each file, we need to know the
exact number of bytes transmitted, which might change during
encryption, hence we need to handle this with transactions */
{
int fd, n_read, cipherlen = 0, finlen = 0;
off_t total = 0, count = 0;
char sendbuffer[CF_BUFSIZE + 256], out[CF_BUFSIZE], filename[CF_BUFSIZE];
unsigned char iv[32] =
{ 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8 };
int blocksize = CF_BUFSIZE - 4 * CF_INBAND_OFFSET;
char *key, enctype;
struct stat sb;
ConnectionInfo *conn_info = args->conn->conn_info;
key = args->conn->session_key;
enctype = args->conn->encryption_type;
TranslatePath(filename, args->replyfile);
stat(filename, &sb);
Log(LOG_LEVEL_DEBUG, "CfEncryptGetFile('%s'), size = %jd",
filename, (intmax_t) sb.st_size);
/* Now check to see if we have remote permission */
if (!TransferRights(args->conn, filename, &sb))
{
Log(LOG_LEVEL_INFO, "REFUSE access to file: %s", filename);
RefuseAccess(args->conn, args->replyfile);
FailedTransfer(conn_info);
return;
}
EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
if (ctx == NULL)
{
Log(LOG_LEVEL_ERR, "Failed to allocate cipher: %s",
TLSErrorString(ERR_get_error()));
return;
}
if ((fd = safe_open(filename, O_RDONLY)) == -1)
{
Log(LOG_LEVEL_ERR, "Open error of file '%s'. (open: %s)", filename, GetErrorStr());
FailedTransfer(conn_info);
}
else
{
int div = 3;
if (sb.st_size > 10485760L) /* File larger than 10 MB, checks every 64kB */
{
div = 32;
}
while (true)
{
memset(sendbuffer, 0, CF_BUFSIZE);
if ((n_read = read(fd, sendbuffer, blocksize)) == -1)
{
Log(LOG_LEVEL_ERR, "Read failed in EncryptGetFile. (read: %s)", GetErrorStr());
break;
}
off_t savedlen = sb.st_size;
if (count++ % div == 0) /* Don't do this too often */
{
Log(LOG_LEVEL_DEBUG, "Restatting '%s' - size %d", filename, n_read);
if (stat(filename, &sb))
{
Log(LOG_LEVEL_ERR, "Cannot stat file '%s' (stat: %s)",
filename, GetErrorStr());
break;
}
}
if (sb.st_size != savedlen)
{
AbortTransfer(conn_info, filename);
break;
}
total += n_read;
if (n_read > 0)
{
EVP_EncryptInit_ex(ctx, CfengineCipher(enctype), NULL, key, iv);
if (!EVP_EncryptUpdate(ctx, out, &cipherlen, sendbuffer, n_read))
{
FailedTransfer(conn_info);
EVP_CIPHER_CTX_free(ctx);
close(fd);
return;
}
if (!EVP_EncryptFinal_ex(ctx, out + cipherlen, &finlen))
{
FailedTransfer(conn_info);
EVP_CIPHER_CTX_free(ctx);
close(fd);
return;
}
}
if (total >= savedlen)
{
if (SendTransaction(conn_info, out, cipherlen + finlen, CF_DONE) == -1)
{
Log(LOG_LEVEL_VERBOSE, "Send failed in GetFile. (send: %s)", GetErrorStr());
EVP_CIPHER_CTX_free(ctx);
close(fd);
return;
}
break;
}
else
{
if (SendTransaction(conn_info, out, cipherlen + finlen, CF_MORE) == -1)
{
Log(LOG_LEVEL_VERBOSE, "Send failed in GetFile. (send: %s)", GetErrorStr());
close(fd);
EVP_CIPHER_CTX_free(ctx);
return;
}
}
}
}
EVP_CIPHER_CTX_free(ctx);
close(fd);
}
int StatFile(ServerConnectionState *conn, char *sendbuffer, char *ofilename)
/* Because we do not know the size or structure of remote datatypes,*/
/* the simplest way to transfer the data is to convert them into */
/* plain text and interpret them on the other side. */
{
Stat cfst;
struct stat statbuf, statlinkbuf;
char linkbuf[CF_BUFSIZE], filename[CF_BUFSIZE];
int islink = false;
TranslatePath(filename, ofilename);
memset(&cfst, 0, sizeof(Stat));
if (strlen(ReadLastNode(filename)) > CF_MAXLINKSIZE)
{
snprintf(sendbuffer, CF_BUFSIZE, "BAD: Filename suspiciously long [%s]", filename);
Log(LOG_LEVEL_ERR, "%s", sendbuffer);
SendTransaction(conn->conn_info, sendbuffer, 0, CF_DONE);
return -1;
}
if (lstat(filename, &statbuf) == -1)
{
snprintf(sendbuffer, CF_BUFSIZE, "BAD: unable to stat file %s", filename);
Log(LOG_LEVEL_VERBOSE, "%s. (lstat: %s)", sendbuffer, GetErrorStr());
SendTransaction(conn->conn_info, sendbuffer, 0, CF_DONE);
return -1;
}
cfst.cf_readlink = NULL;
cfst.cf_lmode = 0;
cfst.cf_nlink = CF_NOSIZE;
memset(linkbuf, 0, CF_BUFSIZE);
#ifndef __MINGW32__ // windows doesn't support symbolic links
if (S_ISLNK(statbuf.st_mode))
{
islink = true;
cfst.cf_type = FILE_TYPE_LINK; /* pointless - overwritten */
cfst.cf_lmode = statbuf.st_mode & 07777;
cfst.cf_nlink = statbuf.st_nlink;
if (readlink(filename, linkbuf, CF_BUFSIZE - 1) == -1)
{
strcpy(sendbuffer, "BAD: unable to read link");
Log(LOG_LEVEL_ERR, "%s. (readlink: %s)", sendbuffer, GetErrorStr());
SendTransaction(conn->conn_info, sendbuffer, 0, CF_DONE);
return -1;
}
Log(LOG_LEVEL_DEBUG, "readlink '%s'", linkbuf);
cfst.cf_readlink = linkbuf;
}
if (islink && (stat(filename, &statlinkbuf) != -1)) /* linktype=copy used by agent */
{
Log(LOG_LEVEL_DEBUG, "Getting size of link deref '%s'", linkbuf);
statbuf.st_size = statlinkbuf.st_size;
statbuf.st_mode = statlinkbuf.st_mode;
statbuf.st_uid = statlinkbuf.st_uid;
statbuf.st_gid = statlinkbuf.st_gid;
statbuf.st_mtime = statlinkbuf.st_mtime;
statbuf.st_ctime = statlinkbuf.st_ctime;
}
#endif /* !__MINGW32__ */
if (S_ISDIR(statbuf.st_mode))
{
cfst.cf_type = FILE_TYPE_DIR;
}
if (S_ISREG(statbuf.st_mode))
{
cfst.cf_type = FILE_TYPE_REGULAR;
}
if (S_ISSOCK(statbuf.st_mode))
{
cfst.cf_type = FILE_TYPE_SOCK;
}
if (S_ISCHR(statbuf.st_mode))
{
cfst.cf_type = FILE_TYPE_CHAR_;
}
if (S_ISBLK(statbuf.st_mode))
{
cfst.cf_type = FILE_TYPE_BLOCK;
}
if (S_ISFIFO(statbuf.st_mode))
{
cfst.cf_type = FILE_TYPE_FIFO;
}
cfst.cf_mode = statbuf.st_mode & 07777;
cfst.cf_uid = statbuf.st_uid & 0xFFFFFFFF;
cfst.cf_gid = statbuf.st_gid & 0xFFFFFFFF;
cfst.cf_size = statbuf.st_size;
cfst.cf_atime = statbuf.st_atime;
cfst.cf_mtime = statbuf.st_mtime;
cfst.cf_ctime = statbuf.st_ctime;
cfst.cf_ino = statbuf.st_ino;
cfst.cf_dev = statbuf.st_dev;
cfst.cf_readlink = linkbuf;
if (cfst.cf_nlink == CF_NOSIZE)
{
cfst.cf_nlink = statbuf.st_nlink;
}
/* Is file sparse? */
if (statbuf.st_size > ST_NBYTES(statbuf))
{
cfst.cf_makeholes = 1; /* must have a hole to get checksum right */
}
else
{
cfst.cf_makeholes = 0;
}
memset(sendbuffer, 0, CF_BUFSIZE);
/* send as plain text */
Log(LOG_LEVEL_DEBUG, "OK: type = %d, mode = %jo, lmode = %jo, "
"uid = %ju, gid = %ju, size = %jd, atime=%jd, mtime = %jd",
cfst.cf_type, (uintmax_t) cfst.cf_mode, (uintmax_t) cfst.cf_lmode,
(uintmax_t) cfst.cf_uid, (uintmax_t) cfst.cf_gid, (intmax_t) cfst.cf_size,
(intmax_t) cfst.cf_atime, (intmax_t) cfst.cf_mtime);
snprintf(sendbuffer, CF_BUFSIZE,
"OK: %d %ju %ju %ju %ju %jd %jd %jd %jd %d %d %d %jd",
cfst.cf_type, (uintmax_t) cfst.cf_mode, (uintmax_t) cfst.cf_lmode,
(uintmax_t) cfst.cf_uid, (uintmax_t) cfst.cf_gid, (intmax_t) cfst.cf_size,
(intmax_t) cfst.cf_atime, (intmax_t) cfst.cf_mtime, (intmax_t) cfst.cf_ctime,
cfst.cf_makeholes, cfst.cf_ino, cfst.cf_nlink, (intmax_t) cfst.cf_dev);
SendTransaction(conn->conn_info, sendbuffer, 0, CF_DONE);
memset(sendbuffer, 0, CF_BUFSIZE);
if (cfst.cf_readlink != NULL)
{
strcpy(sendbuffer, "OK:");
strcat(sendbuffer, cfst.cf_readlink);
}
else
{
strcpy(sendbuffer, "OK:");
}
SendTransaction(conn->conn_info, sendbuffer, 0, CF_DONE);
return 0;
}
bool CompareLocalHash(const char *filename, const char digest[EVP_MAX_MD_SIZE + 1],
char sendbuffer[CF_BUFSIZE])
{
char translated_filename[CF_BUFSIZE] = { 0 };
TranslatePath(translated_filename, filename);
unsigned char file_digest[EVP_MAX_MD_SIZE + 1] = { 0 };
/* TODO connection might timeout if this takes long! */
HashFile(translated_filename, file_digest, CF_DEFAULT_DIGEST, false);
if (HashesMatch(digest, file_digest, CF_DEFAULT_DIGEST))
{
assert(strlen(CFD_FALSE) < CF_BUFSIZE);
strcpy(sendbuffer, CFD_FALSE);
Log(LOG_LEVEL_DEBUG, "Hashes matched ok");
return true;
}
else
{
assert(strlen(CFD_TRUE) < CF_BUFSIZE);
strcpy(sendbuffer, CFD_TRUE);
Log(LOG_LEVEL_DEBUG, "Hashes didn't match");
return false;
}
}
void GetServerLiteral(EvalContext *ctx, ServerConnectionState *conn, char *sendbuffer, char *recvbuffer, int encrypted)
{
char handle[CF_BUFSIZE], out[CF_BUFSIZE];
int cipherlen;
sscanf(recvbuffer, "VAR %255[^\n]", handle);
if (ReturnLiteralData(ctx, handle, out))
{
memset(sendbuffer, 0, CF_BUFSIZE);
snprintf(sendbuffer, CF_BUFSIZE - 1, "%s", out);
}
else
{
memset(sendbuffer, 0, CF_BUFSIZE);
snprintf(sendbuffer, CF_BUFSIZE - 1, "BAD: Not found");
}
if (encrypted)
{
cipherlen = EncryptString(out, sizeof(out),
sendbuffer, strlen(sendbuffer) + 1,
conn->encryption_type, conn->session_key);
SendTransaction(conn->conn_info, out, cipherlen, CF_DONE);
}
else
{
SendTransaction(conn->conn_info, sendbuffer, 0, CF_DONE);
}
}
int GetServerQuery(ServerConnectionState *conn, char *recvbuffer, int encrypt)
{
char query[CF_BUFSIZE];
query[0] = '\0';
sscanf(recvbuffer, "QUERY %255[^\n]", query);
if (strlen(query) == 0)
{
return false;
}
return ReturnQueryData(conn, query, encrypt);
}
void ReplyServerContext(ServerConnectionState *conn, int encrypted, Item *classes)
{
char sendbuffer[CF_BUFSIZE - CF_INBAND_OFFSET];
size_t ret = ItemList2CSV_bound(classes,
sendbuffer, sizeof(sendbuffer), ',');
if (ret >= sizeof(sendbuffer))
{
Log(LOG_LEVEL_ERR, "Overflow: classes don't fit in send buffer");
}
DeleteItemList(classes);
if (encrypted)
{
char out[CF_BUFSIZE];
int cipherlen = EncryptString(out, sizeof(out),
sendbuffer, strlen(sendbuffer) + 1,
conn->encryption_type, conn->session_key);
SendTransaction(conn->conn_info, out, cipherlen, CF_DONE);
}
else
{
SendTransaction(conn->conn_info, sendbuffer, 0, CF_DONE);
}
}
int CfOpenDirectory(ServerConnectionState *conn, char *sendbuffer, char *oldDirname)
{
Dir *dirh;
const struct dirent *dirp;
int offset;
char dirname[CF_BUFSIZE];
TranslatePath(dirname, oldDirname);
if (!IsAbsoluteFileName(dirname))
{
strcpy(sendbuffer, "BAD: request to access a non-absolute filename");
SendTransaction(conn->conn_info, sendbuffer, 0, CF_DONE);
return -1;
}
if ((dirh = DirOpen(dirname)) == NULL)
{
Log(LOG_LEVEL_INFO, "Couldn't open directory '%s' (DirOpen:%s)",
dirname, GetErrorStr());
snprintf(sendbuffer, CF_BUFSIZE, "BAD: cfengine, couldn't open dir %s", dirname);
SendTransaction(conn->conn_info, sendbuffer, 0, CF_DONE);
return -1;
}
/* Pack names for transmission */
offset = 0;
for (dirp = DirRead(dirh); dirp != NULL; dirp = DirRead(dirh))
{
/* Always leave MAXLINKSIZE bytes for CFD_TERMINATOR. Why??? */
if (strlen(dirp->d_name) + 1 + offset >= CF_BUFSIZE - CF_MAXLINKSIZE)
{
/* Double '\0' indicates end of packet. */
sendbuffer[offset] = '\0';
SendTransaction(conn->conn_info, sendbuffer, offset + 1, CF_MORE);
offset = 0; /* new packet */
}
/* TODO fix copying names greater than 256. */
strlcpy(sendbuffer + offset, dirp->d_name, CF_MAXLINKSIZE);
offset += strlen(dirp->d_name) + 1; /* +1 for '\0' */
}
strcpy(sendbuffer + offset, CFD_TERMINATOR);
offset += strlen(CFD_TERMINATOR) + 1; /* +1 for '\0' */
/* Double '\0' indicates end of packet. */
sendbuffer[offset] = '\0';
SendTransaction(conn->conn_info, sendbuffer, offset + 1, CF_DONE);
DirClose(dirh);
return 0;
}
/**************************************************************/
int CfSecOpenDirectory(ServerConnectionState *conn, char *sendbuffer, char *dirname)
{
Dir *dirh;
const struct dirent *dirp;
int offset, cipherlen;
char out[CF_BUFSIZE];
if (!IsAbsoluteFileName(dirname))
{
strcpy(sendbuffer, "BAD: request to access a non-absolute filename");
cipherlen = EncryptString(out, sizeof(out),
sendbuffer, strlen(sendbuffer) + 1,
conn->encryption_type, conn->session_key);
SendTransaction(conn->conn_info, out, cipherlen, CF_DONE);
return -1;
}
if ((dirh = DirOpen(dirname)) == NULL)
{
Log(LOG_LEVEL_VERBOSE, "Couldn't open dir %s", dirname);
snprintf(sendbuffer, CF_BUFSIZE, "BAD: cfengine, couldn't open dir %s", dirname);
cipherlen = EncryptString(out, sizeof(out),
sendbuffer, strlen(sendbuffer) + 1,
conn->encryption_type, conn->session_key);
SendTransaction(conn->conn_info, out, cipherlen, CF_DONE);
return -1;
}
/* Pack names for transmission */
memset(sendbuffer, 0, CF_BUFSIZE);
offset = 0;
for (dirp = DirRead(dirh); dirp != NULL; dirp = DirRead(dirh))
{
if (strlen(dirp->d_name) + 1 + offset >= CF_BUFSIZE - CF_MAXLINKSIZE)
{
cipherlen = EncryptString(out, sizeof(out),
sendbuffer, offset + 1,
conn->encryption_type, conn->session_key);
SendTransaction(conn->conn_info, out, cipherlen, CF_MORE);
offset = 0;
memset(sendbuffer, 0, CF_BUFSIZE);
memset(out, 0, CF_BUFSIZE);
}
strlcpy(sendbuffer + offset, dirp->d_name, CF_MAXLINKSIZE);
/* + zero byte separator */
offset += strlen(dirp->d_name) + 1;
}
strcpy(sendbuffer + offset, CFD_TERMINATOR);
cipherlen =
EncryptString(out, sizeof(out),
sendbuffer, offset + 2 + strlen(CFD_TERMINATOR),
conn->encryption_type, conn->session_key);
SendTransaction(conn->conn_info, out, cipherlen, CF_DONE);
DirClose(dirh);
return 0;
}
/********************* MISC UTILITY FUNCTIONS *************************/
/**
* Search and replace occurrences of #find1, #find2, #find3, with
* #repl1, #repl2, #repl3 respectively.
*
* "$(connection.ip)" from "191.168.0.1"
* "$(connection.hostname)" from "blah.cfengine.com",
* "$(connection.key)" from "SHA=asdfghjkl"
*
* @return the output length of #buf, (size_t) -1 if overflow would occur,
* or 0 if no replacement happened and #buf was not touched.
*
* @TODO change the function to more generic interface accepting arbitrary
* find/replace pairs.
*/
size_t ReplaceSpecialVariables(char *buf, size_t buf_size,
const char *find1, const char *repl1,
const char *find2, const char *repl2,
const char *find3, const char *repl3)
{
size_t ret = 0;
if ((find1 != NULL) && (find1[0] != '\0') &&
(repl1 != NULL) && (repl1[0] != '\0'))
{
size_t ret2 = StringReplace(buf, buf_size, find1, repl1);
ret = MAX(ret, ret2); /* size_t is unsigned, thus -1 wins */
}
if ((ret != (size_t) -1) &&
(find2 != NULL) && (find2[0] != '\0') &&
(repl2 != NULL) && (repl2[0] != '\0'))
{
size_t ret2 = StringReplace(buf, buf_size, find2, repl2);
ret = MAX(ret, ret2);
}
if ((ret != (size_t) -1) &&
(find3 != NULL) && (find3[0] != '\0') &&
(repl3 != NULL) && (repl3[0] != '\0'))
{
size_t ret2 = StringReplace(buf, buf_size, find3, repl3);
ret = MAX(ret, ret2);
}
/* Zero is returned only if all of the above were zero. */
return ret;
}
/**
* Remove trailing FILE_SEPARATOR, unless we're referring to root dir: '/' or 'a:\'
*/
bool PathRemoveTrailingSlash(char *s, size_t s_len)
{
char *first_separator = strchr(s, FILE_SEPARATOR);
if (first_separator != NULL &&
s[s_len-1] == FILE_SEPARATOR &&
&s[s_len-1] != first_separator)
{
s[s_len-1] = '\0';
return true;
}
return false;
}
/**
* Append a trailing FILE_SEPARATOR if it's not there.
*/
bool PathAppendTrailingSlash(char *s, size_t s_len)
{
if (s_len > 0 && s[s_len-1] != FILE_SEPARATOR)
{
s[s_len] = FILE_SEPARATOR;
s[s_len+1] = '\0';
return true;
}
return false;
}
/* We use this instead of IsAbsoluteFileName() which also checks for
* quotes. There is no meaning in receiving quoted strings over the
* network. */
static bool PathIsAbsolute(const char *s)
{
bool result = false;
#if defined(__MINGW32__)
if (isalpha(s[0]) && (s[1] == ':') && (s[2] == FILE_SEPARATOR))
{
result = true; /* A:\ */
}
else /* \\ */
{
result = (s[0] == FILE_SEPARATOR && s[1] == FILE_SEPARATOR);
}
#else
if (s[0] == FILE_SEPARATOR) /* / */
{
result = true;
}
#endif
return result;
}
/**
* If #path is relative, expand the first part accorting to #shortcuts, doing
* any replacements of special variables "$(connection.*)" on the way, with
* the provided #ipaddr, #hostname, #key.
*
* @return the length of the new string or 0 if no replace took place. -1 in
* case of overflow.
*/
size_t ShortcutsExpand(char *path, size_t path_size,
const StringMap *shortcuts,
const char *ipaddr, const char *hostname,
const char *key)
{
char dst[path_size];
size_t path_len = strlen(path);
if (path_len == 0)
{
UnexpectedError("ShortcutsExpand: 0 length string!");
return (size_t) -1;
}
if (!PathIsAbsolute(path))
{
char *separ = strchr(path, FILE_SEPARATOR);
size_t first_part_len;
if (separ != NULL)
{
first_part_len = separ - path;
assert(first_part_len < path_len);
}
else
{
first_part_len = path_len;
}
size_t second_part_len = path_len - first_part_len;
/* '\0'-terminate first_part, do StringMapGet(), undo '\0'-term */
char separ_char = path[first_part_len];
path[first_part_len] = '\0';
char *replacement = StringMapGet(shortcuts, path);
path[first_part_len] = separ_char;
/* Either the first_part ends with separator, or its all the string */
assert(separ_char == FILE_SEPARATOR ||
separ_char == '\0');
if (replacement != NULL) /* we found a shortcut */
{
size_t replacement_len = strlen(replacement);
if (replacement_len + 1 > path_size)
{
goto err_too_long;
}
/* Replacement path for shortcut was found, but it may contain
* special variables such as $(connection.ip), that we also need
* to expand. */
/* TODO if StrAnyStr(replacement, "$(connection.ip)", "$(connection.hostname)", "$(connection.key)") */
char replacement_expanded[path_size];
memcpy(replacement_expanded, replacement, replacement_len + 1);
size_t ret =
ReplaceSpecialVariables(replacement_expanded, sizeof(replacement_expanded),
"$(connection.ip)", ipaddr,
"$(connection.hostname)", hostname,
"$(connection.key)", key);
size_t replacement_expanded_len;
/* (ret == -1) is checked later. */
if (ret == 0) /* No expansion took place */
{
replacement_expanded_len = replacement_len;
}
else
{
replacement_expanded_len = ret;
}
size_t dst_len = replacement_expanded_len + second_part_len;
if (ret == (size_t) -1 || dst_len + 1 > path_size)
{
goto err_too_long;
}
/* Assemble final result. */
memcpy(dst, replacement_expanded, replacement_expanded_len);
/* Second part may be empty, then this only copies '\0'. */
memcpy(&dst[replacement_expanded_len], &path[first_part_len],
second_part_len + 1);
Log(LOG_LEVEL_DEBUG,
"ShortcutsExpand: Path '%s' became: %s",
path, dst);
/* Copy back to path. */
memcpy(path, dst, dst_len + 1);
return dst_len;
}
}
/* No expansion took place, either because path was absolute, or because
* no shortcut was found. */
return 0;
err_too_long:
Log(LOG_LEVEL_INFO, "Path too long after shortcut expansion!");
return (size_t) -1;
}
/**
* Canonicalize a path, ensure it is absolute, and resolve all symlinks.
* In detail:
*
* 1. MinGW: Translate to windows-compatible: slashes to FILE_SEPARATOR
* and uppercase to lowercase.
* 2. Ensure the path is absolute.
* 3. Resolve symlinks, resolve '.' and '..' and remove double '/'
* WARNING this will currently fail if file does not exist,
* returning -1 and setting errno==ENOENT!
*
* @note trailing slash is left as is if it's there.
* @note #reqpath is written in place (if success was returned). It is always
* an absolute path.
* @note #reqpath is invalid to be of zero length.
* @note #reqpath_size must be at least PATH_MAX.
*
* @return the length of #reqpath after preprocessing. In case of error
* return (size_t) -1.
*/
size_t PreprocessRequestPath(char *reqpath, size_t reqpath_size)
{
errno = 0; /* on return, errno might be set from realpath() */
char dst[reqpath_size];
size_t reqpath_len = strlen(reqpath);
if (reqpath_len == 0)
{
UnexpectedError("PreprocessRequestPath: 0 length string!");
return (size_t) -1;
}
/* Translate all slashes to backslashes on Windows so that all the rest
* of work is done using FILE_SEPARATOR. THIS HAS TO BE FIRST. */
#if defined(__MINGW32__)
{
char *p = reqpath;
while ((p = strchr(p, '/')) != NULL)
{
*p = FILE_SEPARATOR;
}
/* Also convert everything to lowercase. */
ToLowerStrInplace(reqpath);
}
#endif
if (!PathIsAbsolute(reqpath))
{
Log(LOG_LEVEL_INFO, "Relative paths are not allowed: %s", reqpath);
return (size_t) -1;
}
/* TODO replace realpath with Solaris' resolvepath(), in all
* platforms. That one does not check for existence, just resolves
* symlinks and canonicalises. Ideally we would want the following:
*
* PathResolve(dst, src, dst_size, basedir);
*
* - It prepends basedir if path relative (could be the shortcut)
* - It compresses double '/', '..', '.'
* - It follows each component of the path replacing symlinks
* - errno = ENOENT if path component does not exist, but keeps
* compressing path anyway.
* - Leaves trailing slash as it was passed to it.
* OR appends it depending on last component ISDIR.
*/
assert(sizeof(dst) >= PATH_MAX); /* needed for realpath() */
char *p = realpath(reqpath, dst);
if (p == NULL)
{
/* TODO If path does not exist try to canonicalise only directory. INSECURE?*/
/* if (errno == ENOENT) */
/* { */
/* } */
struct stat statbuf;
if ((lstat(reqpath, &statbuf) == 0) && S_ISLNK(statbuf.st_mode))
{
Log(LOG_LEVEL_VERBOSE, "Requested file is a dead symbolic link (filename: %s)", reqpath);
strlcpy(dst, reqpath, CF_BUFSIZE);
}
else
{
Log(LOG_LEVEL_INFO,
"Failed to canonicalise filename '%s' (realpath: %s)",
reqpath, GetErrorStr());
return (size_t) -1;
}
}
size_t dst_len = strlen(dst);
/* Some realpath()s remove trailing '/' even for dirs! Put it back if
* original request had it. */
if (reqpath[reqpath_len - 1] == FILE_SEPARATOR &&
dst[dst_len - 1] != FILE_SEPARATOR)
{
if (dst_len + 2 > sizeof(dst))
{
Log(LOG_LEVEL_INFO, "Error, path too long: %s", reqpath);
return (size_t) -1;
}
PathAppendTrailingSlash(dst, dst_len);
dst_len++;
}
memcpy(reqpath, dst, dst_len + 1);
reqpath_len = dst_len;
return reqpath_len;
}
/**
* Set conn->uid (and conn->sid on Windows).
*/
void SetConnIdentity(ServerConnectionState *conn, const char *username)
{
size_t username_len = strlen(username);
conn->uid = CF_UNKNOWN_OWNER;
conn->username[0] = '\0';
if (username_len < sizeof(conn->username))
{
memcpy(conn->username, username, username_len + 1);
}
bool is_root = strcmp(conn->username, "root") == 0;
if (is_root)
{
/* If the remote user identifies himself as root, even on Windows
* cf-serverd must grant access to all files. uid==0 is checked later
* in TranferRights() for that. */
conn->uid = 0;
}
#ifdef __MINGW32__ /* NT uses security identifier instead of uid */
if (!NovaWin_UserNameToSid(conn->username, (SID *) conn->sid,
CF_MAXSIDSIZE, !is_root))
{
memset(conn->sid, 0, CF_MAXSIDSIZE); /* is invalid sid - discarded */
}
#else /* UNIX - common path */
if (conn->uid == CF_UNKNOWN_OWNER) /* skip looking up UID for root */
{
static pthread_mutex_t pwnam_mtx = PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP;
struct passwd *pw = NULL;
if (ThreadLock(&pwnam_mtx))
{
/* TODO Redmine#7643: looking up the UID is expensive and should
* not be needed, since today's agent machine VS hub most probably
* do not share the accounts. */
pw = getpwnam(conn->username);
if (pw != NULL)
{
conn->uid = pw->pw_uid;
}
ThreadUnlock(&pwnam_mtx);
}
}
#endif
}
static bool CharsetAcceptable(const char *s, size_t s_len)
{
const char *ACCEPT =
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_:";
size_t acceptable_chars = strspn(s, ACCEPT);
if (s_len == 0)
{
s_len = strlen(s);
}
if (acceptable_chars < s_len)
{
Log(LOG_LEVEL_INFO,
"llegal character in column %zu of: %s",
acceptable_chars, s);
return false;
}
return true;
}
/**
* @param #args_start is a comma separated list of words, which may be
* prefixed with spaces and suffixed with spaces and other
* words. Example: " asd,fgh,jk blah". In this example the
* list has 3 words, and "blah" is not one of them.
*
* Both #args_start and #args_len are in-out parameters.
* At the end of execution #args_start returns the real start of the list, and
* #args_len the real length.
*/
static bool AuthorizeDelimitedArgs(const ServerConnectionState *conn,
struct acl *acl,
char **args_start, size_t *args_len)
{
char *s;
size_t s_len, skip;
assert(args_start != NULL);
assert(args_len != NULL);
/* Give the name s and s_len purely for ease of use. */
s_len = *args_len;
s = *args_start;
/* Skip spaces in the beginning of argument list. */
skip = strspn(s, " \t");
s += skip;
if (s_len == 0) /* if end was not given, find it */
{
s_len = strcspn(s, " \t");
}
else /* if end was given */
{
s_len = (skip <= s_len) ? (s_len - skip) : 0;
}
/* Admit, unless any token fails to be authorised. */
bool admit = true;
if (s_len > 0)
{
const char tmp_c = s[s_len];
s[s_len] = '\0';
/* Iterate over comma-separated list. */
char *token = &s[0];
while (token < &s[s_len] && admit)
{
char *token_end = strchrnul(token, ',');
const char tmp_sep = *token_end;
*token_end = '\0';
if (!CharsetAcceptable(token, 0) ||
!acl_CheckRegex(acl, token,
conn->ipaddr, conn->revdns,
KeyPrintableHash(conn->conn_info->remote_key),
conn->username))
{
Log(LOG_LEVEL_INFO, "Access denied to: %s", token);
admit = false; /* EARLY RETURN */
}
*token_end = tmp_sep;
token = token_end + 1;
}
s[s_len] = tmp_c;
}
*args_start = s;
*args_len = s_len;
return admit;
}
/**
* @return #true if the connection should remain open for next requests, or
* #false if the server should actively close it - for example when
* protocol errors have occurred.
*/
bool DoExec2(const EvalContext *ctx,
ServerConnectionState *conn,
char *exec_args,
char *sendbuf, size_t sendbuf_size)
{
/* STEP 0: Verify cfruncommand was successfully configured. */
if (NULL_OR_EMPTY(CFRUNCOMMAND))
{
Log(LOG_LEVEL_INFO, "EXEC denied due to empty cfruncommand");
RefuseAccess(conn, "EXEC");
return false;
}
/* STEP 1: Resolve and check permissions of CFRUNCOMMAND's arg0. IT is
* done now and not at configuration time, as the file stat may
* have changed since then. */
{
char arg0[PATH_MAX];
if (CommandArg0_bound(arg0, CFRUNCOMMAND, sizeof(arg0)) == (size_t) -1 ||
PreprocessRequestPath(arg0, sizeof(arg0)) == (size_t) -1)
{
Log(LOG_LEVEL_INFO, "EXEC failed, invalid cfruncommand arg0");
RefuseAccess(conn, "EXEC");
return false;
}
/* Check body server access_rules, whether arg0 is authorized. */
/* TODO EXEC should not just use paths_acl access control, but
* specific "exec_path" ACL. Then different command execution could be
* allowed per host, and the host could even set argv[0] in his EXEC
* request, rather than only the arguments. */
if (acl_CheckPath(paths_acl, arg0,
conn->ipaddr, conn->revdns,
KeyPrintableHash(conn->conn_info->remote_key))
== false)
{
Log(LOG_LEVEL_INFO, "EXEC denied due to ACL for file: %s", arg0);
RefuseAccess(conn, "EXEC");
return false;
}
}
/* STEP 2: Check body server control "allowusers" */
if (!AllowedUser(conn->username))
{
Log(LOG_LEVEL_INFO, "EXEC denied due to not allowed user: %s",
conn->username);
RefuseAccess(conn, "EXEC");
return false;
}
/* STEP 3: This matches cf-runagent -s class1,class2 against classes
* set during cf-serverd's policy evaluation. */
if (!MatchClasses(ctx, conn))
{
snprintf(sendbuf, sendbuf_size,
"EXEC denied due to failed class match (check cf-serverd verbose output)");
Log(LOG_LEVEL_INFO, "%s", sendbuf);
SendTransaction(conn->conn_info, sendbuf, 0, CF_DONE);
return true;
}
/* STEP 4: Parse and authorise the EXEC arguments, which will be used as
* arguments to CFRUNCOMMAND. Currently we only accept
* [ -D classlist ] and [ -b bundlesequence ] arguments. */
char cmdbuf[CF_BUFSIZE] = "";
size_t cmdbuf_len = 0;
assert(sizeof(CFRUNCOMMAND) <= sizeof(cmdbuf));
StrCat(cmdbuf, sizeof(cmdbuf), &cmdbuf_len, CFRUNCOMMAND, 0);
exec_args += strspn(exec_args, " \t"); /* skip spaces */
while (exec_args[0] != '\0')
{
if (strncmp(exec_args, "-D", 2) == 0)
{
exec_args += 2;
char *classlist = exec_args;
size_t classlist_len = 0;
bool allow = AuthorizeDelimitedArgs(conn, roles_acl,
&classlist, &classlist_len);
if (!allow)
{
snprintf(sendbuf, sendbuf_size,
"EXEC denied role activation (check cf-serverd verbose output)");
Log(LOG_LEVEL_INFO, "%s", sendbuf);
SendTransaction(conn->conn_info, sendbuf, 0, CF_DONE);
return true;
}
if (classlist_len > 0)
{
/* Append "-D classlist" to cfruncommand. */
StrCat(cmdbuf, sizeof(cmdbuf), &cmdbuf_len,
" -D ", 0);
StrCat(cmdbuf, sizeof(cmdbuf), &cmdbuf_len,
classlist, classlist_len);
}
exec_args = classlist + classlist_len;
}
else if (strncmp(exec_args, "-b", 2) == 0)
{
exec_args += 2;
char *bundlesequence = exec_args;
size_t bundlesequence_len = 0;
bool allow = AuthorizeDelimitedArgs(conn, bundles_acl,
&bundlesequence,
&bundlesequence_len);
if (!allow)
{
snprintf(sendbuf, sendbuf_size,
"EXEC denied bundle activation (check cf-serverd verbose output)");
Log(LOG_LEVEL_INFO, "%s", sendbuf);
SendTransaction(conn->conn_info, sendbuf, 0, CF_DONE);
return true;
}
if (bundlesequence_len > 0)
{
/* Append "--bundlesequence bundlesequence" to cfruncommand. */
StrCat(cmdbuf, sizeof(cmdbuf), &cmdbuf_len,
" --bundlesequence ", 0);
StrCat(cmdbuf, sizeof(cmdbuf), &cmdbuf_len,
bundlesequence, bundlesequence_len);
}
exec_args = bundlesequence + bundlesequence_len;
}
else /* disallowed parameter */
{
snprintf(sendbuf, sendbuf_size,
"EXEC denied: invalid arguments: %s",
exec_args);
Log(LOG_LEVEL_INFO, "%s", sendbuf);
SendTransaction(conn->conn_info, sendbuf, 0, CF_DONE);
return true;
}
exec_args += strspn(exec_args, " \t"); /* skip spaces */
}
if (cmdbuf_len >= sizeof(cmdbuf))
{
snprintf(sendbuf, sendbuf_size,
"EXEC denied: too long (%zu B) command: %s",
cmdbuf_len, cmdbuf);
Log(LOG_LEVEL_INFO, "%s", sendbuf);
SendTransaction(conn->conn_info, sendbuf, 0, CF_DONE);
return false;
}
/* STEP 5: RUN CFRUNCOMMAND. */
snprintf(sendbuf, sendbuf_size,
"cf-serverd executing cfruncommand: %s\n",
cmdbuf);
SendTransaction(conn->conn_info, sendbuf, 0, CF_DONE);
Log(LOG_LEVEL_INFO, "%s", sendbuf);
FILE *pp = cf_popen(cmdbuf, "r", true);
if (pp == NULL)
{
snprintf(sendbuf, sendbuf_size,
"Unable to run '%s' (pipe: %s)",
cmdbuf, GetErrorStr());
Log(LOG_LEVEL_INFO, "%s", sendbuf);
SendTransaction(conn->conn_info, sendbuf, 0, CF_DONE);
return false;
}
size_t line_size = CF_BUFSIZE;
char *line = xmalloc(line_size);
while (true)
{
ssize_t res = CfReadLine(&line, &line_size, pp);
if (res == -1)
{
if (!feof(pp))
{
/* Error reading, discard all unconsumed input before
* aborting - linux-specific! */
fflush(pp);
}
break;
}
/* NOTICE: we can't SendTransaction() overlong strings, and we need to
* prepend and append to the string. */
size_t line_len = strlen(line);
if (line_len >= sendbuf_size - 5)
{
line[sendbuf_size - 5] = '\0';
}
/* Prefixing output with "> " and postfixing with '\n' is new
* behaviour as of 3.7.0. Prefixing happens to avoid zero-length
* transaction packet. */
/* Old cf-runagent versions do not append a newline, so we must do
* it here. New ones do though, so TODO deprecate. */
xsnprintf(sendbuf, sendbuf_size, "> %s\n", line);
if (SendTransaction(conn->conn_info, sendbuf, 0, CF_DONE) == -1)
{
Log(LOG_LEVEL_INFO,
"Sending failed, aborting EXEC (send: %s)",
GetErrorStr());
break;
}
}
free(line);
cf_pclose(pp);
return true;
}
cfengine-3.12.1/cf-serverd/server_transform.h 0000644 0000000 0000000 00000002322 13377750461 021200 0 ustar 00root root 0000000 0000000 /*
Copyright 2018 Northern.tech AS
This file is part of CFEngine 3 - written and maintained by Northern.tech AS.
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; version 3.
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, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
To the extent this program is licensed as part of the Enterprise
versions of CFEngine, the applicable Commercial Open Source License
(COSL) may apply to this file if you as a licensee so wish it. See
included file COSL.txt.
*/
#ifndef CFENGINE_SERVER_TRANSFORM_H
#define CFENGINE_SERVER_TRANSFORM_H
#include
#include
void Summarize(void);
void KeepPromises(EvalContext *ctx, const Policy *policy, GenericAgentConfig *config);
#endif
cfengine-3.12.1/cf-serverd/server_access.h 0000644 0000000 0000000 00000011513 13377750461 020430 0 ustar 00root root 0000000 0000000 /*
Copyright 2018 Northern.tech AS
This file is part of CFEngine 3 - written and maintained by Northern.tech AS.
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; version 3.
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, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
To the extent this program is licensed as part of the Enterprise
versions of CFEngine, the applicable Commercial Open Source License
(COSL) may apply to this file if you as a licensee so wish it. See
included file COSL.txt.
*/
#ifndef CFENGINE_ACCESS_H
#define CFENGINE_ACCESS_H
#include
#include /* StringMap */
#include "strlist.h" /* StrList */
/**
* Access control list referring to one resource, e.g. path, class, variable,
* literal, bundle.
*
* @note: Each strlist might be NULL, which is equivalent to having 0
* elements.
*
* @note: Currently these lists are binary searched, so after filling them up
* make sure you call StrList_Sort() to sort them.
*/
struct admitdeny_acl
{
StrList *ips; /* admit_ips, deny_ips */
StrList *hostnames; /* admit_hostnames, deny_hostnames */
StrList *keys; /* admit_keys, deny_keys */
StrList *usernames; /* currently used only in roles access promise */
};
/**
* This is a list of all resorce ACLs for one resource. E.g. for resource_type
* == path, this should contain a list of all paths together with a list of
* ACLs (struct resource_acl) referring to the relevant path.
*
* @note Currently this list of resource_names may be binary searched so it
* must be sorted once populated.
*
* @WARNING Remember to store directories *always* with traling '/', else they
* won't match for children dirs (on purpose, and this functionality
* was built into StrList_SearchLongestPrefix()).
*/
struct acl
{
// enum acl_type resource_type;
size_t len; /* Length of resource_names,acls[] */
size_t alloc_len; /* Used for realloc() economy */
StrList *resource_names; /* paths, class names, variables etc */
struct resource_acl
{
struct admitdeny_acl admit;
struct admitdeny_acl deny;
} acls[];
};
/* These acls are set on server startup or when promises change, and are
* read-only for the rest of their life, thus are thread-safe. */
/* The paths_acl should be populated with directories having a trailing '/'
* to be able to tell apart from files. */
extern struct acl *paths_acl;
extern struct acl *classes_acl; /* remoteclassesmatching */
extern struct acl *vars_acl; /* remotescalar */
extern struct acl *literals_acl;
extern struct acl *query_acl; /* reporting */
extern struct acl *bundles_acl; /* cf-runagent connections*/
/* Roles ACL contains classes regexes under resource_names, but currently only
* lists of admit usernames under the admitdeny_acl, no
* ips,hostnames,keys. It's used for the "roles" access promise. TODO convert
* to a common access promise with resource_type=>"role". */
extern struct acl *roles_acl; /* cf-runagent connections */
size_t ReplaceSpecialVariables(char *buf, size_t buf_size,
const char *find1, const char *repl1,
const char *find2, const char *repl2,
const char *find3, const char *repl3);
size_t acl_SortedInsert(struct acl **a, const char *handle);
void acl_Free(struct acl *a);
void acl_Summarise(const struct acl *acl, const char *title);
/* TODO instead of getting all kind of different parameters like
* ipaddr,hostname,key, the following functions should get a
* "struct peer_id" with all this plus more. */
bool acl_CheckExact(const struct acl *acl, const char *req_string,
const char *ipaddr, const char *hostname,
const char *key);
bool acl_CheckPath(const struct acl *acl, const char *reqpath,
const char *ipaddr, const char *hostname,
const char *key);
bool acl_CheckRegex(const struct acl *acl, const char *req_string,
const char *ipaddr, const char *hostname,
const char *key, const char *username);
#endif
cfengine-3.12.1/cf-serverd/Makefile.in 0000644 0000000 0000000 00000070317 13377750516 017505 0 ustar 00root root 0000000 0000000 # Makefile.in generated by automake 1.14.1 from Makefile.am.
# @configure_input@
# Copyright (C) 1994-2013 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
# PARTICULAR PURPOSE.
@SET_MAKE@
VPATH = @srcdir@
am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
am__make_running_with_option = \
case $${target_option-} in \
?) ;; \
*) echo "am__make_running_with_option: internal error: invalid" \
"target option '$${target_option-}' specified" >&2; \
exit 1;; \
esac; \
has_opt=no; \
sane_makeflags=$$MAKEFLAGS; \
if $(am__is_gnu_make); then \
sane_makeflags=$$MFLAGS; \
else \
case $$MAKEFLAGS in \
*\\[\ \ ]*) \
bs=\\; \
sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
| sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
esac; \
fi; \
skip_next=no; \
strip_trailopt () \
{ \
flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
}; \
for flg in $$sane_makeflags; do \
test $$skip_next = yes && { skip_next=no; continue; }; \
case $$flg in \
*=*|--*) continue;; \
-*I) strip_trailopt 'I'; skip_next=yes;; \
-*I?*) strip_trailopt 'I';; \
-*O) strip_trailopt 'O'; skip_next=yes;; \
-*O?*) strip_trailopt 'O';; \
-*l) strip_trailopt 'l'; skip_next=yes;; \
-*l?*) strip_trailopt 'l';; \
-[dEDm]) skip_next=yes;; \
-[JT]) skip_next=yes;; \
esac; \
case $$flg in \
*$$target_option*) has_opt=yes; break;; \
esac; \
done; \
test $$has_opt = yes
am__make_dryrun = (target_option=n; $(am__make_running_with_option))
am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
pkgdatadir = $(datadir)/@PACKAGE@
pkgincludedir = $(includedir)/@PACKAGE@
pkglibdir = $(libdir)/@PACKAGE@
pkglibexecdir = $(libexecdir)/@PACKAGE@
am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
install_sh_DATA = $(install_sh) -c -m 644
install_sh_PROGRAM = $(install_sh) -c
install_sh_SCRIPT = $(install_sh) -c
INSTALL_HEADER = $(INSTALL_DATA)
transform = $(program_transform_name)
NORMAL_INSTALL = :
PRE_INSTALL = :
POST_INSTALL = :
NORMAL_UNINSTALL = :
PRE_UNINSTALL = :
POST_UNINSTALL = :
build_triplet = @build@
host_triplet = @host@
target_triplet = @target@
@BUILTIN_EXTENSIONS_FALSE@bin_PROGRAMS = cf-serverd$(EXEEXT)
subdir = cf-serverd
DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
$(top_srcdir)/depcomp
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/m4/acinclude.m4 \
$(top_srcdir)/m4/adl_recursive_eval.m4 \
$(top_srcdir)/m4/cf3_check_proper_func.m4 \
$(top_srcdir)/m4/cf3_path_root_prog.m4 \
$(top_srcdir)/m4/cf3_with_library.m4 \
$(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
$(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
$(top_srcdir)/m4/lt~obsolete.m4 \
$(top_srcdir)/m4/old-autoconf.m4 $(top_srcdir)/m4/snprintf.m4 \
$(top_srcdir)/m4/strndup.m4 $(top_srcdir)/m4/tar.m4 \
$(top_srcdir)/m4/cf3_gcc_flags.m4 \
$(top_srcdir)/m4/cf3_platforms.m4 $(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4)
mkinstalldirs = $(install_sh) -d
CONFIG_HEADER = $(top_builddir)/libutils/config.h
CONFIG_CLEAN_FILES =
CONFIG_CLEAN_VPATH_FILES =
LTLIBRARIES = $(noinst_LTLIBRARIES)
libcf_serverd_la_DEPENDENCIES = ../libpromises/libpromises.la
am_libcf_serverd_la_OBJECTS = cf-serverd.lo \
cf-serverd-enterprise-stubs.lo cf-serverd-functions.lo \
server_common.lo server.lo server_transform.lo \
server_classic.lo server_tls.lo server_access.lo strlist.lo
libcf_serverd_la_OBJECTS = $(am_libcf_serverd_la_OBJECTS)
AM_V_lt = $(am__v_lt_@AM_V@)
am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
am__v_lt_0 = --silent
am__v_lt_1 =
am__installdirs = "$(DESTDIR)$(bindir)"
PROGRAMS = $(bin_PROGRAMS)
cf_serverd_SOURCES = cf-serverd.c
cf_serverd_OBJECTS = cf_serverd-cf-serverd.$(OBJEXT)
@BUILTIN_EXTENSIONS_FALSE@cf_serverd_DEPENDENCIES = libcf-serverd.la
cf_serverd_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=link $(CCLD) $(cf_serverd_CFLAGS) \
$(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
AM_V_P = $(am__v_P_@AM_V@)
am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
am__v_P_0 = false
am__v_P_1 = :
AM_V_GEN = $(am__v_GEN_@AM_V@)
am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
am__v_GEN_0 = @echo " GEN " $@;
am__v_GEN_1 =
AM_V_at = $(am__v_at_@AM_V@)
am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
am__v_at_0 = @
am__v_at_1 =
DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/libutils
depcomp = $(SHELL) $(top_srcdir)/depcomp
am__depfiles_maybe = depfiles
am__mv = mv -f
COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
$(AM_CFLAGS) $(CFLAGS)
AM_V_CC = $(am__v_CC_@AM_V@)
am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
am__v_CC_0 = @echo " CC " $@;
am__v_CC_1 =
CCLD = $(CC)
LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
$(AM_LDFLAGS) $(LDFLAGS) -o $@
AM_V_CCLD = $(am__v_CCLD_@AM_V@)
am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
am__v_CCLD_0 = @echo " CCLD " $@;
am__v_CCLD_1 =
SOURCES = $(libcf_serverd_la_SOURCES) cf-serverd.c
DIST_SOURCES = $(libcf_serverd_la_SOURCES) cf-serverd.c
am__can_run_installinfo = \
case $$AM_UPDATE_INFO_DIR in \
n|no|NO) false;; \
*) (install-info --version) >/dev/null 2>&1;; \
esac
am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
# Read a list of newline-separated strings from the standard input,
# and print each of them once, without duplicates. Input order is
# *not* preserved.
am__uniquify_input = $(AWK) '\
BEGIN { nonempty = 0; } \
{ items[$$0] = 1; nonempty = 1; } \
END { if (nonempty) { for (i in items) print i; }; } \
'
# Make sure the list of sources is unique. This is necessary because,
# e.g., the same source file might be shared among _SOURCES variables
# for different programs/libraries.
am__define_uniq_tagged_files = \
list='$(am__tagged_files)'; \
unique=`for i in $$list; do \
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
done | $(am__uniquify_input)`
ETAGS = etags
CTAGS = ctags
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
ACLOCAL = @ACLOCAL@
AMTAR = @AMTAR@
AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
AR = @AR@
AUTOCONF = @AUTOCONF@
AUTOHEADER = @AUTOHEADER@
AUTOMAKE = @AUTOMAKE@
AWK = @AWK@
CC = @CC@
CCDEPMODE = @CCDEPMODE@
CFLAGS = @CFLAGS@
CORE_CFLAGS = @CORE_CFLAGS@
CORE_CPPFLAGS = @CORE_CPPFLAGS@
CORE_LDFLAGS = @CORE_LDFLAGS@
CORE_LIBS = @CORE_LIBS@
CPP = @CPP@
CPPFLAGS = @CPPFLAGS@
CYGPATH_W = @CYGPATH_W@
DEFS = @DEFS@
DEPDIR = @DEPDIR@
DLLTOOL = @DLLTOOL@
DSYMUTIL = @DSYMUTIL@
DUMPBIN = @DUMPBIN@
ECHO_C = @ECHO_C@
ECHO_N = @ECHO_N@
ECHO_T = @ECHO_T@
EGREP = @EGREP@
EXEEXT = @EXEEXT@
FGREP = @FGREP@
GETCONF = @GETCONF@
GETLOADAVG_LIBS = @GETLOADAVG_LIBS@
GREP = @GREP@
HOSTNAME = @HOSTNAME@
INIT_D_PATH = @INIT_D_PATH@
INSTALL = @INSTALL@
INSTALL_DATA = @INSTALL_DATA@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_SCRIPT = @INSTALL_SCRIPT@
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
KMEM_GROUP = @KMEM_GROUP@
LCOV = @LCOV@
LCOV_GENHTML = @LCOV_GENHTML@
LD = @LD@
LDFLAGS = @LDFLAGS@
LEX = @LEX@
LEXLIB = @LEXLIB@
LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
LIBACL_CFLAGS = @LIBACL_CFLAGS@
LIBACL_CPPFLAGS = @LIBACL_CPPFLAGS@
LIBACL_LDFLAGS = @LIBACL_LDFLAGS@
LIBACL_LIBS = @LIBACL_LIBS@
LIBACL_PATH = @LIBACL_PATH@
LIBCURL_CFLAGS = @LIBCURL_CFLAGS@
LIBCURL_CPPFLAGS = @LIBCURL_CPPFLAGS@
LIBCURL_LDFLAGS = @LIBCURL_LDFLAGS@
LIBCURL_LIBS = @LIBCURL_LIBS@
LIBCURL_PATH = @LIBCURL_PATH@
LIBOBJS = @LIBOBJS@
LIBS = @LIBS@
LIBTOOL = @LIBTOOL@
LIBVIRT_CFLAGS = @LIBVIRT_CFLAGS@
LIBVIRT_CPPFLAGS = @LIBVIRT_CPPFLAGS@
LIBVIRT_LDFLAGS = @LIBVIRT_LDFLAGS@
LIBVIRT_LIBS = @LIBVIRT_LIBS@
LIBVIRT_PATH = @LIBVIRT_PATH@
LIBXML2_CFLAGS = @LIBXML2_CFLAGS@
LIBXML2_CPPFLAGS = @LIBXML2_CPPFLAGS@
LIBXML2_LDFLAGS = @LIBXML2_LDFLAGS@
LIBXML2_LIBS = @LIBXML2_LIBS@
LIBXML2_PATH = @LIBXML2_PATH@
LIBYAML_CFLAGS = @LIBYAML_CFLAGS@
LIBYAML_CPPFLAGS = @LIBYAML_CPPFLAGS@
LIBYAML_LDFLAGS = @LIBYAML_LDFLAGS@
LIBYAML_LIBS = @LIBYAML_LIBS@
LIBYAML_PATH = @LIBYAML_PATH@
LIPO = @LIPO@
LMDB_CFLAGS = @LMDB_CFLAGS@
LMDB_CPPFLAGS = @LMDB_CPPFLAGS@
LMDB_LDFLAGS = @LMDB_LDFLAGS@
LMDB_LIBS = @LMDB_LIBS@
LMDB_PATH = @LMDB_PATH@
LN_S = @LN_S@
LTLIBOBJS = @LTLIBOBJS@
MAINT = @MAINT@
MAKEINFO = @MAKEINFO@
MANIFEST_TOOL = @MANIFEST_TOOL@
MKDIR_P = @MKDIR_P@
MYSQL_CFLAGS = @MYSQL_CFLAGS@
MYSQL_CPPFLAGS = @MYSQL_CPPFLAGS@
MYSQL_LDFLAGS = @MYSQL_LDFLAGS@
MYSQL_LIBS = @MYSQL_LIBS@
MYSQL_PATH = @MYSQL_PATH@
NEED_SETGID = @NEED_SETGID@
NM = @NM@
NMEDIT = @NMEDIT@
OBJDUMP = @OBJDUMP@
OBJEXT = @OBJEXT@
OPENSSL_CFLAGS = @OPENSSL_CFLAGS@
OPENSSL_CPPFLAGS = @OPENSSL_CPPFLAGS@
OPENSSL_LDFLAGS = @OPENSSL_LDFLAGS@
OPENSSL_LIBS = @OPENSSL_LIBS@
OPENSSL_PATH = @OPENSSL_PATH@
OS_ENVIRONMENT_PATH = @OS_ENVIRONMENT_PATH@
OTOOL = @OTOOL@
OTOOL64 = @OTOOL64@
PACKAGE = @PACKAGE@
PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
PACKAGE_NAME = @PACKAGE_NAME@
PACKAGE_STRING = @PACKAGE_STRING@
PACKAGE_TARNAME = @PACKAGE_TARNAME@
PACKAGE_URL = @PACKAGE_URL@
PACKAGE_VERSION = @PACKAGE_VERSION@
PAM_CFLAGS = @PAM_CFLAGS@
PAM_CPPFLAGS = @PAM_CPPFLAGS@
PAM_LDFLAGS = @PAM_LDFLAGS@
PAM_LIBS = @PAM_LIBS@
PAM_PATH = @PAM_PATH@
PATH_SEPARATOR = @PATH_SEPARATOR@
PCRE_CFLAGS = @PCRE_CFLAGS@
PCRE_CPPFLAGS = @PCRE_CPPFLAGS@
PCRE_LDFLAGS = @PCRE_LDFLAGS@
PCRE_LIBS = @PCRE_LIBS@
PCRE_PATH = @PCRE_PATH@
PERL = @PERL@
POSTGRESQL_CFLAGS = @POSTGRESQL_CFLAGS@
POSTGRESQL_CPPFLAGS = @POSTGRESQL_CPPFLAGS@
POSTGRESQL_LDFLAGS = @POSTGRESQL_LDFLAGS@
POSTGRESQL_LIBS = @POSTGRESQL_LIBS@
POSTGRESQL_PATH = @POSTGRESQL_PATH@
PTHREAD_CC = @PTHREAD_CC@
PTHREAD_CFLAGS = @PTHREAD_CFLAGS@
PTHREAD_LIBS = @PTHREAD_LIBS@
QDBM_CFLAGS = @QDBM_CFLAGS@
QDBM_CPPFLAGS = @QDBM_CPPFLAGS@
QDBM_LDFLAGS = @QDBM_LDFLAGS@
QDBM_LIBS = @QDBM_LIBS@
QDBM_PATH = @QDBM_PATH@
RANLIB = @RANLIB@
SED = @SED@
SET_MAKE = @SET_MAKE@
SHELL = @SHELL@
STRIP = @STRIP@
SYSTEMD_SERVICE_PATH = @SYSTEMD_SERVICE_PATH@
TOKYOCABINET_CFLAGS = @TOKYOCABINET_CFLAGS@
TOKYOCABINET_CPPFLAGS = @TOKYOCABINET_CPPFLAGS@
TOKYOCABINET_LDFLAGS = @TOKYOCABINET_LDFLAGS@
TOKYOCABINET_LIBS = @TOKYOCABINET_LIBS@
TOKYOCABINET_PATH = @TOKYOCABINET_PATH@
VERSION = @VERSION@
YACC = @YACC@
YFLAGS = @YFLAGS@
abs_builddir = @abs_builddir@
abs_srcdir = @abs_srcdir@
abs_top_builddir = @abs_top_builddir@
abs_top_srcdir = @abs_top_srcdir@
ac_ct_AR = @ac_ct_AR@
ac_ct_CC = @ac_ct_CC@
ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
acx_pthread_config = @acx_pthread_config@
am__include = @am__include@
am__leading_dot = @am__leading_dot@
am__quote = @am__quote@
am__tar = @am__tar@
am__untar = @am__untar@
bindir = @bindir@
build = @build@
build_alias = @build_alias@
build_cpu = @build_cpu@
build_os = @build_os@
build_vendor = @build_vendor@
builddir = @builddir@
datadir = @datadir@
datarootdir = @datarootdir@
docdir = @docdir@
dvidir = @dvidir@
enable_builtin_extensions = @enable_builtin_extensions@
exec_prefix = @exec_prefix@
host = @host@
host_alias = @host_alias@
host_cpu = @host_cpu@
host_os = @host_os@
host_vendor = @host_vendor@
htmldir = @htmldir@
hw_cv_func_ctime_proper = @hw_cv_func_ctime_proper@
hw_cv_func_mkdir_proper = @hw_cv_func_mkdir_proper@
hw_cv_func_rename_proper = @hw_cv_func_rename_proper@
hw_cv_func_stat_proper = @hw_cv_func_stat_proper@
includedir = @includedir@
infodir = @infodir@
inputdir = @inputdir@
install_sh = @install_sh@
libdir = @libdir@
libexecdir = @libexecdir@
localedir = @localedir@
localstatedir = @localstatedir@
logdir = @logdir@
mandir = @mandir@
masterdir = @masterdir@
mkdir_p = @mkdir_p@
oldincludedir = @oldincludedir@
pdfdir = @pdfdir@
piddir = @piddir@
prefix = @prefix@
program_transform_name = @program_transform_name@
projlibdir = @projlibdir@
psdir = @psdir@
sbindir = @sbindir@
sharedstatedir = @sharedstatedir@
srcdir = @srcdir@
statedir = @statedir@
sysconfdir = @sysconfdir@
target = @target@
target_alias = @target_alias@
target_cpu = @target_cpu@
target_os = @target_os@
target_vendor = @target_vendor@
top_build_prefix = @top_build_prefix@
top_builddir = @top_builddir@
top_srcdir = @top_srcdir@
workdir = @workdir@
#
# Copyright 2018 Northern.tech AS
#
# This file is part of CFEngine 3 - written and maintained by Northern.tech AS.
#
# 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; version 3.
#
# 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, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
#
# To the extent this program is licensed as part of the Enterprise
# versions of CFEngine, the applicable Commercial Open Source License
# (COSL) may apply to this file if you as a licensee so wish it. See
# included file COSL.txt.
#
noinst_LTLIBRARIES = libcf-serverd.la
AM_CPPFLAGS = -I$(srcdir)/../libpromises -I$(srcdir)/../libutils \
-I$(srcdir)/../libcfnet \
-I$(srcdir)/../libenv \
$(OPENSSL_CPPFLAGS) \
$(PCRE_CPPFLAGS) \
$(ENTERPRISE_CPPFLAGS)
AM_CFLAGS = \
$(OPENSSL_CFLAGS) \
$(ENTERPRISE_CFLAGS)
libcf_serverd_la_LIBADD = ../libpromises/libpromises.la
libcf_serverd_la_SOURCES = \
cf-serverd.c \
cf-serverd-enterprise-stubs.c cf-serverd-enterprise-stubs.h \
cf-serverd-functions.c cf-serverd-functions.h \
server_common.c server_common.h \
server.c server.h \
server_transform.c server_transform.h \
server_classic.c server_classic.h \
server_tls.c server_tls.h \
server_access.c server_access.h \
strlist.c strlist.h
@BUILTIN_EXTENSIONS_FALSE@cf_serverd_CFLAGS = $(AM_CFLAGS)
@BUILTIN_EXTENSIONS_FALSE@cf_serverd_LDADD = libcf-serverd.la
CLEANFILES = *.gcno *.gcda
#
# Some basic clean ups
#
MOSTLYCLEANFILES = *~ *.orig *.rej
all: all-am
.SUFFIXES:
.SUFFIXES: .c .lo .o .obj
$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
@for dep in $?; do \
case '$(am__configure_deps)' in \
*$$dep*) \
( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
&& { if test -f $@; then exit 0; else break; fi; }; \
exit 1;; \
esac; \
done; \
echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu cf-serverd/Makefile'; \
$(am__cd) $(top_srcdir) && \
$(AUTOMAKE) --gnu cf-serverd/Makefile
.PRECIOUS: Makefile
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
@case '$?' in \
*config.status*) \
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
*) \
echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
esac;
$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(am__aclocal_m4_deps):
clean-noinstLTLIBRARIES:
-test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
@list='$(noinst_LTLIBRARIES)'; \
locs=`for p in $$list; do echo $$p; done | \
sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
sort -u`; \
test -z "$$locs" || { \
echo rm -f $${locs}; \
rm -f $${locs}; \
}
libcf-serverd.la: $(libcf_serverd_la_OBJECTS) $(libcf_serverd_la_DEPENDENCIES) $(EXTRA_libcf_serverd_la_DEPENDENCIES)
$(AM_V_CCLD)$(LINK) $(libcf_serverd_la_OBJECTS) $(libcf_serverd_la_LIBADD) $(LIBS)
install-binPROGRAMS: $(bin_PROGRAMS)
@$(NORMAL_INSTALL)
@list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \
if test -n "$$list"; then \
echo " $(MKDIR_P) '$(DESTDIR)$(bindir)'"; \
$(MKDIR_P) "$(DESTDIR)$(bindir)" || exit 1; \
fi; \
for p in $$list; do echo "$$p $$p"; done | \
sed 's/$(EXEEXT)$$//' | \
while read p p1; do if test -f $$p \
|| test -f $$p1 \
; then echo "$$p"; echo "$$p"; else :; fi; \
done | \
sed -e 'p;s,.*/,,;n;h' \
-e 's|.*|.|' \
-e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \
sed 'N;N;N;s,\n, ,g' | \
$(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \
{ d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \
if ($$2 == $$4) files[d] = files[d] " " $$1; \
else { print "f", $$3 "/" $$4, $$1; } } \
END { for (d in files) print "f", d, files[d] }' | \
while read type dir files; do \
if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \
test -z "$$files" || { \
echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \
$(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \
} \
; done
uninstall-binPROGRAMS:
@$(NORMAL_UNINSTALL)
@list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \
files=`for p in $$list; do echo "$$p"; done | \
sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \
-e 's/$$/$(EXEEXT)/' \
`; \
test -n "$$list" || exit 0; \
echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \
cd "$(DESTDIR)$(bindir)" && rm -f $$files
clean-binPROGRAMS:
@list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \
echo " rm -f" $$list; \
rm -f $$list || exit $$?; \
test -n "$(EXEEXT)" || exit 0; \
list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
echo " rm -f" $$list; \
rm -f $$list
cf-serverd$(EXEEXT): $(cf_serverd_OBJECTS) $(cf_serverd_DEPENDENCIES) $(EXTRA_cf_serverd_DEPENDENCIES)
@rm -f cf-serverd$(EXEEXT)
$(AM_V_CCLD)$(cf_serverd_LINK) $(cf_serverd_OBJECTS) $(cf_serverd_LDADD) $(LIBS)
mostlyclean-compile:
-rm -f *.$(OBJEXT)
distclean-compile:
-rm -f *.tab.c
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cf-serverd-enterprise-stubs.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cf-serverd-functions.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cf-serverd.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cf_serverd-cf-serverd.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/server.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/server_access.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/server_classic.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/server_common.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/server_tls.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/server_transform.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/strlist.Plo@am__quote@
.c.o:
@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
.c.obj:
@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
.c.lo:
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
cf_serverd-cf-serverd.o: cf-serverd.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(cf_serverd_CFLAGS) $(CFLAGS) -MT cf_serverd-cf-serverd.o -MD -MP -MF $(DEPDIR)/cf_serverd-cf-serverd.Tpo -c -o cf_serverd-cf-serverd.o `test -f 'cf-serverd.c' || echo '$(srcdir)/'`cf-serverd.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/cf_serverd-cf-serverd.Tpo $(DEPDIR)/cf_serverd-cf-serverd.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cf-serverd.c' object='cf_serverd-cf-serverd.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(cf_serverd_CFLAGS) $(CFLAGS) -c -o cf_serverd-cf-serverd.o `test -f 'cf-serverd.c' || echo '$(srcdir)/'`cf-serverd.c
cf_serverd-cf-serverd.obj: cf-serverd.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(cf_serverd_CFLAGS) $(CFLAGS) -MT cf_serverd-cf-serverd.obj -MD -MP -MF $(DEPDIR)/cf_serverd-cf-serverd.Tpo -c -o cf_serverd-cf-serverd.obj `if test -f 'cf-serverd.c'; then $(CYGPATH_W) 'cf-serverd.c'; else $(CYGPATH_W) '$(srcdir)/cf-serverd.c'; fi`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/cf_serverd-cf-serverd.Tpo $(DEPDIR)/cf_serverd-cf-serverd.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cf-serverd.c' object='cf_serverd-cf-serverd.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(cf_serverd_CFLAGS) $(CFLAGS) -c -o cf_serverd-cf-serverd.obj `if test -f 'cf-serverd.c'; then $(CYGPATH_W) 'cf-serverd.c'; else $(CYGPATH_W) '$(srcdir)/cf-serverd.c'; fi`
mostlyclean-libtool:
-rm -f *.lo
clean-libtool:
-rm -rf .libs _libs
ID: $(am__tagged_files)
$(am__define_uniq_tagged_files); mkid -fID $$unique
tags: tags-am
TAGS: tags
tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
set x; \
here=`pwd`; \
$(am__define_uniq_tagged_files); \
shift; \
if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
test -n "$$unique" || unique=$$empty_fix; \
if test $$# -gt 0; then \
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
"$$@" $$unique; \
else \
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
$$unique; \
fi; \
fi
ctags: ctags-am
CTAGS: ctags
ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
$(am__define_uniq_tagged_files); \
test -z "$(CTAGS_ARGS)$$unique" \
|| $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
$$unique
GTAGS:
here=`$(am__cd) $(top_builddir) && pwd` \
&& $(am__cd) $(top_srcdir) \
&& gtags -i $(GTAGS_ARGS) "$$here"
cscopelist: cscopelist-am
cscopelist-am: $(am__tagged_files)
list='$(am__tagged_files)'; \
case "$(srcdir)" in \
[\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
*) sdir=$(subdir)/$(srcdir) ;; \
esac; \
for i in $$list; do \
if test -f "$$i"; then \
echo "$(subdir)/$$i"; \
else \
echo "$$sdir/$$i"; \
fi; \
done >> $(top_builddir)/cscope.files
distclean-tags:
-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
distdir: $(DISTFILES)
@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
list='$(DISTFILES)'; \
dist_files=`for file in $$list; do echo $$file; done | \
sed -e "s|^$$srcdirstrip/||;t" \
-e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
case $$dist_files in \
*/*) $(MKDIR_P) `echo "$$dist_files" | \
sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
sort -u` ;; \
esac; \
for file in $$dist_files; do \
if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
if test -d $$d/$$file; then \
dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
if test -d "$(distdir)/$$file"; then \
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
fi; \
if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
fi; \
cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
else \
test -f "$(distdir)/$$file" \
|| cp -p $$d/$$file "$(distdir)/$$file" \
|| exit 1; \
fi; \
done
check-am: all-am
check: check-am
all-am: Makefile $(LTLIBRARIES) $(PROGRAMS)
installdirs:
for dir in "$(DESTDIR)$(bindir)"; do \
test -z "$$dir" || $(MKDIR_P) "$$dir"; \
done
install: install-am
install-exec: install-exec-am
install-data: install-data-am
uninstall: uninstall-am
install-am: all-am
@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
installcheck: installcheck-am
install-strip:
if test -z '$(STRIP)'; then \
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
install; \
else \
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
"INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
fi
mostlyclean-generic:
-test -z "$(MOSTLYCLEANFILES)" || rm -f $(MOSTLYCLEANFILES)
clean-generic:
-test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
distclean-generic:
-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
maintainer-clean-generic:
@echo "This command is intended for maintainers to use"
@echo "it deletes files that may require special tools to rebuild."
clean: clean-am
clean-am: clean-binPROGRAMS clean-generic clean-libtool \
clean-noinstLTLIBRARIES mostlyclean-am
distclean: distclean-am
-rm -rf ./$(DEPDIR)
-rm -f Makefile
distclean-am: clean-am distclean-compile distclean-generic \
distclean-tags
dvi: dvi-am
dvi-am:
html: html-am
html-am:
info: info-am
info-am:
install-data-am:
install-dvi: install-dvi-am
install-dvi-am:
install-exec-am: install-binPROGRAMS
install-html: install-html-am
install-html-am:
install-info: install-info-am
install-info-am:
install-man:
install-pdf: install-pdf-am
install-pdf-am:
install-ps: install-ps-am
install-ps-am:
installcheck-am:
maintainer-clean: maintainer-clean-am
-rm -rf ./$(DEPDIR)
-rm -f Makefile
maintainer-clean-am: distclean-am maintainer-clean-generic
mostlyclean: mostlyclean-am
mostlyclean-am: mostlyclean-compile mostlyclean-generic \
mostlyclean-libtool
pdf: pdf-am
pdf-am:
ps: ps-am
ps-am:
uninstall-am: uninstall-binPROGRAMS
.MAKE: install-am install-strip
.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean \
clean-binPROGRAMS clean-generic clean-libtool \
clean-noinstLTLIBRARIES cscopelist-am ctags ctags-am distclean \
distclean-compile distclean-generic distclean-libtool \
distclean-tags distdir dvi dvi-am html html-am info info-am \
install install-am install-binPROGRAMS install-data \
install-data-am install-dvi install-dvi-am install-exec \
install-exec-am install-html install-html-am install-info \
install-info-am install-man install-pdf install-pdf-am \
install-ps install-ps-am install-strip installcheck \
installcheck-am installdirs maintainer-clean \
maintainer-clean-generic mostlyclean mostlyclean-compile \
mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
tags tags-am uninstall uninstall-am uninstall-binPROGRAMS
@BUILTIN_EXTENSIONS_FALSE@ # Workaround for automake madness (try removing it if you want to know why).
# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.
.NOEXPORT:
cfengine-3.12.1/cf-serverd/cf-serverd-functions.h 0000644 0000000 0000000 00000003143 13377750461 021647 0 ustar 00root root 0000000 0000000 /*
Copyright 2018 Northern.tech AS
This file is part of CFEngine 3 - written and maintained by Northern.tech AS.
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; version 3.
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, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
To the extent this program is licensed as part of the Enterprise
versions of CFEngine, the applicable Commercial Open Source License
(COSL) may apply to this file if you as a licensee so wish it. See
included file COSL.txt.
*/
#ifndef CFENGINE_CF_SERVERD_FUNCTIONS_H
#define CFENGINE_CF_SERVERD_FUNCTIONS_H
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
typedef int (*InitServerFunction)(size_t queue_size, char *bind_address);
GenericAgentConfig *CheckOpts(int argc, char **argv);
int StartServer(EvalContext *ctx, Policy **policy, GenericAgentConfig *config);
#endif
cfengine-3.12.1/cf-serverd/Makefile.am 0000644 0000000 0000000 00000003741 13377750461 017470 0 ustar 00root root 0000000 0000000 #
# Copyright 2018 Northern.tech AS
#
# This file is part of CFEngine 3 - written and maintained by Northern.tech AS.
#
# 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; version 3.
#
# 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, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
#
# To the extent this program is licensed as part of the Enterprise
# versions of CFEngine, the applicable Commercial Open Source License
# (COSL) may apply to this file if you as a licensee so wish it. See
# included file COSL.txt.
#
noinst_LTLIBRARIES = libcf-serverd.la
AM_CPPFLAGS = -I$(srcdir)/../libpromises -I$(srcdir)/../libutils \
-I$(srcdir)/../libcfnet \
-I$(srcdir)/../libenv \
$(OPENSSL_CPPFLAGS) \
$(PCRE_CPPFLAGS) \
$(ENTERPRISE_CPPFLAGS)
AM_CFLAGS = \
$(OPENSSL_CFLAGS) \
$(ENTERPRISE_CFLAGS)
libcf_serverd_la_LIBADD = ../libpromises/libpromises.la
libcf_serverd_la_SOURCES = \
cf-serverd.c \
cf-serverd-enterprise-stubs.c cf-serverd-enterprise-stubs.h \
cf-serverd-functions.c cf-serverd-functions.h \
server_common.c server_common.h \
server.c server.h \
server_transform.c server_transform.h \
server_classic.c server_classic.h \
server_tls.c server_tls.h \
server_access.c server_access.h \
strlist.c strlist.h
if !BUILTIN_EXTENSIONS
bin_PROGRAMS = cf-serverd
# Workaround for automake madness (try removing it if you want to know why).
cf_serverd_CFLAGS = $(AM_CFLAGS)
cf_serverd_LDADD = libcf-serverd.la
endif
CLEANFILES = *.gcno *.gcda
#
# Some basic clean ups
#
MOSTLYCLEANFILES = *~ *.orig *.rej
cfengine-3.12.1/cf-serverd/cf-serverd.c 0000644 0000000 0000000 00000004546 13377750461 017644 0 ustar 00root root 0000000 0000000 /*
Copyright 2018 Northern.tech AS
This file is part of CFEngine 3 - written and maintained by Northern.tech AS.
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; version 3.
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, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
To the extent this program is licensed as part of the Enterprise
versions of CFEngine, the applicable Commercial Open Source License
(COSL) may apply to this file if you as a licensee so wish it. See
included file COSL.txt.
*/
#include
#include
#include /* CleanReportBookFilterSet() */
#include
#include
#include
#include
static void ThisAgentInit(void)
{
umask(077);
}
int main(int argc, char *argv[])
{
/* Ensure that if fd 0,1,2 are closed, we reserve them to avoid opening
* the listening socket on them and closing it later when daemonising. */
int fd = -1;
do
{
fd = open(NULLFILE, O_RDWR, 0);
} while (fd == STDIN_FILENO ||
fd == STDOUT_FILENO ||
fd == STDERR_FILENO);
close(fd);
GenericAgentConfig *config = CheckOpts(argc, argv);
EvalContext *ctx = EvalContextNew();
GenericAgentConfigApply(ctx, config);
GenericAgentDiscoverContext(ctx, config);
Policy *policy = SelectAndLoadPolicy(config, ctx, false, false);
if (!policy)
{
Log(LOG_LEVEL_ERR, "Error reading CFEngine policy. Exiting...");
DoCleanupAndExit(EXIT_FAILURE);
}
GenericAgentPostLoadInit(ctx);
ThisAgentInit();
KeepPromises(ctx, policy, config);
Summarize();
int threads_left = StartServer(ctx, &policy, config);
if (threads_left <= 0)
{
PolicyDestroy(policy);
GenericAgentFinalize(ctx, config);
CleanReportBookFilterSet();
}
return 0;
}
cfengine-3.12.1/cf-serverd/server_access.c 0000644 0000000 0000000 00000046122 13377750461 020427 0 ustar 00root root 0000000 0000000 /*
Copyright 2018 Northern.tech AS
This file is part of CFEngine 3 - written and maintained by Northern.tech AS.
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; version 3.
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, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
To the extent this program is licensed as part of the Enterprise
versions of CFEngine, the applicable Commercial Open Source License
(COSL) may apply to this file if you as a licensee so wish it. See
included file COSL.txt.
*/
#include
#include "server_access.h"
#include "strlist.h"
#include "server.h"
#include /* FuzzySetMatch */
#include /* StringMatchFull TODO REMOVE */
#include
#include
#include
struct acl *paths_acl;
struct acl *classes_acl;
struct acl *vars_acl;
struct acl *literals_acl;
struct acl *query_acl;
struct acl *bundles_acl;
struct acl *roles_acl;
/**
* Run this function on every resource (file, class, var etc) access to
* grant/deny rights. Currently it checks if:
* 1. #ipaddr matches the subnet expression in {admit,deny}_ips
* 2. #hostname matches the subdomain expression in {admit,deny}_hostnames
* 3. #key is searched as-is in {admit,deny}_keys
* 4. #username is searched as-is in {admit,deny}_usernames
*
* @param #found If not NULL then it returns whether the denial was implicit
* (found=false) or explicit (found=true). If not NULL it also
* changes the way the ACLs are traversed to a SLOWER mode,
* since every entry has to be checked for explicit denial.
*
* @return Default is false, i.e. deny. If a match is found in #acl->admit.*
* then return true, unless a match is also found in #acl->deny.* in
* which case return false.
*
* @TODO preprocess our global ACL the moment a client connects, and store in
* ServerConnectionState a list of objects that he can access. That way
* only his relevant resources will be stored in e.g. {admit,deny}_paths
* lists, and running through these two lists on every file request will
* be much faster.
*/
static bool access_CheckResource(const struct resource_acl *acl,
bool *found,
const char *ipaddr, const char *hostname,
const char *key, const char *username)
{
bool access = false; /* DENY by default */
bool have_match = false; /* No matching rule found yet */
/* First we check for admission, secondly for denial, so that denial takes
* precedence. */
if (!NULL_OR_EMPTY(ipaddr) && acl->admit.ips != NULL)
{
/* Still using legacy code here, doing linear search over all IPs in
* textual representation... too CPU intensive! TODO store the ACL as
* one list of struct sockaddr_storage, together with CIDR notation
* subnet length.
*/
const char *rule = NULL;
for (int i = 0; i < StrList_Len(acl->admit.ips); i++)
{
if (FuzzySetMatch(StrList_At(acl->admit.ips, i), ipaddr) == 0 ||
/* Legacy regex matching, TODO DEPRECATE */
StringMatchFull(StrList_At(acl->admit.ips, i), ipaddr))
{
rule = StrList_At(acl->admit.ips, i);
break;
}
}
if (rule != NULL)
{
Log(LOG_LEVEL_DEBUG,
"Admit IP due to rule: %s",
rule);
access = true;
have_match = true;
}
}
if (!access && !NULL_OR_EMPTY(hostname) &&
acl->admit.hostnames != NULL)
{
size_t pos = StrList_SearchLongestPrefix(acl->admit.hostnames,
hostname, 0,
'.', false);
/* === Legacy regex matching, slow, TODO DEPRECATE === */
if (pos == (size_t) -1)
{
for (int i = 0; i < StrList_Len(acl->admit.hostnames); i++)
{
if (StringMatchFull(StrList_At(acl->admit.hostnames, i),
hostname))
{
pos = i;
break;
}
}
}
/* =================================================== */
if (pos != (size_t) -1)
{
Log(LOG_LEVEL_DEBUG,
"Admit hostname due to rule: %s",
StrList_At(acl->admit.hostnames, pos));
access = true;
have_match = true;
}
}
if (!access && !NULL_OR_EMPTY(key) &&
acl->admit.keys != NULL)
{
size_t pos;
bool ret = StrList_BinarySearch(acl->admit.keys, key, &pos);
if (ret)
{
Log(LOG_LEVEL_DEBUG,
"Admit key due to rule: %s",
StrList_At(acl->admit.keys, pos));
access = true;
have_match = true;
}
}
if (!access && !NULL_OR_EMPTY(username) &&
acl->admit.usernames != NULL)
{
size_t pos;
bool ret = StrList_BinarySearch(acl->admit.usernames, username, &pos);
if (ret)
{
Log(LOG_LEVEL_DEBUG,
"Admit username due to rule: %s",
StrList_At(acl->admit.usernames, pos));
access = true;
have_match = true;
}
}
/* An admit rule was not found, and we don't care whether the denial is
* explicit or implicit: we can finish now. */
if (!access && found == NULL)
{
assert(!have_match);
return false; /* EARLY RETURN! */
}
/* If access has been granted, we might need to deny it based on ACL. */
/* Same goes if access has not been granted and "found" is not NULL, in
* which case we have to return in "found", whether an explicit denial
* rule matched or not. */
assert((access && have_match) ||
(!access && !have_match && found != NULL));
if ((access || !have_match) &&
!NULL_OR_EMPTY(ipaddr) &&
acl->deny.ips != NULL)
{
const char *rule = NULL;
for (int i = 0; i < StrList_Len(acl->deny.ips); i++)
{
if (FuzzySetMatch(StrList_At(acl->deny.ips, i), ipaddr) == 0 ||
/* Legacy regex matching, TODO DEPRECATE */
StringMatchFull(StrList_At(acl->deny.ips, i), ipaddr))
{
rule = StrList_At(acl->deny.ips, i);
break;
}
}
if (rule != NULL)
{
Log(LOG_LEVEL_DEBUG,
"Deny IP due to rule: %s",
rule);
access = false;
have_match = true;
}
}
if ((access || !have_match) &&
!NULL_OR_EMPTY(hostname) &&
acl->deny.hostnames != NULL)
{
size_t pos = StrList_SearchLongestPrefix(acl->deny.hostnames,
hostname, 0,
'.', false);
/* === Legacy regex matching, slow, TODO DEPRECATE === */
if (pos == (size_t) -1)
{
for (int i = 0; i < StrList_Len(acl->deny.hostnames); i++)
{
if (StringMatchFull(StrList_At(acl->deny.hostnames, i),
hostname))
{
pos = i;
break;
}
}
}
/* =================================================== */
if (pos != (size_t) -1)
{
Log(LOG_LEVEL_DEBUG,
"Deny hostname due to rule: %s",
StrList_At(acl->deny.hostnames, pos));
access = false;
have_match = true;
}
}
if ((access || !have_match) &&
!NULL_OR_EMPTY(key) &&
acl->deny.keys != NULL)
{
size_t pos;
bool ret = StrList_BinarySearch(acl->deny.keys, key, &pos);
if (ret)
{
Log(LOG_LEVEL_DEBUG,
"Deny key due to rule: %s",
StrList_At(acl->deny.keys, pos));
access = false;
have_match = true;
}
}
if ((access || !have_match) &&
!NULL_OR_EMPTY(username) &&
acl->deny.usernames != NULL)
{
size_t pos;
bool ret = StrList_BinarySearch(acl->deny.usernames, username, &pos);
if (ret)
{
Log(LOG_LEVEL_DEBUG,
"Deny username due to rule: %s",
StrList_At(acl->deny.usernames, pos));
access = false;
have_match = true;
}
}
/* We can't have implicit admittance,
admittance must always be explicit. */
assert(! (access && !have_match));
if (found != NULL)
{
*found = have_match;
}
return access;
}
/**
* Search #req_path in #acl, if found check its rules. The longest parent
* directory of #req_path is searched, or an exact match. Directories *must*
* end with FILE_SEPARATOR in the ACL list.
*
* @return If ACL entry is found, and host is listed in there return
* true. Else return false.
*/
bool acl_CheckPath(const struct acl *acl, const char *reqpath,
const char *ipaddr, const char *hostname,
const char *key)
{
bool access = false; /* Deny access by default */
size_t reqpath_len = strlen(reqpath);
/* CHECK 1: Search for parent directory or exact entry in ACL. */
size_t pos = StrList_SearchLongestPrefix(acl->resource_names,
reqpath, reqpath_len,
FILE_SEPARATOR, true);
if (pos != (size_t) -1) /* acl entry was found */
{
const struct resource_acl *racl = &acl->acls[pos];
bool ret = access_CheckResource(racl, NULL, ipaddr, hostname, key, NULL);
if (ret == true) /* entry found that grants access */
{
access = true;
}
Log(LOG_LEVEL_DEBUG,
"acl_CheckPath: '%s' found in ACL entry '%s', admit=%s",
reqpath, acl->resource_names->list[pos]->str,
ret == true ? "true" : "false");
}
/* CHECK 2: replace ACL entry parts with special variables (if applicable),
* e.g. turn "/path/to/192.168.1.1.json"
* to "/path/to/$(connection.ip).json" */
char mangled_path[PATH_MAX];
memcpy(mangled_path, reqpath, reqpath_len + 1);
size_t mangled_path_len =
ReplaceSpecialVariables(mangled_path, sizeof(mangled_path),
ipaddr, "$(connection.ip)",
hostname, "$(connection.hostname)",
key, "$(connection.key)");
/* If there were special variables replaced */
if (mangled_path_len != 0 &&
mangled_path_len != (size_t) -1) /* Overflow, TODO handle separately. */
{
size_t pos2 = StrList_SearchLongestPrefix(acl->resource_names,
mangled_path, mangled_path_len,
FILE_SEPARATOR, true);
if (pos2 != (size_t) -1) /* acl entry was found */
{
/* TODO make sure this match is more specific than the other one. */
const struct resource_acl *racl = &acl->acls[pos2];
/* Check if the magic strings are allowed or denied. */
bool ret =
access_CheckResource(racl, NULL,
"$(connection.ip)",
"$(connection.hostname)",
"$(connection.key)", NULL);
if (ret == true) /* entry found that grants access */
{
access = true;
}
Log(LOG_LEVEL_DEBUG,
"acl_CheckPath: '%s' found in ACL entry '%s', admit=%s",
mangled_path, acl->resource_names->list[pos2]->str,
ret == true ? "true" : "false");
}
}
return access;
}
bool acl_CheckExact(const struct acl *acl, const char *req_string,
const char *ipaddr, const char *hostname,
const char *key)
{
bool access = false;
size_t pos = -1;
bool found = StrList_BinarySearch(acl->resource_names, req_string, &pos);
if (found)
{
const struct resource_acl *racl = &acl->acls[pos];
bool ret = access_CheckResource(racl, NULL,
ipaddr, hostname, key, NULL);
if (ret == true) /* entry found that grants access */
{
access = true;
}
}
return access;
}
/**
* Go linearly over all the #acl and check every rule if it matches.
* ADMIT only if at least one rule matches admit and none matches deny.
* DENY if no rule matches OR if at least one matches deny.
*/
bool acl_CheckRegex(const struct acl *acl, const char *req_string,
const char *ipaddr, const char *hostname,
const char *key, const char *username)
{
bool retval = false;
/* For all ACLs */
for (size_t i = 0; i < acl->len; i++)
{
const char *regex = acl->resource_names->list[i]->str;
/* Does this ACL matches the req_string? */
if (StringMatchFull(regex, req_string))
{
const struct resource_acl *racl = &acl->acls[i];
/* Does this ACL apply to this host? */
bool found;
bool admit = access_CheckResource(racl, &found,
ipaddr, hostname, key, username);
if (found && !admit)
{
return false;
}
else if (found && admit)
{
retval = true;
}
else
{
/* If it's not found, there should be no admittance. */
assert(!found);
assert(!admit);
/* We are not touching retval, because it was possibly found
* before and retval has been set to "true". */
}
}
}
return retval;
}
/**
* Search the list of resources for the handle. If found return the index of
* the resource ACL that corresponds to that handle, else add the handle with
* empty ACL, reallocating if necessary. The new handle is inserted in the
* proper position to keep the acl->resource_names list sorted.
*
* @note acl->resource_names list should already be sorted, no problem if all
* inserts are done with this function.
*
* @return the index of the resource_acl corresponding to handle. -1 means
* reallocation failed, but existing values are still valid.
*/
size_t acl_SortedInsert(struct acl **a, const char *handle)
{
assert(handle != NULL);
struct acl *acl = *a; /* for clarity */
size_t position = (size_t) -1;
bool found = StrList_BinarySearch(acl->resource_names,
handle, &position);
if (found)
{
/* Found it, return existing entry. */
assert(position < acl->len);
return position;
}
/* handle is not in acl, we must insert at the position returned. */
assert(position <= acl->len);
/* 1. Check if reallocation is needed. */
if (acl->len == acl->alloc_len)
{
size_t new_alloc_len = acl->alloc_len * 2;
if (new_alloc_len == 0)
{
new_alloc_len = 1;
}
struct acl *p =
realloc(acl, sizeof(*p) + sizeof(*p->acls) * new_alloc_len);
if (p == NULL)
{
return (size_t) -1;
}
acl = p;
acl->alloc_len = new_alloc_len;
*a = acl; /* Change the caller's variable */
}
/* 2. We now have enough space, so insert the resource at the proper
index. */
size_t ret = StrList_Insert(&acl->resource_names,
handle, position);
if (ret == (size_t) -1)
{
/* realloc() failed but the data structure is still valid. */
return (size_t) -1;
}
/* 3. Make room. */
memmove(&acl->acls[position + 1], &acl->acls[position],
(acl->len - position) * sizeof(acl->acls[position]));
acl->len++;
/* 4. Initialise all ACLs for the resource as empty. */
acl->acls[position] = (struct resource_acl) { {0}, {0} }; /* NULL acls <=> empty */
Log(LOG_LEVEL_DEBUG, "Inserted in ACL position %zu: %s",
position, handle);
assert(acl->len == StrList_Len(acl->resource_names));
return position;
}
void acl_Free(struct acl *a)
{
StrList_Free(&a->resource_names);
size_t i;
for (i = 0; i < a->len; i++)
{
StrList_Free(&a->acls[i].admit.ips);
StrList_Free(&a->acls[i].admit.hostnames);
StrList_Free(&a->acls[i].admit.usernames);
StrList_Free(&a->acls[i].admit.keys);
StrList_Free(&a->acls[i].deny.ips);
StrList_Free(&a->acls[i].deny.hostnames);
StrList_Free(&a->acls[i].deny.keys);
}
free(a);
}
void acl_Summarise(const struct acl *acl, const char *title)
{
assert(acl->len == StrList_Len(acl->resource_names));
size_t i, j;
for (i = 0; i < acl->len; i++)
{
Log(LOG_LEVEL_VERBOSE, "\t%s: %s",
title, StrList_At(acl->resource_names, i));
const struct resource_acl *racl = &acl->acls[i];
for (j = 0; j < StrList_Len(racl->admit.ips); j++)
{
Log(LOG_LEVEL_VERBOSE, "\t\tadmit_ips: %s",
StrList_At(racl->admit.ips, j));
}
for (j = 0; j < StrList_Len(racl->admit.hostnames); j++)
{
Log(LOG_LEVEL_VERBOSE, "\t\tadmit_hostnames: %s",
StrList_At(racl->admit.hostnames, j));
}
for (j = 0; j < StrList_Len(racl->admit.keys); j++)
{
Log(LOG_LEVEL_VERBOSE, "\t\tadmit_keys: %s",
StrList_At(racl->admit.keys, j));
}
for (j = 0; j < StrList_Len(racl->deny.ips); j++)
{
Log(LOG_LEVEL_VERBOSE, "\t\tdeny_ips: %s",
StrList_At(racl->deny.ips, j));
}
for (j = 0; j < StrList_Len(racl->deny.hostnames); j++)
{
Log(LOG_LEVEL_VERBOSE, "\t\tdeny_hostnames: %s",
StrList_At(racl->deny.hostnames, j));
}
for (j = 0; j < StrList_Len(racl->deny.keys); j++)
{
Log(LOG_LEVEL_VERBOSE, "\t\tdeny_keys: %s",
StrList_At(racl->deny.keys, j));
}
}
}
cfengine-3.12.1/cf-serverd/server_tls.c 0000644 0000000 0000000 00000104372 13377750461 017772 0 ustar 00root root 0000000 0000000 /*
Copyright 2018 Northern.tech AS
This file is part of CFEngine 3 - written and maintained by Northern.tech AS.
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; version 3.
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, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
To the extent this program is licensed as part of the Enterprise
versions of CFEngine, the applicable Commercial Open Source License
(COSL) may apply to this file if you as a licensee so wish it. See
included file COSL.txt.
*/
#include
#include
#include /* ERR_get_error */
#include /* DecryptString */
#include
#include
#include /* IsMatchItemIn */
#include /* LastSaw1 */
#include /* SendTransaction,ReceiveTransaction */
#include /* TLSSend */
#include
#include
#include /* StringMatchFull */
#include
#include /* IsDirReal */
#include "server_access.h" /* access_CheckResource, acl_CheckExact */
static SSL_CTX *SSLSERVERCONTEXT = NULL;
/**
* @param[in] priv_key private key to use (or %NULL to use the global PRIVKEY)
* @param[in] pub_key public key to use (or %NULL to use the global PUBKEY)
* @param[out] ssl_ctx place to store the SSL context (or %NULL to use the
* global SSL_CTX)
* @warning Make sure you've called CryptoInitialize() first!
*/
bool ServerTLSInitialize(RSA *priv_key, RSA *pub_key, SSL_CTX **ssl_ctx)
{
int ret;
if (priv_key == NULL)
{
/* private key not specified, use the global one */
priv_key = PRIVKEY;
}
if (pub_key == NULL)
{
/* public key not specified, use the global one */
pub_key = PUBKEY;
}
if (priv_key == NULL || pub_key == NULL)
{
Log(LOG_LEVEL_ERR, "Public/private key pair not loaded,"
" please create one using cf-key");
return false;
}
if (!TLSGenericInitialize())
{
return false;
}
if (ssl_ctx == NULL)
{
ssl_ctx = &SSLSERVERCONTEXT;
}
assert(*ssl_ctx == NULL);
*ssl_ctx = SSL_CTX_new(SSLv23_server_method());
if (*ssl_ctx == NULL)
{
Log(LOG_LEVEL_ERR, "SSL_CTX_new: %s",
TLSErrorString(ERR_get_error()));
return false;
}
TLSSetDefaultOptions(*ssl_ctx, SERVER_ACCESS.allowtlsversion);
/*
* CFEngine is not a web server so it does not need to support many
* ciphers. It only allows a safe but very common subset by default,
* extensible via "allowciphers" in body server control. By default
* it allows:
*
* AES256-GCM-SHA384: most high-grade RSA-based cipher from TLSv1.2
* AES256-SHA: most backwards compatible but high-grade, from SSLv3
*/
const char *cipher_list = SERVER_ACCESS.allowciphers;
if (cipher_list == NULL)
{
cipher_list ="AES256-GCM-SHA384:AES256-SHA";
}
Log(LOG_LEVEL_VERBOSE,
"Setting cipher list for incoming TLS connections to: %s",
cipher_list);
ret = SSL_CTX_set_cipher_list(*ssl_ctx, cipher_list);
if (ret != 1)
{
Log(LOG_LEVEL_ERR,
"No valid ciphers in cipher list: %s",
cipher_list);
goto err;
}
/* Create cert into memory and load it into SSL context. */
X509 *cert = TLSGenerateCertFromPrivKey(priv_key);
if (cert == NULL)
{
Log(LOG_LEVEL_ERR,
"Failed to generate in-memory certificate from private key");
goto err;
}
SSL_CTX_use_certificate(*ssl_ctx, cert);
X509_free(cert);
ret = SSL_CTX_use_RSAPrivateKey(*ssl_ctx, priv_key);
if (ret != 1)
{
Log(LOG_LEVEL_ERR, "Failed to use RSA private key: %s",
TLSErrorString(ERR_get_error()));
goto err;
}
/* Verify cert consistency. */
ret = SSL_CTX_check_private_key(*ssl_ctx);
if (ret != 1)
{
Log(LOG_LEVEL_ERR, "Inconsistent key and TLS cert: %s",
TLSErrorString(ERR_get_error()));
goto err;
}
return true;
err:
SSL_CTX_free(*ssl_ctx);
*ssl_ctx = NULL;
return false;
}
/**
* @param[in,out] priv_key private key to deinitalize (or %NULL to use the
* global PRIVKEY)
* @param[in,out] pub_key public key to deinitialize (or %NULL to use the
* global PUBKEY)
* @param[in,out] ssl_ctx the SSL context to deinitialize (or %NULL to use the
* global SSL_CTX)
*/
void ServerTLSDeInitialize(RSA **priv_key, RSA **pub_key, SSL_CTX **ssl_ctx)
{
if (priv_key == NULL)
{
priv_key = &PRIVKEY;
}
if (pub_key == NULL)
{
pub_key = &PUBKEY;
}
if (ssl_ctx == NULL)
{
ssl_ctx = &SSLSERVERCONTEXT;
}
if (*pub_key)
{
RSA_free(*pub_key);
*pub_key = NULL;
}
if (*priv_key)
{
RSA_free(*priv_key);
*priv_key = NULL;
}
if (*ssl_ctx != NULL)
{
SSL_CTX_free(*ssl_ctx);
*ssl_ctx = NULL;
}
}
/**
* @brief Set the connection type to CLASSIC or TLS.
* It is performed by peeking into the TLS connection to read the first bytes,
* and if it's a CAUTH protocol command use the old protocol loop, else use
* the TLS protocol loop.
* This must be the first thing we run on an accepted connection.
*
* @return true for success, false otherwise.
*/
bool ServerTLSPeek(ConnectionInfo *conn_info)
{
assert(SSLSERVERCONTEXT != NULL);
assert(PRIVKEY != NULL);
assert(PUBKEY != NULL);
assert(ConnectionInfoProtocolVersion(conn_info) == CF_PROTOCOL_UNDEFINED);
const int peek_size = CF_INBAND_OFFSET + sizeof("CAUTH");
char buf[peek_size];
ssize_t got = recv(ConnectionInfoSocket(conn_info), buf, sizeof(buf), MSG_PEEK);
assert(got <= peek_size);
if (got < 0)
{
assert(got == -1);
Log(LOG_LEVEL_ERR, "TCP receive error: %s", GetErrorStr());
return false;
}
else if (got == 0)
{
Log(LOG_LEVEL_INFO,
"Peer closed TCP connection without sending data!");
return false;
}
else if (got < peek_size)
{
Log(LOG_LEVEL_INFO,
"Peer sent only %zd bytes! Considering the protocol as Classic",
got);
ConnectionInfoSetProtocolVersion(conn_info, CF_PROTOCOL_CLASSIC);
}
else if (memcmp(&buf[CF_INBAND_OFFSET], "CAUTH", strlen("CAUTH")) == 0)
{
Log(LOG_LEVEL_VERBOSE,
"Peeked CAUTH in TCP stream, considering the protocol as Classic");
ConnectionInfoSetProtocolVersion(conn_info, CF_PROTOCOL_CLASSIC);
}
else /* got==peek_size && not "CAUTH" */
{
Log(LOG_LEVEL_VERBOSE,
"Peeked nothing important in TCP stream, considering the protocol as TLS");
ConnectionInfoSetProtocolVersion(conn_info, CF_PROTOCOL_TLS);
}
LogRaw(LOG_LEVEL_DEBUG, "Peeked data: ", buf, got);
return true;
}
/**
* 1. Send "CFE_v%d" server hello.
* 2. Receive two lines: One "CFE_v%d" with the protocol version the client
* wishes to have, and one "IDENTITY USERNAME=blah ..." with identification
* information for the client.
*
* @note For Identification dialog to end successfully, one "OK WELCOME" line
* must be sent right after this function, after identity is verified.
*
* @TODO More protocol identity. E.g.
* IDENTITY USERNAME=xxx HOSTNAME=xxx CUSTOMNAME=xxx
*
* @retval true if protocol version was successfully negotiated and IDENTITY
* command was parsed correctly. Identity fields (only #username for
* now) have the respective string values, or they are empty if field
* was not on IDENTITY line. #conn_info->protocol has been updated
* with the negotiated protocol version.
* @retval false in case of error.
*/
bool ServerIdentificationDialog(ConnectionInfo *conn_info,
char *username, size_t username_size)
{
int ret;
char input[1024] = "";
/* The only protocol version we support inside TLS, for now. */
const int SERVER_PROTOCOL_VERSION = CF_PROTOCOL_LATEST;
/* Send "CFE_v%d cf-serverd version". */
char version_string[CF_MAXVARSIZE];
int len = snprintf(version_string, sizeof(version_string),
"CFE_v%d cf-serverd %s\n",
SERVER_PROTOCOL_VERSION, VERSION);
ret = TLSSend(conn_info->ssl, version_string, len);
if (ret != len)
{
Log(LOG_LEVEL_NOTICE, "Connection was hung up!");
return false;
}
/* Receive CFE_v%d ... \n IDENTITY USERNAME=... */
int input_len = TLSRecvLines(conn_info->ssl, input, sizeof(input));
if (input_len <= 0)
{
Log(LOG_LEVEL_NOTICE,
"Client closed connection early! He probably does not trust our key...");
return false;
}
int version_received = -1;
ret = sscanf(input, "CFE_v%d", &version_received);
if (ret != 1)
{
Log(LOG_LEVEL_NOTICE,
"Protocol version negotiation failed! Received: %s",
input);
return false;
}
/* For now we support only one version inside TLS. */
/* TODO value should not be hardcoded but compared to enum ProtocolVersion. */
if (version_received != SERVER_PROTOCOL_VERSION)
{
Log(LOG_LEVEL_NOTICE,
"Client advertises disallowed protocol version: %d",
version_received);
return false;
/* TODO send "BAD ..." ? */
}
/* Did we receive 2nd line or do we need to receive again? */
const char id_line[] = "\nIDENTITY ";
char *line2 = memmem(input, input_len, id_line, strlen(id_line));
if (line2 == NULL)
{
/* Wait for 2nd line to arrive. */
input_len = TLSRecvLines(conn_info->ssl, input, sizeof(input));
if (input_len <= 0)
{
Log(LOG_LEVEL_NOTICE,
"Client closed connection during identification dialog!");
return false;
}
line2 = input;
}
else
{
line2++; /* skip '\n' */
}
/***** Parse all IDENTITY fields from line2 *****/
char word1[1024], word2[1024];
int line2_pos = 0, chars_read = 0;
/* Reset all identity variables, we'll set them according to fields
* on IDENTITY line. For now only "username" setting exists... */
username[0] = '\0';
/* Assert sscanf() is safe to use. */
assert(sizeof(word1) >= sizeof(input));
assert(sizeof(word2) >= sizeof(input));
ret = sscanf(line2, "IDENTITY %[^=]=%s%n", word1, word2, &chars_read);
while (ret >= 2)
{
/* Found USERNAME identity setting */
if (strcmp(word1, "USERNAME") == 0)
{
if ((strlen(word2) < username_size) && (IsUserNameValid(word2) == true))
{
strcpy(username, word2);
}
else
{
Log(LOG_LEVEL_NOTICE, "Received invalid IDENTITY: %s=%s",
word1, word2);
return false;
}
Log(LOG_LEVEL_VERBOSE, "Setting IDENTITY: %s=%s",
word1, word2);
}
/* ... else if (strcmp()) for other acceptable IDENTITY parameters. */
else
{
Log(LOG_LEVEL_VERBOSE, "Received unknown IDENTITY parameter: %s=%s",
word1, word2);
}
line2_pos += chars_read;
ret = sscanf(&line2[line2_pos], " %[^=]=%s%n", word1, word2, &chars_read);
}
/* Version client and server agreed on. */
conn_info->protocol = version_received;
return true;
}
bool ServerSendWelcome(const ServerConnectionState *conn)
{
char s[1024] = "OK WELCOME";
size_t len = strlen(s);
int ret;
/* "OK WELCOME" is the important part. The rest is just extra verbosity. */
if (conn->username[0] != '\0')
{
ret = snprintf(&s[len], sizeof(s) - len, " %s=%s",
"USERNAME", conn->username);
if (ret >= sizeof(s) - len)
{
Log(LOG_LEVEL_NOTICE, "Sending OK WELCOME message truncated: %s", s);
return false;
}
len += ret;
}
/* Overwrite the terminating '\0', we don't need it anyway. */
s[len] = '\n';
len++;
ret = TLSSend(conn->conn_info->ssl, s, len);
if (ret == -1)
{
return false;
}
return true;
}
/**
* @brief Accept a TLS connection and authenticate and identify.
*
* Doesn't include code for verifying key and lastseen
*
* @param conn connection state
* @param ssl_ctx SSL context to use for the session (or %NULL to use the
* default SSLSERVERCONTEXT)
*
* @see ServerTLSSessionEstablish
* @return true for success false otherwise
*/
bool BasicServerTLSSessionEstablish(ServerConnectionState *conn, SSL_CTX *ssl_ctx)
{
if (conn->conn_info->status == CONNECTIONINFO_STATUS_ESTABLISHED)
{
return true;
}
if (ssl_ctx == NULL)
{
ssl_ctx = SSLSERVERCONTEXT;
}
assert(ConnectionInfoSSL(conn->conn_info) == NULL);
SSL *ssl = SSL_new(ssl_ctx);
if (ssl == NULL)
{
Log(LOG_LEVEL_ERR, "SSL_new: %s",
TLSErrorString(ERR_get_error()));
return false;
}
ConnectionInfoSetSSL(conn->conn_info, ssl);
/* Pass conn_info inside the ssl struct for TLSVerifyCallback(). */
SSL_set_ex_data(ssl, CONNECTIONINFO_SSL_IDX, conn->conn_info);
/* Now we are letting OpenSSL take over the open socket. */
SSL_set_fd(ssl, ConnectionInfoSocket(conn->conn_info));
int ret = SSL_accept(ssl);
if (ret <= 0)
{
TLSLogError(ssl, LOG_LEVEL_ERR,
"Failed to accept TLS connection", ret);
return false;
}
Log(LOG_LEVEL_VERBOSE, "TLS version negotiated: %8s; Cipher: %s,%s",
SSL_get_version(ssl),
SSL_get_cipher_name(ssl),
SSL_get_cipher_version(ssl));
return true;
}
/**
* @brief Accept a TLS connection and authenticate and identify.
*
* This function uses trustkeys to trust new keys and updates lastseen
*
* @param conn connection state
* @param ssl_ctx SSL context to use for the session (or %NULL to use the
* default SSLSERVERCONTEXT)
*
* @see BasicServerTLSSessionEstablish
* @note Various fields in #conn are set, like username and keyhash.
* @return true for success false otherwise
*/
bool ServerTLSSessionEstablish(ServerConnectionState *conn, SSL_CTX *ssl_ctx)
{
if (conn->conn_info->status == CONNECTIONINFO_STATUS_ESTABLISHED)
{
return true;
}
bool established = BasicServerTLSSessionEstablish(conn, ssl_ctx);
if (!established)
{
return false;
}
Log(LOG_LEVEL_VERBOSE, "TLS session established, checking trust...");
/* Send/Receive "CFE_v%d" version string, agree on version, receive
identity (username) of peer. */
char username[sizeof(conn->username)] = "";
bool id_success = ServerIdentificationDialog(conn->conn_info,
username, sizeof(username));
if (!id_success)
{
return false;
}
/* We *now* (maybe a bit late) verify the key that the client sent us in
* the TLS handshake, since we need the username to do so. TODO in the
* future store keys irrelevant of username, so that we can match them
* before IDENTIFY. */
int ret = TLSVerifyPeer(conn->conn_info, conn->ipaddr, username);
if (ret == -1) /* error */
{
return false;
}
if (ret == 1) /* trusted key */
{
Log(LOG_LEVEL_VERBOSE,
"%s: Client is TRUSTED, public key MATCHES stored one.",
KeyPrintableHash(ConnectionInfoKey(conn->conn_info)));
}
if (ret == 0) /* untrusted key */
{
if ((SERVER_ACCESS.trustkeylist != NULL) &&
(IsMatchItemIn(SERVER_ACCESS.trustkeylist, conn->ipaddr)))
{
Log(LOG_LEVEL_VERBOSE,
"Peer was found in \"trustkeysfrom\" list");
Log(LOG_LEVEL_NOTICE, "Trusting new key: %s",
KeyPrintableHash(ConnectionInfoKey(conn->conn_info)));
SavePublicKey(username, KeyPrintableHash(conn->conn_info->remote_key),
KeyRSA(ConnectionInfoKey(conn->conn_info)));
}
else
{
Log(LOG_LEVEL_NOTICE,
"TRUST FAILED, peer presented an untrusted key, dropping connection!");
Log(LOG_LEVEL_VERBOSE,
"Add peer to \"trustkeysfrom\" if you really want to start trusting this new key.");
return false;
}
}
/* All checks succeeded, set conn->uid (conn->sid for Windows)
* according to the received USERNAME identity. */
SetConnIdentity(conn, username);
/* No CAUTH, SAUTH in non-classic protocol. */
conn->user_data_set = 1;
conn->rsa_auth = 1;
LastSaw1(conn->ipaddr, KeyPrintableHash(ConnectionInfoKey(conn->conn_info)),
LAST_SEEN_ROLE_ACCEPT);
ServerSendWelcome(conn);
return true;
}
//*******************************************************************
// COMMANDS
//*******************************************************************
ProtocolCommandNew GetCommandNew(char *str)
{
int i;
for (i = 0; PROTOCOL_NEW[i] != NULL; i++)
{
int cmdlen = strlen(PROTOCOL_NEW[i]);
if ((strncmp(str, PROTOCOL_NEW[i], cmdlen) == 0) &&
(str[cmdlen] == ' ' || str[cmdlen] == '\0'))
{
return i;
}
}
assert (i == PROTOCOL_COMMAND_BAD);
return i;
}
/**
* Currently this function returns false when we want the connection
* closed, and true, when we want to proceed further with requests.
*
* @TODO So we need this function to return more than true/false, because now
* we return true even when access is denied! E.g. return -1 for error, 0 on
* success, 1 on access denied. It can be an option if connection will close
* on denial.
*/
bool BusyWithNewProtocol(EvalContext *ctx, ServerConnectionState *conn)
{
/* The CF_BUFEXT extra space is there to ensure we're not *reading* out of
* bounds in commands that carry extra binary arguments, like MD5. */
char recvbuffer[CF_BUFSIZE + CF_BUFEXT] = { 0 };
/* This size is the max we can SendTransaction(). */
char sendbuffer[CF_BUFSIZE - CF_INBAND_OFFSET] = { 0 };
char filename[CF_BUFSIZE + 1]; /* +1 for appending slash sometimes */
ServerFileGetState get_args = { 0 };
/* We already encrypt because of the TLS layer, no need to encrypt more. */
const int encrypted = 0;
/* Legacy stuff only for old protocol. */
assert(conn->rsa_auth == 1);
assert(conn->user_data_set == 1);
/* Receive up to CF_BUFSIZE - 1 bytes. */
const int received = ReceiveTransaction(conn->conn_info,
recvbuffer, NULL);
if (received == -1)
{
/* Already Log()ged in case of error. */
return false;
}
if (received > CF_BUFSIZE - 1)
{
UnexpectedError("Received transaction of size %d", received);
return false;
}
if (strlen(recvbuffer) == 0)
{
Log(LOG_LEVEL_WARNING,
"Got NULL transmission (of size %d)", received);
return true;
}
/* Don't process request if we're signalled to exit. */
if (IsPendingTermination())
{
Log(LOG_LEVEL_VERBOSE, "Server must exit, closing connection");
return false;
}
/* TODO break recvbuffer here: command, param1, param2 etc. */
switch (GetCommandNew(recvbuffer))
{
case PROTOCOL_COMMAND_EXEC:
{
const size_t EXEC_len = strlen(PROTOCOL_NEW[PROTOCOL_COMMAND_EXEC]);
/* Assert recvbuffer starts with EXEC. */
assert(strncmp(PROTOCOL_NEW[PROTOCOL_COMMAND_EXEC],
recvbuffer, EXEC_len) == 0);
char *args = &recvbuffer[EXEC_len];
args += strspn(args, " \t"); /* bypass spaces */
Log(LOG_LEVEL_VERBOSE, "%14s %7s %s",
"Received:", "EXEC", args);
bool b = DoExec2(ctx, conn, args,
sendbuffer, sizeof(sendbuffer));
/* In the end we might keep the connection open (return true) to be
* ready for next requests, but we must always send the TERMINATOR
* string so that the client can close the connection at will. */
Terminate(conn->conn_info);
return b;
}
case PROTOCOL_COMMAND_VERSION:
snprintf(sendbuffer, sizeof(sendbuffer), "OK: %s", Version());
SendTransaction(conn->conn_info, sendbuffer, 0, CF_DONE);
return true;
case PROTOCOL_COMMAND_GET:
{
int ret = sscanf(recvbuffer, "GET %d %[^\n]",
&(get_args.buf_size), filename);
if (ret != 2 ||
get_args.buf_size <= 0 || get_args.buf_size > CF_BUFSIZE)
{
goto protocol_error;
}
Log(LOG_LEVEL_VERBOSE, "%14s %7s %s",
"Received:", "GET", filename);
/* TODO batch all the following in one function since it's very
* similar in all of GET, OPENDIR and STAT. */
size_t zret = ShortcutsExpand(filename, sizeof(filename),
SERVER_ACCESS.path_shortcuts,
conn->ipaddr, conn->revdns,
KeyPrintableHash(ConnectionInfoKey(conn->conn_info)));
if (zret == (size_t) -1)
{
goto protocol_error;
}
zret = PreprocessRequestPath(filename, sizeof(filename));
if (zret == (size_t) -1)
{
RefuseAccess(conn, recvbuffer);
return true;
}
PathRemoveTrailingSlash(filename, strlen(filename));
Log(LOG_LEVEL_VERBOSE, "%14s %7s %s",
"Translated to:", "GET", filename);
if (acl_CheckPath(paths_acl, filename,
conn->ipaddr, conn->revdns,
KeyPrintableHash(ConnectionInfoKey(conn->conn_info)))
== false)
{
Log(LOG_LEVEL_INFO, "access denied to GET: %s", filename);
RefuseAccess(conn, recvbuffer);
return true;
}
memset(sendbuffer, 0, sizeof(sendbuffer));
if (get_args.buf_size >= CF_BUFSIZE)
{
get_args.buf_size = 2048;
}
/* TODO eliminate! */
get_args.conn = conn;
get_args.encrypt = false;
get_args.replybuff = sendbuffer;
get_args.replyfile = filename;
CfGetFile(&get_args);
return true;
}
case PROTOCOL_COMMAND_OPENDIR:
{
memset(filename, 0, sizeof(filename));
int ret = sscanf(recvbuffer, "OPENDIR %[^\n]", filename);
if (ret != 1)
{
goto protocol_error;
}
Log(LOG_LEVEL_VERBOSE, "%14s %7s %s",
"Received:", "OPENDIR", filename);
/* sizeof()-1 because we need one extra byte for
appending '/' afterwards. */
size_t zret = ShortcutsExpand(filename, sizeof(filename) - 1,
SERVER_ACCESS.path_shortcuts,
conn->ipaddr, conn->revdns,
KeyPrintableHash(ConnectionInfoKey(conn->conn_info)));
if (zret == (size_t) -1)
{
goto protocol_error;
}
zret = PreprocessRequestPath(filename, sizeof(filename) - 1);
if (zret == (size_t) -1)
{
RefuseAccess(conn, recvbuffer);
return true;
}
/* OPENDIR *must* be directory. */
PathAppendTrailingSlash(filename, strlen(filename));
Log(LOG_LEVEL_VERBOSE, "%14s %7s %s",
"Translated to:", "OPENDIR", filename);
if (acl_CheckPath(paths_acl, filename,
conn->ipaddr, conn->revdns,
KeyPrintableHash(ConnectionInfoKey(conn->conn_info)))
== false)
{
Log(LOG_LEVEL_INFO, "access denied to OPENDIR: %s", filename);
RefuseAccess(conn, recvbuffer);
return true;
}
CfOpenDirectory(conn, sendbuffer, filename);
return true;
}
case PROTOCOL_COMMAND_SYNCH:
{
long time_no_see = 0;
memset(filename, 0, sizeof(filename));
int ret = sscanf(recvbuffer, "SYNCH %ld STAT %[^\n]",
&time_no_see, filename);
if (ret != 2 || filename[0] == '\0')
{
goto protocol_error;
}
time_t tloc = time(NULL);
if (tloc == -1)
{
/* Should never happen. */
Log(LOG_LEVEL_ERR, "Couldn't read system clock. (time: %s)", GetErrorStr());
SendTransaction(conn->conn_info, "BAD: clocks out of synch", 0, CF_DONE);
return true;
}
time_t trem = (time_t) time_no_see;
int drift = (int) (tloc - trem);
Log(LOG_LEVEL_VERBOSE, "%14s %7s %s",
"Received:", "STAT", filename);
/* sizeof()-1 because we need one extra byte for
appending '/' afterwards. */
size_t zret = ShortcutsExpand(filename, sizeof(filename) - 1,
SERVER_ACCESS.path_shortcuts,
conn->ipaddr, conn->revdns,
KeyPrintableHash(ConnectionInfoKey(conn->conn_info)));
if (zret == (size_t) -1)
{
goto protocol_error;
}
zret = PreprocessRequestPath(filename, sizeof(filename) - 1);
if (zret == (size_t) -1)
{
RefuseAccess(conn, recvbuffer);
return true;
}
if (IsDirReal(filename) == 1)
{
PathAppendTrailingSlash(filename, strlen(filename));
}
else
{
PathRemoveTrailingSlash(filename, strlen(filename));
}
Log(LOG_LEVEL_VERBOSE, "%14s %7s %s",
"Translated to:", "STAT", filename);
if (acl_CheckPath(paths_acl, filename,
conn->ipaddr, conn->revdns,
KeyPrintableHash(ConnectionInfoKey(conn->conn_info)))
== false)
{
Log(LOG_LEVEL_INFO, "access denied to STAT: %s", filename);
RefuseAccess(conn, recvbuffer);
return true;
}
Log(LOG_LEVEL_DEBUG, "Clocks were off by %ld",
(long) tloc - (long) trem);
if (DENYBADCLOCKS && (drift * drift > CLOCK_DRIFT * CLOCK_DRIFT))
{
snprintf(sendbuffer, sizeof(sendbuffer),
"BAD: Clocks are too far unsynchronized %ld/%ld",
(long) tloc, (long) trem);
Log(LOG_LEVEL_INFO, "denybadclocks %s", sendbuffer);
SendTransaction(conn->conn_info, sendbuffer, 0, CF_DONE);
return true;
}
StatFile(conn, sendbuffer, filename);
return true;
}
case PROTOCOL_COMMAND_MD5:
{
int ret = sscanf(recvbuffer, "MD5 %[^\n]", filename);
if (ret != 1)
{
goto protocol_error;
}
Log(LOG_LEVEL_VERBOSE, "%14s %7s %s",
"Received:", "MD5", filename);
/* TODO batch all the following in one function since it's very
* similar in all of GET, OPENDIR and STAT. */
size_t zret = ShortcutsExpand(filename, sizeof(filename),
SERVER_ACCESS.path_shortcuts,
conn->ipaddr, conn->revdns,
KeyPrintableHash(ConnectionInfoKey(conn->conn_info)));
if (zret == (size_t) -1)
{
goto protocol_error;
}
zret = PreprocessRequestPath(filename, sizeof(filename));
if (zret == (size_t) -1)
{
RefuseAccess(conn, recvbuffer);
return true;
}
PathRemoveTrailingSlash(filename, strlen(filename));
Log(LOG_LEVEL_VERBOSE, "%14s %7s %s",
"Translated to:", "MD5", filename);
if (acl_CheckPath(paths_acl, filename,
conn->ipaddr, conn->revdns,
KeyPrintableHash(ConnectionInfoKey(conn->conn_info)))
== false)
{
Log(LOG_LEVEL_INFO, "access denied to file: %s", filename);
RefuseAccess(conn, recvbuffer);
return true;
}
assert(CF_DEFAULT_DIGEST_LEN <= EVP_MAX_MD_SIZE);
unsigned char digest[EVP_MAX_MD_SIZE + 1];
assert(CF_BUFSIZE + CF_SMALL_OFFSET + CF_DEFAULT_DIGEST_LEN
<= sizeof(recvbuffer));
memcpy(digest, recvbuffer + strlen(recvbuffer) + CF_SMALL_OFFSET,
CF_DEFAULT_DIGEST_LEN);
CompareLocalHash(filename, digest, sendbuffer);
SendTransaction(conn->conn_info, sendbuffer, 0, CF_DONE);
return true;
}
case PROTOCOL_COMMAND_VAR:
{
char var[256];
int ret = sscanf(recvbuffer, "VAR %255[^\n]", var);
if (ret != 1)
{
goto protocol_error;
}
/* TODO if this is literals_acl, then when should I check vars_acl? */
if (acl_CheckExact(literals_acl, var,
conn->ipaddr, conn->revdns,
KeyPrintableHash(ConnectionInfoKey(conn->conn_info)))
== false)
{
Log(LOG_LEVEL_INFO, "access denied to variable: %s", var);
RefuseAccess(conn, recvbuffer);
return true;
}
GetServerLiteral(ctx, conn, sendbuffer, recvbuffer, encrypted);
return true;
}
case PROTOCOL_COMMAND_CONTEXT:
{
char client_regex[256];
int ret = sscanf(recvbuffer, "CONTEXT %255[^\n]", client_regex);
if (ret != 1)
{
goto protocol_error;
}
Log(LOG_LEVEL_VERBOSE, "%14s %7s %s",
"Received:", "CONTEXT", client_regex);
/* WARNING: this comes from legacy code and must be killed if we care
* about performance. We should not accept regular expressions from
* the client, but this will break backwards compatibility.
*
* I replicated the code in raw form here to emphasize complexity,
* it's the only *slow* command currently in the protocol. */
Item *persistent_classes = ListPersistentClasses();
Item *matched_classes = NULL;
/* For all persistent classes */
for (Item *ip = persistent_classes; ip != NULL; ip = ip->next)
{
const char *class_name = ip->name;
/* Does this class match the regex the client sent? */
if (StringMatchFull(client_regex, class_name))
{
/* Is this class allowed to be given to the specific
* host, according to the regexes in the ACLs? */
if (acl_CheckRegex(classes_acl, class_name,
conn->ipaddr, conn->revdns,
KeyPrintableHash(ConnectionInfoKey(conn->conn_info)),
NULL)
== true)
{
Log(LOG_LEVEL_DEBUG, "Access granted to class: %s",
class_name);
PrependItem(&matched_classes, class_name, NULL);
}
}
}
if (matched_classes == NULL)
{
Log(LOG_LEVEL_INFO,
"No allowed classes for remoteclassesmatching: %s",
client_regex);
RefuseAccess(conn, recvbuffer);
return true;
}
ReplyServerContext(conn, encrypted, matched_classes);
return true;
}
case PROTOCOL_COMMAND_QUERY:
{
char query[256], name[128];
int ret1 = sscanf(recvbuffer, "QUERY %255[^\n]", query);
int ret2 = sscanf(recvbuffer, "QUERY %127s", name);
if (ret1 != 1 || ret2 != 1)
{
goto protocol_error;
}
if (acl_CheckExact(query_acl, name,
conn->ipaddr, conn->revdns,
KeyPrintableHash(ConnectionInfoKey(conn->conn_info)))
== false)
{
Log(LOG_LEVEL_INFO, "access denied to query: %s", query);
RefuseAccess(conn, recvbuffer);
return true;
}
if (GetServerQuery(conn, recvbuffer, encrypted))
{
return true;
}
break;
}
case PROTOCOL_COMMAND_CALL_ME_BACK:
/* Server side, handing the collect call off to cf-hub. */
if (acl_CheckExact(query_acl, "collect_calls",
conn->ipaddr, conn->revdns,
KeyPrintableHash(ConnectionInfoKey(conn->conn_info)))
== false)
{
Log(LOG_LEVEL_INFO,
"access denied to Call-Collect, check the ACL for class: collect_calls");
return false;
}
ReceiveCollectCall(conn);
/* On success that returned true; otherwise, it did all
* relevant Log()ging. Either way, we're no longer busy with
* it and our caller can close the connection: */
return false;
case PROTOCOL_COMMAND_BAD:
Log(LOG_LEVEL_WARNING, "Unexpected protocol command: %s", recvbuffer);
}
/* We should only reach this point if something went really bad, and
* close connection. In all other cases (like access denied) connection
* shouldn't be closed.
*/
protocol_error:
strcpy(sendbuffer, "BAD: Request denied");
SendTransaction(conn->conn_info, sendbuffer, 0, CF_DONE);
Log(LOG_LEVEL_INFO,
"Closing connection due to illegal request: %s", recvbuffer);
return false;
}
cfengine-3.12.1/cf-serverd/server_classic.c 0000644 0000000 0000000 00000147465 13377750461 020623 0 ustar 00root root 0000000 0000000 /*
Copyright 2018 Northern.tech AS
This file is part of CFEngine 3 - written and maintained by Northern.tech AS.
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; version 3.
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, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
To the extent this program is licensed as part of the Enterprise
versions of CFEngine, the applicable Commercial Open Source License
(COSL) may apply to this file if you as a licensee so wish it. See
included file COSL.txt.
*/
#include
#include /* BN_* */
#include /* ERR_get_error */
#include
#include
#include /* IsMatchItemIn */
#include /* IsRegexItemIn */
#include /* ReceiveTransaction,SendTransaction */
#include
#include /* ToLowerStrInplace */
#include /* StringMatchFull */
#include /* LastSaw1 */
#include /* HashString */
#include /* HavePublicKey */
#include /* ReceiveCollectCall */
#include
#include "server.h" /* ServerConnectionState */
#include "server_common.h" /* ListPersistentClasses */
/* Functionality needed exclusively for the classic protocol. */
//*******************************************************************
// COMMANDS
//*******************************************************************
typedef enum
{
PROTOCOL_COMMAND_EXEC,
PROTOCOL_COMMAND_AUTH,
PROTOCOL_COMMAND_GET,
PROTOCOL_COMMAND_OPENDIR,
PROTOCOL_COMMAND_SYNC,
PROTOCOL_COMMAND_CONTEXTS,
PROTOCOL_COMMAND_MD5,
PROTOCOL_COMMAND_MD5_SECURE,
PROTOCOL_COMMAND_AUTH_PLAIN,
PROTOCOL_COMMAND_AUTH_SECURE,
PROTOCOL_COMMAND_SYNC_SECURE,
PROTOCOL_COMMAND_GET_SECURE,
PROTOCOL_COMMAND_VERSION,
PROTOCOL_COMMAND_OPENDIR_SECURE,
PROTOCOL_COMMAND_VAR,
PROTOCOL_COMMAND_VAR_SECURE,
PROTOCOL_COMMAND_CONTEXT,
PROTOCOL_COMMAND_CONTEXT_SECURE,
PROTOCOL_COMMAND_QUERY_SECURE,
PROTOCOL_COMMAND_CALL_ME_BACK,
PROTOCOL_COMMAND_BAD
} ProtocolCommandClassic;
static const char *PROTOCOL_CLASSIC[] =
{
"EXEC",
"AUTH", /* old protocol */
"GET",
"OPENDIR",
"SYNCH",
"CLASSES",
"MD5",
"SMD5",
"CAUTH",
"SAUTH",
"SSYNCH",
"SGET",
"VERSION",
"SOPENDIR",
"VAR",
"SVAR",
"CONTEXT",
"SCONTEXT",
"SQUERY",
"SCALLBACK",
NULL
};
static ProtocolCommandClassic GetCommandClassic(char *str)
{
int i;
for (i = 0; PROTOCOL_CLASSIC[i] != NULL; i++)
{
int cmdlen = strlen(PROTOCOL_CLASSIC[i]);
if ((strncmp(str, PROTOCOL_CLASSIC[i], cmdlen) == 0) &&
(str[cmdlen] == ' ' || str[cmdlen] == '\0'))
{
return i;
}
}
assert (i == PROTOCOL_COMMAND_BAD);
return i;
}
/* 'resolved' argument needs to be at least CF_BUFSIZE long */
static bool ResolveFilename(const char *req_path, char *res_path)
{
#if !defined _WIN32
if (realpath(req_path, res_path) == NULL)
{
return false;
}
#else
memset(res_path, 0, CF_BUFSIZE);
CompressPath(res_path, CF_BUFSIZE, req_path);
#endif
/* Adjust for forward slashes */
MapName(res_path);
/* NT has case-insensitive path names */
#ifdef __MINGW32__
int i;
for (i = 0; i < strlen(res_path); i++)
{
res_path[i] = ToLower(res_path[i]);
}
#endif /* __MINGW32__ */
return true;
}
static bool PathMatch(const char *stem, const char *request)
{
const size_t stemlen = strlen(stem);
if (strcmp(stem, FILE_SEPARATOR_STR) == 0)
{
/* Matches everything: */
return true;
}
if (strcmp(stem, request) == 0)
{
/* An exact match is a match: */
return true;
}
/* Otherwise, match only if stem names a parent directory of request: */
return (strlen(request) > stemlen &&
request[stemlen] == FILE_SEPARATOR &&
strncmp(stem, request, stemlen) == 0);
}
static int AccessControl(EvalContext *ctx, const char *req_path, ServerConnectionState *conn, int encrypt)
{
int access = false;
char transrequest[CF_BUFSIZE];
struct stat statbuf;
char translated_req_path[CF_BUFSIZE];
char transpath[CF_BUFSIZE];
/*
* /var/cfengine -> $workdir translation.
*/
TranslatePath(translated_req_path, req_path);
if (ResolveFilename(translated_req_path, transrequest))
{
Log(LOG_LEVEL_VERBOSE, "Filename %s is resolved to %s", translated_req_path, transrequest);
}
else if ((lstat(translated_req_path, &statbuf) == -1) && !S_ISLNK(statbuf.st_mode))
{
Log(LOG_LEVEL_INFO, "Couldn't resolve (realpath: %s) filename: %s",
GetErrorStr(), translated_req_path);
return false; /* can't continue without transrequest */
}
else
{
Log(LOG_LEVEL_VERBOSE, "Requested file is a dead symbolic link (filename: %s)", translated_req_path);
strlcpy(transrequest, translated_req_path, CF_BUFSIZE);
}
if (lstat(transrequest, &statbuf) == -1)
{
Log(LOG_LEVEL_INFO, "Couldn't stat (lstat: %s) filename: %s",
GetErrorStr(), transrequest);
return false;
}
Log(LOG_LEVEL_DEBUG, "AccessControl, match (%s,%s) encrypt request = %d", transrequest, conn->hostname, encrypt);
if (SERVER_ACCESS.admit == NULL)
{
Log(LOG_LEVEL_INFO, "cf-serverd access list is empty, no files are visible");
return false;
}
conn->maproot = false;
for (Auth *ap = SERVER_ACCESS.admit; ap != NULL; ap = ap->next)
{
Log(LOG_LEVEL_DEBUG, "Examining rule in access list (%s,%s)", transrequest, ap->path);
/* TODO MapName when constructing this list. */
strlcpy(transpath, ap->path, CF_BUFSIZE);
MapName(transpath);
if (PathMatch(transpath, transrequest))
{
Log(LOG_LEVEL_VERBOSE, "Found a matching rule in access list (%s in %s)", transrequest, transpath);
if (stat(transpath, &statbuf) == -1)
{
Log(LOG_LEVEL_INFO,
"Warning cannot stat file object %s in admit/grant, or access list refers to dangling link",
transpath);
continue;
}
if (!encrypt && ap->encrypt)
{
Log(LOG_LEVEL_ERR, "File %s requires encrypt connection...will not serve", transpath);
access = false;
}
else
{
Log(LOG_LEVEL_DEBUG, "Checking whether to map root privileges..");
if (IsMatchItemIn(ap->maproot, conn->ipaddr) ||
IsRegexItemIn(ctx, ap->maproot, conn->hostname))
{
conn->maproot = true;
Log(LOG_LEVEL_VERBOSE, "Mapping root privileges to access non-root files");
}
if (IsMatchItemIn(ap->accesslist, conn->ipaddr) ||
IsRegexItemIn(ctx, ap->accesslist, conn->hostname))
{
access = true;
Log(LOG_LEVEL_DEBUG, "Access granted to host: %s", conn->ipaddr);
}
}
break;
}
}
for (Auth *dp = SERVER_ACCESS.deny; dp != NULL; dp = dp->next)
{
strlcpy(transpath, dp->path, CF_BUFSIZE);
MapName(transpath);
if (PathMatch(transpath, transrequest))
{
if ((IsMatchItemIn(dp->accesslist, conn->ipaddr)) ||
(IsRegexItemIn(ctx, dp->accesslist, conn->hostname)))
{
access = false;
Log(LOG_LEVEL_INFO,
"Host '%s' in deny list, explicitly denying access to '%s' in '%s'",
conn->ipaddr, transrequest, transpath);
break;
}
}
}
if (access)
{
Log(LOG_LEVEL_VERBOSE, "Host %s granted access to %s", conn->hostname, req_path);
if (encrypt && LOGENCRYPT)
{
/* Log files that were marked as requiring encryption */
Log(LOG_LEVEL_INFO, "Host %s granted access to %s", conn->hostname, req_path);
}
}
else
{
Log(LOG_LEVEL_INFO, "Host %s denied access to %s", conn->hostname, req_path);
}
return access;
}
/* Checks the "varadmit" legacy ACL. */
static int LiteralAccessControl(EvalContext *ctx, char *in, ServerConnectionState *conn, int encrypt)
{
Auth *ap;
int access = false;
char name[CF_BUFSIZE];
name[0] = '\0';
if (strncmp(in, "VAR", 3) == 0)
{
sscanf(in, "VAR %255[^\n]", name);
}
else if (strncmp(in, "CALL_ME_BACK", strlen("CALL_ME_BACK")) == 0)
{
sscanf(in, "CALL_ME_BACK %255[^\n]", name);
}
else
{
sscanf(in, "QUERY %128s", name);
}
conn->maproot = false;
for (ap = SERVER_ACCESS.varadmit; ap != NULL; ap = ap->next)
{
Log(LOG_LEVEL_VERBOSE, "Examining rule in access list (%s,%s)?", name, ap->path);
if (strcmp(ap->path, name) == 0) /* exact match */
{
Log(LOG_LEVEL_VERBOSE, "Found a matching rule in access list (%s in %s)", name, ap->path);
if ((!ap->literal) && (!ap->variable))
{
Log(LOG_LEVEL_ERR,
"Variable/query '%s' requires a literal server item...cannot set variable directly by path",
ap->path);
access = false;
break;
}
if (!encrypt && ap->encrypt)
{
Log(LOG_LEVEL_ERR, "Variable %s requires encrypt connection...will not serve", name);
access = false;
break;
}
else
{
Log(LOG_LEVEL_DEBUG, "Checking whether to map root privileges");
if ((IsMatchItemIn(ap->maproot, conn->ipaddr)) ||
(IsRegexItemIn(ctx, ap->maproot, conn->hostname)))
{
conn->maproot = true;
Log(LOG_LEVEL_VERBOSE, "Mapping root privileges");
}
else
{
Log(LOG_LEVEL_VERBOSE, "No root privileges granted");
}
if ((IsMatchItemIn(ap->accesslist, conn->ipaddr))
|| (IsRegexItemIn(ctx, ap->accesslist, conn->hostname)))
{
access = true;
Log(LOG_LEVEL_DEBUG, "Access privileges - match found");
}
}
}
}
for (ap = SERVER_ACCESS.vardeny; ap != NULL; ap = ap->next)
{
if (strcmp(ap->path, name) == 0)
{
if ((IsMatchItemIn(ap->accesslist, conn->ipaddr))
|| (IsRegexItemIn(ctx, ap->accesslist, conn->hostname)))
{
access = false;
Log(LOG_LEVEL_VERBOSE, "Host %s explicitly denied access to %s", conn->hostname, name);
break;
}
}
}
if (access)
{
Log(LOG_LEVEL_VERBOSE, "Host %s granted access to literal '%s'", conn->hostname, name);
if (encrypt && LOGENCRYPT)
{
/* Log files that were marked as requiring encryption */
Log(LOG_LEVEL_INFO, "Host %s granted access to literal '%s'", conn->hostname, name);
}
}
else
{
Log(LOG_LEVEL_VERBOSE, "Host %s denied access to literal '%s'", conn->hostname, name);
}
return access;
}
/* Checks the "varadmit" legacy ACL. */
static Item *ContextAccessControl(EvalContext *ctx, char *in, ServerConnectionState *conn, int encrypt)
{
Auth *ap;
int access = false;
char client_regex[CF_BUFSIZE];
Item *ip, *matches = NULL;
int ret = sscanf(in, "CONTEXT %255[^\n]", client_regex);
Item *persistent_classes = ListPersistentClasses();
if (ret != 1 || persistent_classes == NULL)
{
return NULL;
}
for (ip = persistent_classes; ip != NULL; ip = ip->next)
{
/* Does the class match the regex that the agent requested? */
if (StringMatchFull(client_regex, ip->name))
{
for (ap = SERVER_ACCESS.varadmit; ap != NULL; ap = ap->next)
{
/* Does the class match any of the regex in ACLs? */
if (StringMatchFull(ap->path, ip->name))
{
Log(LOG_LEVEL_VERBOSE,
"Found a matching rule in access list (%s in %s)",
ip->name, ap->path);
if (!ap->classpattern)
{
Log(LOG_LEVEL_ERR,
"Context %s requires a literal server item... "
"cannot set variable directly by path",
ap->path);
access = false;
continue;
}
if (!encrypt && ap->encrypt)
{
Log(LOG_LEVEL_ERR,
"Context %s requires encrypt connection... "
"will not serve",
ip->name);
access = false;
break;
}
else
{
Log(LOG_LEVEL_DEBUG,
"Checking whether to map root privileges");
if ((IsMatchItemIn(ap->maproot, conn->ipaddr))
|| (IsRegexItemIn(ctx, ap->maproot, conn->hostname)))
{
conn->maproot = true;
Log(LOG_LEVEL_VERBOSE,
"Mapping root privileges");
}
else
{
Log(LOG_LEVEL_VERBOSE,
"No root privileges granted");
}
if ((IsMatchItemIn(ap->accesslist, conn->ipaddr))
|| (IsRegexItemIn(ctx, ap->accesslist, conn->hostname)))
{
access = true;
Log(LOG_LEVEL_DEBUG,
"Access privileges - match found");
}
}
}
}
for (ap = SERVER_ACCESS.vardeny; ap != NULL; ap = ap->next)
{
if (strcmp(ap->path, ip->name) == 0)
{
if ((IsMatchItemIn(ap->accesslist, conn->ipaddr))
|| (IsRegexItemIn(ctx, ap->accesslist, conn->hostname)))
{
access = false;
Log(LOG_LEVEL_VERBOSE,
"Host %s explicitly denied access to context %s",
conn->hostname, ip->name);
break;
}
}
}
if (access)
{
Log(LOG_LEVEL_VERBOSE,
"Host %s granted access to context '%s'",
conn->hostname, ip->name);
AppendItem(&matches, ip->name, NULL);
if (encrypt && LOGENCRYPT)
{
/* Log files that were marked as requiring encryption */
Log(LOG_LEVEL_INFO,
"Host %s granted access to context '%s'",
conn->hostname, ip->name);
}
}
else
{
Log(LOG_LEVEL_VERBOSE,
"Host %s denied access to context '%s'",
conn->hostname, ip->name);
}
}
}
DeleteItemList(persistent_classes);
return matches;
}
static int cfscanf(char *in, int len1, int len2, char *out1, char *out2, char *out3)
{
int len3 = 0;
char *sp;
sp = in;
memcpy(out1, sp, len1);
out1[len1] = '\0';
sp += len1 + 1;
memcpy(out2, sp, len2);
sp += len2 + 1;
len3 = strlen(sp);
memcpy(out3, sp, len3);
out3[len3] = '\0';
return (len1 + len2 + len3 + 2);
}
static void SetConnectionData(ServerConnectionState *conn, char *buf)
{
char ipstring[CF_MAXVARSIZE], fqname[CF_MAXVARSIZE], username[CF_MAXVARSIZE];
Log(LOG_LEVEL_DEBUG, "Connecting host identifies itself as '%s'", buf);
memset(ipstring, 0, CF_MAXVARSIZE);
memset(fqname, 0, CF_MAXVARSIZE);
memset(username, 0, CF_MAXVARSIZE);
sscanf(buf, "%255s %255s %255s", ipstring, fqname, username);
/* The "ipstring" that the client sends is currently *ignored* as
* conn->ipaddr is always set from the connecting socket address. */
Log(LOG_LEVEL_DEBUG, "(ipstring=[%s],fqname=[%s],username=[%s],socket=[%s])",
ipstring, fqname, username, conn->ipaddr);
ToLowerStrInplace(fqname);
strlcpy(conn->hostname, fqname, CF_MAXVARSIZE);
SetConnIdentity(conn, username);
}
static int CheckStoreKey(ServerConnectionState *conn, RSA *key)
{
RSA *savedkey;
const char *udigest = KeyPrintableHash(ConnectionInfoKey(conn->conn_info));
assert(udigest != NULL);
if ((savedkey = HavePublicKey(conn->username, conn->ipaddr, udigest)))
{
Log(LOG_LEVEL_VERBOSE,
"A public key was already known from %s/%s - no trust required",
conn->hostname, conn->ipaddr);
const BIGNUM *key_n, *key_e, *savedkey_n, *savedkey_e;
RSA_get0_key(key, &key_n, &key_e, NULL);
RSA_get0_key(savedkey, &savedkey_n, &savedkey_e, NULL);
if ((BN_cmp(savedkey_e, key_e) == 0) && (BN_cmp(savedkey_n, key_n) == 0))
{
Log(LOG_LEVEL_VERBOSE,
"The public key identity was confirmed as %s@%s",
conn->username, conn->hostname);
SendTransaction(conn->conn_info, "OK: key accepted", 0, CF_DONE);
RSA_free(savedkey);
return true;
}
}
/* Finally, if we're still here then the key is new (not in ppkeys
* directory): Allow access only if host is listed in "trustkeysfrom" body
* server control option. */
if ((SERVER_ACCESS.trustkeylist != NULL) &&
(IsMatchItemIn(SERVER_ACCESS.trustkeylist, conn->ipaddr)))
{
Log(LOG_LEVEL_VERBOSE,
"Host %s/%s was found in the list of hosts to trust",
conn->hostname, conn->ipaddr);
SendTransaction(conn->conn_info,
"OK: unknown key was accepted on trust", 0, CF_DONE);
SavePublicKey(conn->username, udigest, key);
return true;
}
else
{
Log(LOG_LEVEL_VERBOSE,
"No previous key found, and unable to accept this one on trust");
SendTransaction(conn->conn_info,
"BAD: key could not be accepted on trust",
0, CF_DONE);
return false;
}
}
static int AuthenticationDialogue(ServerConnectionState *conn, char *recvbuffer, int recvlen)
{
unsigned char digest[EVP_MAX_MD_SIZE + 1] = { 0 };
if (PRIVKEY == NULL || PUBKEY == NULL)
{
Log(LOG_LEVEL_ERR, "No public/private key pair is loaded,"
" please create one using cf-key");
return false;
}
int PRIVKEY_size = RSA_size(PRIVKEY);
int digestLen;
HashMethod digestType;
if (FIPS_MODE)
{
digestType = CF_DEFAULT_DIGEST;
digestLen = CF_DEFAULT_DIGEST_LEN;
}
else
{
digestType = HASH_METHOD_MD5;
digestLen = CF_MD5_LEN;
}
/* parameters received in SAUTH command */
char iscrypt, enterprise_field;
/* proposition C1 - SAUTH command */
{
char sauth[10] = { 0 };
unsigned int crypt_len; /* received encrypted challenge length */
unsigned int challenge_len; /* challenge length after decryption */
int nparam = sscanf(recvbuffer, "%9s %c %u %u %c",
sauth, &iscrypt, &crypt_len,
&challenge_len, &enterprise_field);
if (nparam >= 1 && strcmp(sauth, "SAUTH") != 0)
{
Log(LOG_LEVEL_ERR, "Authentication failure: "
"was expecting SAUTH command but got '%s'",
sauth);
return false;
}
if (nparam != 5 && nparam != 4)
{
Log(LOG_LEVEL_ERR, "Authentication failure: "
"peer sent only %d arguments to SAUTH command",
nparam - 1);
return false;
}
/* CFEngine 2 had no enterprise/community differentiation. */
if (nparam == 4)
{
Log(LOG_LEVEL_VERBOSE,
"Peer sent only 4 parameters, "
"assuming it is a legacy community client");
enterprise_field = 'c';
}
if ((challenge_len == 0) || (crypt_len == 0))
{
Log(LOG_LEVEL_ERR,
"Authentication failure: received unexpected challenge length "
"(%u that decrypts to %u bytes)",
challenge_len, crypt_len);
return false;
}
if (crypt_len > CF_NONCELEN * 2)
{
Log(LOG_LEVEL_ERR, "Authentication failure: "
"received encrypted challenge is too long "
"(%d bytes)", crypt_len);
return false;
}
if (challenge_len > CF_NONCELEN * 2)
{
Log(LOG_LEVEL_ERR, "Authentication failure: "
"received challenge is too long (%u bytes)",
challenge_len);
return false;
}
Log(LOG_LEVEL_DEBUG,
"Challenge encryption = %c, challenge_len = %u, crypt_len = %u",
iscrypt, challenge_len, crypt_len);
char *challenge;
char decrypted_challenge[PRIVKEY_size];
if (iscrypt == 'y') /* challenge came encrypted */
{
if (recvlen < CF_RSA_PROTO_OFFSET + crypt_len)
{
Log(LOG_LEVEL_ERR, "Authentication failure: peer sent only %d "
"bytes as encrypted challenge but claims to have sent %u bytes",
recvlen - CF_RSA_PROTO_OFFSET, crypt_len);
}
int ret = RSA_private_decrypt(crypt_len, recvbuffer + CF_RSA_PROTO_OFFSET,
decrypted_challenge, PRIVKEY, RSA_PKCS1_PADDING);
if (ret < 0)
{
Log(LOG_LEVEL_ERR, "Authentication failure: "
"private decrypt of received challenge failed (%s)",
CryptoLastErrorString());
Log(LOG_LEVEL_ERR,
"Probably the client has wrong public key for this server");
return false;
}
if (ret != challenge_len)
{
Log(LOG_LEVEL_ERR, "Authentication failure: "
"private decrypt of received challenge (%u bytes) "
"resulted in %d bytes instead of promised %u bytes",
crypt_len, ret, challenge_len);
return false;
}
challenge = decrypted_challenge;
}
else /* challenge came unencrypted */
{
if (challenge_len != crypt_len)
{
Log(LOG_LEVEL_ERR,
"Authentication failure: peer sent illegal challenge "
"(challenge_len %u != crypt_len %u)",
challenge_len, crypt_len);
return false;
}
if (recvlen < CF_RSA_PROTO_OFFSET + challenge_len)
{
Log(LOG_LEVEL_ERR,
"Authentication failure: peer sent only %d "
"bytes as challenge but claims to have sent %u bytes",
recvlen - CF_RSA_PROTO_OFFSET, challenge_len);
return false;
}
challenge = &recvbuffer[CF_RSA_PROTO_OFFSET];
}
/* Client's ID is now established by key or trusted, reply with digest */
HashString(challenge, challenge_len, digest, digestType);
}
BIGNUM *newkey_n, *newkey_e;
/* proposition C2 - Receive client's public key modulus */
{
int len_n = ReceiveTransaction(conn->conn_info, recvbuffer, NULL);
if (len_n == -1)
{
Log(LOG_LEVEL_ERR, "Authentication failure: "
"error while receiving public key modulus");
return false;
}
if ((newkey_n = BN_mpi2bn(recvbuffer, len_n, NULL)) == NULL)
{
Log(LOG_LEVEL_ERR, "Authentication failure: "
"private decrypt of received public key modulus failed "
"(%s)", CryptoLastErrorString());
return false;
}
}
/* proposition C3 - Receive client's public key exponent. */
{
int len_e = ReceiveTransaction(conn->conn_info, recvbuffer, NULL);
if (len_e == -1)
{
Log(LOG_LEVEL_ERR, "Authentication failure: "
"error while receiving public key exponent");
return false;
}
if ((newkey_e = BN_mpi2bn(recvbuffer, len_e, NULL)) == NULL)
{
Log(LOG_LEVEL_ERR, "Authentication failure: "
"private decrypt of received public key exponent failed "
"(%s)", CryptoLastErrorString());
BN_free(newkey_n);
return false;
}
}
RSA *newkey = RSA_new();
if (newkey == NULL)
{
Log(LOG_LEVEL_ERR, "Failed to allocate RSA key: %s",
TLSErrorString(ERR_get_error()));
BN_free(newkey_n);
BN_free(newkey_e);
return false;
}
if (RSA_set0_key(newkey, newkey_n, newkey_e, NULL) != 1)
{
Log(LOG_LEVEL_ERR, "Failed to set RSA key: %s",
TLSErrorString(ERR_get_error()));
BN_free(newkey_n);
BN_free(newkey_e);
RSA_free(newkey);
return false;
}
/* Compute and store hash of the client's public key. */
{
Key *key = KeyNew(newkey, CF_DEFAULT_DIGEST);
conn->conn_info->remote_key = key;
Log(LOG_LEVEL_VERBOSE, "Peer's identity is: %s",
KeyPrintableHash(key));
LastSaw1(conn->ipaddr, KeyPrintableHash(key),
LAST_SEEN_ROLE_ACCEPT);
/* Do we want to trust the received key? */
if (!CheckStoreKey(conn, newkey)) /* conceals proposition S1 */
{
return false;
}
}
/* proposition S2 - reply with digest of challenge. */
{
Log(LOG_LEVEL_DEBUG, "Sending challenge response");
SendTransaction(conn->conn_info, digest, digestLen, CF_DONE);
}
/* proposition S3 - send counter-challenge */
{
BIGNUM *counter_challenge_BN = BN_new();
if (counter_challenge_BN == NULL)
{
Log(LOG_LEVEL_ERR, "Authentication failure: "
"cannot allocate BIGNUM structure for counter-challenge");
return false;
}
BN_rand(counter_challenge_BN, CF_NONCELEN, 0, 0);
char counter_challenge[CF_BUFSIZE];
int counter_challenge_len = BN_bn2mpi(counter_challenge_BN, counter_challenge);
BN_free(counter_challenge_BN);
/* Compute counter-challenge digest. */
HashString(counter_challenge, counter_challenge_len, digest, digestType);
/* Encryption buffer is always RSA_size(key) and buffer needs 11 bytes,
* see RSA_public_encrypt manual. */
int encrypted_len = RSA_size(newkey);
char encrypted_counter_challenge[encrypted_len];
assert(counter_challenge_len < encrypted_len - 11);
int ret = RSA_public_encrypt(counter_challenge_len, counter_challenge,
encrypted_counter_challenge, newkey,
RSA_PKCS1_PADDING);
if (ret != encrypted_len)
{
if (ret == -1)
{
Log(LOG_LEVEL_ERR, "Authentication failure: "
"public encryption of counter-challenge failed "
"(%s)", CryptoLastErrorString());
}
else
{
Log(LOG_LEVEL_ERR, "Authentication failure: "
"public encryption of counter-challenge failed "
"(result length %d but should be %d)",
ret, encrypted_len);
}
return false;
}
Log(LOG_LEVEL_DEBUG, "Sending counter-challenge");
SendTransaction(conn->conn_info, encrypted_counter_challenge,
encrypted_len, CF_DONE);
}
/* proposition S4, S5 - If the client doesn't have our public key, send it. */
{
if (iscrypt != 'y')
{
Log(LOG_LEVEL_DEBUG, "Sending server's public key");
char bignum_buf[CF_BUFSIZE] = { 0 };
const BIGNUM *n, *e;
RSA_get0_key(PUBKEY, &n, &e, NULL);
/* proposition S4 - conditional */
int len_n = BN_bn2mpi(n, bignum_buf);
SendTransaction(conn->conn_info, bignum_buf, len_n, CF_DONE);
/* proposition S5 - conditional */
int len_e = BN_bn2mpi(e, bignum_buf);
SendTransaction(conn->conn_info, bignum_buf, len_e, CF_DONE);
}
}
/* proposition C4 - Receive counter-challenge response. */
{
char recv_buf[CF_BUFSIZE] = { 0 };
int recv_len = ReceiveTransaction(conn->conn_info, recv_buf, NULL);
if (recv_len < digestLen)
{
if (recv_len == -1)
{
Log(LOG_LEVEL_ERR, "Authentication failure: "
"error receiving counter-challenge response; "
"maybe the client does not trust our key?");
}
else /* 0 < recv_len < expected_len */
{
Log(LOG_LEVEL_ERR, "Authentication failure: "
"error receiving counter-challenge response, "
"only got %d out of %d bytes",
recv_len, digestLen);
}
return false;
}
if (HashesMatch(digest, recv_buf, digestType))
{
Log(LOG_LEVEL_VERBOSE,
"Authentication of client %s/%s achieved",
conn->hostname, conn->ipaddr);
}
else
{
Log(LOG_LEVEL_ERR, "Authentication failure: "
"counter-challenge response was incorrect");
return false;
}
}
/* proposition C5 - Receive session key */
{
Log(LOG_LEVEL_DEBUG, "Receiving session key from client...");
char session_key[CF_BUFSIZE] = { 0 };
int session_key_size = CfSessionKeySize(enterprise_field);
int keylen = ReceiveTransaction(conn->conn_info, session_key, NULL);
Log(LOG_LEVEL_DEBUG,
"Received encrypted session key of %d bytes, "
"should decrypt to %d bytes",
keylen, session_key_size);
if (keylen == -1)
{
Log(LOG_LEVEL_ERR, "Authentication failure: "
"error receiving session key");
return false;
}
if (keylen > CF_BUFSIZE / 2)
{
Log(LOG_LEVEL_ERR, "Authentication failure: "
"session key received is too long (%d bytes)",
keylen);
return false;
}
conn->session_key = xmalloc(session_key_size);
conn->encryption_type = enterprise_field;
if (keylen == CF_BLOWFISHSIZE) /* Support the old non-ecnrypted for upgrade */
{
memcpy(conn->session_key, session_key, session_key_size);
}
else
{
char decrypted_session_key[PRIVKEY_size];
int ret = RSA_private_decrypt(keylen, session_key,
decrypted_session_key, PRIVKEY,
RSA_PKCS1_PADDING);
if (ret != session_key_size)
{
if (ret < 0)
{
Log(LOG_LEVEL_ERR, "Authentication failure: "
"private decrypt of session key failed "
"(%s)", CryptoLastErrorString());
}
else
{
Log(LOG_LEVEL_ERR, "Authentication failure: "
"session key decrypts to invalid size, "
"expected %d but got %d bytes",
session_key_size, ret);
}
return false;
}
memcpy(conn->session_key, decrypted_session_key, session_key_size);
}
}
return true;
}
int BusyWithClassicConnection(EvalContext *ctx, ServerConnectionState *conn)
{
time_t tloc, trem = 0;
char recvbuffer[CF_BUFSIZE + CF_BUFEXT], check[CF_BUFSIZE];
char sendbuffer[CF_BUFSIZE] = { 0 };
char filename[CF_BUFSIZE], buffer[CF_BUFSIZE], out[CF_BUFSIZE];
long time_no_see = 0;
unsigned int len = 0;
int drift, plainlen, received, encrypted = 0;
size_t zret;
ServerFileGetState get_args;
Item *classes;
memset(recvbuffer, 0, CF_BUFSIZE + CF_BUFEXT);
memset(&get_args, 0, sizeof(get_args));
received = ReceiveTransaction(conn->conn_info, recvbuffer, NULL);
if (received == -1)
{
return false;
}
if (strlen(recvbuffer) == 0)
{
Log(LOG_LEVEL_WARNING, "Got NULL transmission, skipping!");
return true;
}
/* Don't process request if we're signalled to exit. */
if (IsPendingTermination())
{
Log(LOG_LEVEL_VERBOSE, "Server must exit, closing connection");
return false;
}
ProtocolCommandClassic command = GetCommandClassic(recvbuffer);
switch (command)
{
/* Plain text authentication; this MUST be the first command client
using classic protocol is sending. */
case PROTOCOL_COMMAND_AUTH_PLAIN:
SetConnectionData(conn, (char *) (recvbuffer + strlen("CAUTH ")));
if (!IsUserNameValid(conn->username))
{
Log(LOG_LEVEL_INFO, "Client is sending wrong username: %s",
conn->username);
RefuseAccess(conn, recvbuffer);
return false;
}
/* This is used only for forcing correct state of state machine while
connecting and authenticating user using classic protocol. */
conn->user_data_set = true;
return true;
/* This MUST be exactly second command client using classic protocol is
sending. This is where key agreement takes place. */
case PROTOCOL_COMMAND_AUTH_SECURE:
/* First command was omitted by client; this is protocol violation. */
if (!conn->user_data_set)
{
Log(LOG_LEVEL_INFO,
"Client is not verified; rejecting connection");
RefuseAccess(conn, recvbuffer);
return false;
}
conn->rsa_auth = AuthenticationDialogue(conn, recvbuffer, received);
if (!conn->rsa_auth)
{
Log(LOG_LEVEL_INFO, "Auth dialogue error");
RefuseAccess(conn, recvbuffer);
return false;
}
return true;
default:
break;
}
/* At this point we should have both user_data_set and rsa_auth set to
perform any operation. We can check only for second one as without
first it won't be set up. */
if (!conn->rsa_auth)
{
Log(LOG_LEVEL_INFO,
"REFUSAL due to no RSA authentication (command: %d)",
command);
RefuseAccess(conn, recvbuffer);
return false;
}
/* We have to have key at this point. */
assert(conn->session_key);
/* At this point we can safely do next switch and make sure user is
* authenticated. */
switch (command)
{
case PROTOCOL_COMMAND_EXEC:
{
const size_t EXEC_len = strlen(PROTOCOL_CLASSIC[PROTOCOL_COMMAND_EXEC]);
/* Assert recvbuffer starts with EXEC. */
assert(strncmp(PROTOCOL_CLASSIC[PROTOCOL_COMMAND_EXEC],
recvbuffer, EXEC_len) == 0);
char *args = &recvbuffer[EXEC_len];
args += strspn(args, " \t"); /* bypass spaces */
Log(LOG_LEVEL_VERBOSE, "%14s %7s %s",
"Received:", "EXEC", args);
bool b = DoExec2(ctx, conn, args,
sendbuffer, sizeof(sendbuffer));
/* In the end we might keep the connection open (return true) to be
* ready for next requests, but we must always send the TERMINATOR
* string so that the client can close the connection at will. */
Terminate(conn->conn_info);
return b;
}
case PROTOCOL_COMMAND_VERSION:
snprintf(sendbuffer, sizeof(sendbuffer), "OK: %s", Version());
SendTransaction(conn->conn_info, sendbuffer, 0, CF_DONE);
return conn->user_data_set;
case PROTOCOL_COMMAND_GET:
memset(filename, 0, CF_BUFSIZE);
sscanf(recvbuffer, "GET %d %[^\n]", &(get_args.buf_size), filename);
if ((get_args.buf_size < 0) || (get_args.buf_size > CF_BUFSIZE))
{
Log(LOG_LEVEL_INFO, "GET buffer out of bounds");
RefuseAccess(conn, recvbuffer);
return false;
}
zret = ShortcutsExpand(filename, sizeof(filename),
SERVER_ACCESS.path_shortcuts,
conn->ipaddr, conn->hostname,
KeyPrintableHash(ConnectionInfoKey(conn->conn_info)));
if (zret == (size_t) -1)
{
Log(LOG_LEVEL_VERBOSE, "Expanding filename (%s) made it too long (>= %zu)", filename, sizeof(filename));
return false;
}
if (!AccessControl(ctx, filename, conn, false))
{
Log(LOG_LEVEL_INFO, "Access denied to get object");
RefuseAccess(conn, recvbuffer);
return true;
}
memset(sendbuffer, 0, sizeof(sendbuffer));
if (get_args.buf_size >= CF_BUFSIZE)
{
get_args.buf_size = 2048;
}
get_args.conn = conn;
get_args.encrypt = false;
get_args.replybuff = sendbuffer;
get_args.replyfile = filename;
CfGetFile(&get_args);
return true;
case PROTOCOL_COMMAND_GET_SECURE:
memset(buffer, 0, CF_BUFSIZE);
sscanf(recvbuffer, "SGET %u %d", &len, &(get_args.buf_size));
if (received != len + CF_PROTO_OFFSET)
{
Log(LOG_LEVEL_INFO, "Protocol error SGET");
RefuseAccess(conn, recvbuffer);
return false;
}
plainlen = DecryptString(buffer, sizeof(buffer),
recvbuffer + CF_PROTO_OFFSET, len,
conn->encryption_type, conn->session_key);
cfscanf(buffer, strlen("GET"), strlen("dummykey"), check, sendbuffer, filename);
if (strcmp(check, "GET") != 0)
{
Log(LOG_LEVEL_INFO, "SGET/GET problem");
RefuseAccess(conn, recvbuffer);
return true;
}
if ((get_args.buf_size < 0) || (get_args.buf_size > 8192))
{
Log(LOG_LEVEL_INFO, "SGET bounding error");
RefuseAccess(conn, recvbuffer);
return false;
}
if (get_args.buf_size >= CF_BUFSIZE)
{
get_args.buf_size = 2048;
}
zret = ShortcutsExpand(filename, sizeof(filename),
SERVER_ACCESS.path_shortcuts,
conn->ipaddr, conn->hostname,
KeyPrintableHash(ConnectionInfoKey(conn->conn_info)));
if (zret == (size_t) -1)
{
Log(LOG_LEVEL_VERBOSE, "Expanding filename (%s) made it too long (>= %zu)", filename, sizeof(filename));
return false;
}
Log(LOG_LEVEL_DEBUG, "Confirm decryption, and thus validity of caller");
Log(LOG_LEVEL_DEBUG, "SGET '%s' with blocksize %d", filename, get_args.buf_size);
if (!AccessControl(ctx, filename, conn, true))
{
Log(LOG_LEVEL_INFO, "Access control error");
RefuseAccess(conn, recvbuffer);
return false;
}
memset(sendbuffer, 0, sizeof(sendbuffer));
get_args.conn = conn;
get_args.encrypt = true;
get_args.replybuff = sendbuffer;
get_args.replyfile = filename;
CfEncryptGetFile(&get_args);
return true;
case PROTOCOL_COMMAND_OPENDIR_SECURE:
memset(buffer, 0, CF_BUFSIZE);
sscanf(recvbuffer, "SOPENDIR %u", &len);
if ((len >= sizeof(out)) || (received != (len + CF_PROTO_OFFSET)))
{
Log(LOG_LEVEL_INFO, "Protocol error OPENDIR: %d", len);
RefuseAccess(conn, recvbuffer);
return false;
}
memcpy(out, recvbuffer + CF_PROTO_OFFSET, len);
plainlen = DecryptString(recvbuffer, sizeof(recvbuffer),
out, len,
conn->encryption_type, conn->session_key);
if (strncmp(recvbuffer, "OPENDIR", 7) != 0)
{
Log(LOG_LEVEL_INFO, "Opendir failed to decrypt");
RefuseAccess(conn, recvbuffer);
return true;
}
memset(filename, 0, CF_BUFSIZE);
sscanf(recvbuffer, "OPENDIR %[^\n]", filename);
zret = ShortcutsExpand(filename, sizeof(filename),
SERVER_ACCESS.path_shortcuts,
conn->ipaddr, conn->hostname,
KeyPrintableHash(ConnectionInfoKey(conn->conn_info)));
if (zret == (size_t) -1)
{
Log(LOG_LEVEL_VERBOSE, "Expanding filename (%s) made it too long (>= %zu)", filename, sizeof(filename));
return false;
}
if (!AccessControl(ctx, filename, conn, true)) /* opendir don't care about privacy */
{
Log(LOG_LEVEL_INFO, "Access error");
RefuseAccess(conn, recvbuffer);
return false;
}
CfSecOpenDirectory(conn, sendbuffer, filename);
return true;
case PROTOCOL_COMMAND_OPENDIR:
memset(filename, 0, CF_BUFSIZE);
sscanf(recvbuffer, "OPENDIR %[^\n]", filename);
zret = ShortcutsExpand(filename, sizeof(filename),
SERVER_ACCESS.path_shortcuts,
conn->ipaddr, conn->hostname,
KeyPrintableHash(ConnectionInfoKey(conn->conn_info)));
if (zret == (size_t) -1)
{
Log(LOG_LEVEL_VERBOSE, "Expanding filename (%s) made it too long (>= %zu)", filename, sizeof(filename));
return false;
}
if (!AccessControl(ctx, filename, conn, false)) /* opendir don't care about privacy */
{
Log(LOG_LEVEL_INFO, "DIR access error");
RefuseAccess(conn, recvbuffer);
return false;
}
CfOpenDirectory(conn, sendbuffer, filename);
return true;
case PROTOCOL_COMMAND_SYNC_SECURE:
memset(buffer, 0, CF_BUFSIZE);
sscanf(recvbuffer, "SSYNCH %u", &len);
if ((len >= sizeof(out)) || (received != (len + CF_PROTO_OFFSET)))
{
Log(LOG_LEVEL_INFO, "Protocol error SSYNCH: %d", len);
RefuseAccess(conn, recvbuffer);
return false;
}
memcpy(out, recvbuffer + CF_PROTO_OFFSET, len);
plainlen = DecryptString(recvbuffer, sizeof(recvbuffer),
out, len,
conn->encryption_type, conn->session_key);
if (plainlen < 0)
{
DebugBinOut((char *) conn->session_key, 32, "Session key");
Log(LOG_LEVEL_ERR, "Bad decrypt (%d)", len);
}
if (strncmp(recvbuffer, "SYNCH", 5) != 0)
{
Log(LOG_LEVEL_INFO, "No synch");
RefuseAccess(conn, recvbuffer);
return true;
}
/* roll through, no break */
case PROTOCOL_COMMAND_SYNC:
memset(filename, 0, CF_BUFSIZE);
sscanf(recvbuffer, "SYNCH %ld STAT %[^\n]", &time_no_see, filename);
trem = (time_t) time_no_see;
if (filename[0] == '\0')
{
break;
}
if ((tloc = time((time_t *) NULL)) == -1)
{
Log(LOG_LEVEL_INFO, "Couldn't read system clock. (time: %s)", GetErrorStr());
SendTransaction(conn->conn_info, "BAD: clocks out of synch", 0, CF_DONE);
return true;
}
drift = (int) (tloc - trem);
zret = ShortcutsExpand(filename, sizeof(filename),
SERVER_ACCESS.path_shortcuts,
conn->ipaddr, conn->hostname,
KeyPrintableHash(ConnectionInfoKey(conn->conn_info)));
if (zret == (size_t) -1)
{
Log(LOG_LEVEL_VERBOSE, "Expanding filename (%s) made it too long (>= %zu)", filename, sizeof(filename));
return false;
}
if (!AccessControl(ctx, filename, conn, true))
{
Log(LOG_LEVEL_INFO, "Access control in sync");
RefuseAccess(conn, recvbuffer);
return true;
}
if (DENYBADCLOCKS && (drift * drift > CLOCK_DRIFT * CLOCK_DRIFT))
{
snprintf(sendbuffer, sizeof(sendbuffer),
"BAD: Clocks are too far unsynchronized %ld/%ld",
(long) tloc, (long) trem);
SendTransaction(conn->conn_info, sendbuffer, 0, CF_DONE);
return true;
}
else
{
Log(LOG_LEVEL_DEBUG, "Clocks were off by %ld", (long) tloc - (long) trem);
StatFile(conn, sendbuffer, filename);
}
return true;
case PROTOCOL_COMMAND_MD5_SECURE:
sscanf(recvbuffer, "SMD5 %u", &len);
if ((len >= sizeof(out)) || (received != (len + CF_PROTO_OFFSET)))
{
Log(LOG_LEVEL_INFO, "Decryption error");
RefuseAccess(conn, recvbuffer);
return true;
}
memcpy(out, recvbuffer + CF_PROTO_OFFSET, len);
plainlen = DecryptString(recvbuffer, sizeof(recvbuffer),
out, len,
conn->encryption_type, conn->session_key);
if (strncmp(recvbuffer, "MD5", 3) != 0)
{
Log(LOG_LEVEL_INFO, "MD5 protocol error");
RefuseAccess(conn, recvbuffer);
return false;
}
encrypted = true;
/* roll through, no break */
case PROTOCOL_COMMAND_MD5:
memset(filename, 0, sizeof(filename));
sscanf(recvbuffer, "MD5 %[^\n]", filename);
zret = ShortcutsExpand(filename, sizeof(filename),
SERVER_ACCESS.path_shortcuts,
conn->ipaddr, conn->hostname,
KeyPrintableHash(ConnectionInfoKey(conn->conn_info)));
if (zret == (size_t) -1)
{
Log(LOG_LEVEL_VERBOSE, "Expanding filename (%s) made it too long (>= %zu)", filename, sizeof(filename));
return false;
}
if (!AccessControl(ctx, filename, conn, encrypted))
{
Log(LOG_LEVEL_INFO, "Access denied to get object");
RefuseAccess(conn, recvbuffer);
return true;
}
assert(CF_DEFAULT_DIGEST_LEN <= EVP_MAX_MD_SIZE);
unsigned char digest[EVP_MAX_MD_SIZE + 1];
assert(CF_BUFSIZE + CF_SMALL_OFFSET + CF_DEFAULT_DIGEST_LEN
<= sizeof(recvbuffer));
memcpy(digest, recvbuffer + strlen(recvbuffer) + CF_SMALL_OFFSET,
CF_DEFAULT_DIGEST_LEN);
CompareLocalHash(filename, digest, sendbuffer);
SendTransaction(conn->conn_info, sendbuffer, 0, CF_DONE);
return true;
case PROTOCOL_COMMAND_VAR_SECURE:
sscanf(recvbuffer, "SVAR %u", &len);
if ((len >= sizeof(out)) || (received != (len + CF_PROTO_OFFSET)))
{
Log(LOG_LEVEL_INFO, "Decrypt error SVAR");
RefuseAccess(conn, "decrypt error SVAR");
return true;
}
memcpy(out, recvbuffer + CF_PROTO_OFFSET, len);
plainlen = DecryptString(recvbuffer, sizeof(recvbuffer),
out, len,
conn->encryption_type, conn->session_key);
encrypted = true;
if (strncmp(recvbuffer, "VAR", 3) != 0)
{
Log(LOG_LEVEL_INFO, "VAR protocol defect");
RefuseAccess(conn, "decryption failure");
return false;
}
/* roll through, no break */
case PROTOCOL_COMMAND_VAR:
if (!LiteralAccessControl(ctx, recvbuffer, conn, encrypted))
{
Log(LOG_LEVEL_INFO, "Literal access failure");
RefuseAccess(conn, recvbuffer);
return false;
}
GetServerLiteral(ctx, conn, sendbuffer, recvbuffer, encrypted);
return true;
case PROTOCOL_COMMAND_CONTEXT_SECURE:
sscanf(recvbuffer, "SCONTEXT %u", &len);
if ((len >= sizeof(out)) || (received != (len + CF_PROTO_OFFSET)))
{
Log(LOG_LEVEL_INFO, "Decrypt error SCONTEXT, len,received = %d,%d", len, received);
RefuseAccess(conn, "decrypt error SCONTEXT");
return true;
}
memcpy(out, recvbuffer + CF_PROTO_OFFSET, len);
plainlen = DecryptString(recvbuffer, sizeof(recvbuffer),
out, len,
conn->encryption_type, conn->session_key);
encrypted = true;
if (strncmp(recvbuffer, "CONTEXT", 7) != 0)
{
Log(LOG_LEVEL_INFO, "CONTEXT protocol defect...");
RefuseAccess(conn, "Decryption failed?");
return false;
}
/* roll through, no break */
case PROTOCOL_COMMAND_CONTEXT:
if ((classes = ContextAccessControl(ctx, recvbuffer, conn, encrypted)) == NULL)
{
Log(LOG_LEVEL_INFO, "Context access failure on %s", recvbuffer);
RefuseAccess(conn, recvbuffer);
return false;
}
ReplyServerContext(conn, encrypted, classes);
return true;
case PROTOCOL_COMMAND_QUERY_SECURE:
sscanf(recvbuffer, "SQUERY %u", &len);
if ((len >= sizeof(out)) || (received != (len + CF_PROTO_OFFSET)))
{
Log(LOG_LEVEL_INFO, "Decrypt error SQUERY");
RefuseAccess(conn, "decrypt error SQUERY");
return true;
}
memcpy(out, recvbuffer + CF_PROTO_OFFSET, len);
plainlen = DecryptString(recvbuffer, sizeof(recvbuffer),
out, len,
conn->encryption_type, conn->session_key);
if (strncmp(recvbuffer, "QUERY", 5) != 0)
{
Log(LOG_LEVEL_INFO, "QUERY protocol defect");
RefuseAccess(conn, "decryption failure");
return false;
}
if (!LiteralAccessControl(ctx, recvbuffer, conn, true))
{
Log(LOG_LEVEL_INFO, "Query access failure");
RefuseAccess(conn, recvbuffer);
return false;
}
if (GetServerQuery(conn, recvbuffer, true)) /* always encrypt */
{
return true;
}
break;
case PROTOCOL_COMMAND_CALL_ME_BACK:
sscanf(recvbuffer, "SCALLBACK %u", &len);
if ((len >= sizeof(out)) || (received != (len + CF_PROTO_OFFSET)))
{
Log(LOG_LEVEL_INFO, "Decrypt error CALL_ME_BACK");
return true;
}
memcpy(out, recvbuffer + CF_PROTO_OFFSET, len);
plainlen = DecryptString(recvbuffer, sizeof(recvbuffer),
out, len,
conn->encryption_type, conn->session_key);
if (strncmp(recvbuffer, "CALL_ME_BACK collect_calls", strlen("CALL_ME_BACK collect_calls")) != 0)
{
Log(LOG_LEVEL_INFO, "CALL_ME_BACK protocol defect");
return false;
}
if (!LiteralAccessControl(ctx, recvbuffer, conn, true))
{
Log(LOG_LEVEL_INFO, "Query access failure");
return false;
}
ReceiveCollectCall(conn);
/* On success that returned true; otherwise, it did all
* relevant Log()ging. Either way, we're no longer busy with
* it and our caller can close the connection: */
return false;
case PROTOCOL_COMMAND_AUTH_PLAIN:
case PROTOCOL_COMMAND_AUTH_SECURE:
case PROTOCOL_COMMAND_AUTH:
case PROTOCOL_COMMAND_CONTEXTS:
case PROTOCOL_COMMAND_BAD:
Log(LOG_LEVEL_WARNING, "Unexpected protocol command");
}
strcpy(sendbuffer, "BAD: Request denied");
SendTransaction(conn->conn_info, sendbuffer, 0, CF_DONE);
Log(LOG_LEVEL_INFO, "Closing connection due to request: %s", recvbuffer);
return false;
}
cfengine-3.12.1/cf-serverd/server.h 0000644 0000000 0000000 00000011412 13377750461 017105 0 ustar 00root root 0000000 0000000 /*
Copyright 2018 Northern.tech AS
This file is part of CFEngine 3 - written and maintained by Northern.tech AS.
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; version 3.
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, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
To the extent this program is licensed as part of the Enterprise
versions of CFEngine, the applicable Commercial Open Source License
(COSL) may apply to this file if you as a licensee so wish it. See
included file COSL.txt.
*/
#ifndef CFENGINE_SERVER_H
#define CFENGINE_SERVER_H
#include
#include /* AgentConnection */
#include
//*******************************************************************
// TYPES
//*******************************************************************
typedef struct Auth_ Auth;
/* Access rights for a path, literal, context (classpattern), variable */
/* LEGACY CODE the new struct is paths_acl etc. */
struct Auth_
{
char *path;
int literal;
int classpattern;
int variable;
Item *accesslist; /* which hosts -- IP or hostnames */
Item *maproot; /* which hosts should have root read access */
int encrypt; /* which files HAVE to be transmitted securely */
Auth *next;
};
typedef struct
{
Item *connectionlist; /* List of currently open connections */
/* body server control options */
Item *nonattackerlist; /* "allowconnects" */
Item *attackerlist; /* "denyconnects" */
Item *allowuserlist; /* "allowusers" */
Item *multiconnlist; /* "allowallconnects" */
Item *trustkeylist; /* "trustkeysfrom" */
Item *allowlegacyconnects;
char *allowciphers;
char *allowtlsversion;
/* ACL for resource_type "path". */
Auth *admit;
Auth *admittail;
Auth *deny;
Auth *denytail;
/* ACL for resource_type "literal", "query", "context", "variable". */
Auth *varadmit;
Auth *varadmittail;
Auth *vardeny;
Auth *vardenytail;
int logconns;
/* bundle server access_rules: shortcut for ACL entries, which expands to
* the ACL entry when seen in client requests. */
StringMap *path_shortcuts;
} ServerAccess;
/* TODO rename to IncomingConnection */
struct ServerConnectionState_
{
ConnectionInfo *conn_info;
/* TODO sockaddr_storage, even though we can keep the text as cache. */
char ipaddr[CF_MAX_IP_LEN];
/* TODO this is too big at 1025; maybe allocate dynamically from a pool? */
char revdns[NI_MAXHOST]; /* only populated in new protocol */
#ifdef __MINGW32__
char sid[CF_MAXSIDSIZE]; /* 2K size too big! */
#endif
uid_t uid;
/* TODO move username, hostname etc to a new struct identity. */
char username[CF_MAXVARSIZE];
/* The following are NOT POPULATED with the new protocol,
* TODO DEPRECATE! */
/* hostname is copied from client-supplied CAUTH command */
char hostname[CF_MAXVARSIZE];
int user_data_set;
int rsa_auth;
/* TODO DANGEROUS! this is set for the whole connection if only one path
* is admitted as maproot. */
int maproot;
unsigned char *session_key;
char encryption_type;
/* TODO pass it through function arguments, EvalContext has nothing to do
* with connection-specific data. */
EvalContext *ctx;
};
typedef struct
{
ServerConnectionState *conn;
int encrypt;
int buf_size;
char *replybuff;
char *replyfile;
} ServerFileGetState;
/* Used in cf-serverd-functions.c. */
void ServerEntryPoint(EvalContext *ctx, const char *ipaddr, ConnectionInfo *info);
AgentConnection *ExtractCallBackChannel(ServerConnectionState *conn);
//*******************************************************************
// STATE
//*******************************************************************
#define CLOCK_DRIFT 3600
extern int ACTIVE_THREADS;
extern int CFD_MAXPROCESSES;
extern bool DENYBADCLOCKS;
extern int MAXTRIES;
extern bool LOGENCRYPT;
extern int COLLECT_INTERVAL;
extern bool SERVER_LISTEN;
extern ServerAccess SERVER_ACCESS;
extern char CFRUNCOMMAND[CF_MAXVARSIZE];
extern bool NEED_REVERSE_LOOKUP;
#endif
cfengine-3.12.1/cf-serverd/server_common.h 0000644 0000000 0000000 00000006375 13377750461 020471 0 ustar 00root root 0000000 0000000 /*
Copyright 2018 Northern.tech AS
This file is part of CFEngine 3 - written and maintained by Northern.tech AS.
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; version 3.
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, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
To the extent this program is licensed as part of the Enterprise
versions of CFEngine, the applicable Commercial Open Source License
(COSL) may apply to this file if you as a licensee so wish it. See
included file COSL.txt.
*/
#ifndef CFENGINE_SERVER_COMMON_H
#define CFENGINE_SERVER_COMMON_H
#define CF_BUFEXT 128
#include
#include /* EvalContext */
#include /* ServerConnectionState */
void RefuseAccess(ServerConnectionState *conn, char *errmesg);
int AllowedUser(char *user);
/* Checks whatever user name contains characters we are considering to be invalid */
bool IsUserNameValid(const char *username);
int MatchClasses(const EvalContext *ctx, ServerConnectionState *conn);
void Terminate(ConnectionInfo *connection);
void CfGetFile(ServerFileGetState *args);
void CfEncryptGetFile(ServerFileGetState *args);
int StatFile(ServerConnectionState *conn, char *sendbuffer, char *ofilename);
void ReplyServerContext(ServerConnectionState *conn, int encrypted, Item *classes);
int CfOpenDirectory(ServerConnectionState *conn, char *sendbuffer, char *oldDirname);
int CfSecOpenDirectory(ServerConnectionState *conn, char *sendbuffer, char *dirname);
void GetServerLiteral(EvalContext *ctx, ServerConnectionState *conn, char *sendbuffer, char *recvbuffer, int encrypted);
int GetServerQuery(ServerConnectionState *conn, char *recvbuffer, int encrypted);
bool CompareLocalHash(const char *filename, const char digest[EVP_MAX_MD_SIZE + 1],
char sendbuffer[CF_BUFSIZE]);
Item *ListPersistentClasses(void);
bool PathRemoveTrailingSlash(char *s, size_t s_len);
bool PathAppendTrailingSlash(char *s, size_t s_len);
size_t ReplaceSpecialVariables(char *buf, size_t buf_size,
const char *find1, const char *repl1,
const char *find2, const char *repl2,
const char *find3, const char *repl3);
size_t ShortcutsExpand(char *path, size_t path_size,
const StringMap *shortcuts,
const char *ipaddr, const char *hostname,
const char *key);
size_t PreprocessRequestPath(char *reqpath, size_t reqpath_size);
void SetConnIdentity(ServerConnectionState *conn, const char *username);
bool DoExec2(const EvalContext *ctx,
ServerConnectionState *conn,
char *exec_args,
char *sendbuf, size_t sendbuf_size);
#endif /* CFENGINE_SERVER_COMMON_H */
cfengine-3.12.1/cf-serverd/cf-serverd-enterprise-stubs.h 0000644 0000000 0000000 00000005214 13377750461 023156 0 ustar 00root root 0000000 0000000 /*
Copyright 2018 Northern.tech AS
This file is part of CFEngine 3 - written and maintained by Northern.tech AS.
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; version 3.
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, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
To the extent this program is licensed as part of the Enterprise
versions of CFEngine, the applicable Commercial Open Source License
(COSL) may apply to this file if you as a licensee so wish it. See
included file COSL.txt.
*/
#ifndef CFENGINE_CF_SERVERD_ENTERPRISE_STUBS_H
#define CFENGINE_CF_SERVERD_ENTERPRISE_STUBS_H
#include
#include
struct ServerConnectionState;
ENTERPRISE_VOID_FUNC_3ARG_DECLARE(void, RegisterLiteralServerData, EvalContext *, ctx, const char *, handle, const Promise *, pp);
ENTERPRISE_FUNC_3ARG_DECLARE(int, ReturnLiteralData, EvalContext *, ctx, char *, handle, char *, ret);
ENTERPRISE_FUNC_5ARG_DECLARE(int, SetServerListenState, EvalContext *, ctx, size_t, queue_size,
char *, bind_address, bool, server_listen,
InitServerFunction, InitServerPtr);
typedef void (*ServerEntryPointFunction)(EvalContext *ctx, char *ipaddr, ConnectionInfo *info);
ENTERPRISE_FUNC_1ARG_DECLARE(bool, ReceiveCollectCall, ServerConnectionState *, conn);
ENTERPRISE_FUNC_3ARG_DECLARE(bool, ReturnQueryData, ServerConnectionState *, conn, char *, menu, int, encrypt);
ENTERPRISE_FUNC_2ARG_DECLARE(bool, CFTestD_ReturnQueryData, ServerConnectionState *, conn, char *, menu);
ENTERPRISE_VOID_FUNC_1ARG_DECLARE(void, KeepReportDataSelectAccessPromise,
const Promise *, pp);
ENTERPRISE_VOID_FUNC_0ARG_DECLARE(void, CleanReportBookFilterSet);
ENTERPRISE_VOID_FUNC_1ARG_DECLARE(void, FprintAvahiCfengineTag, FILE *, fp);
ENTERPRISE_VOID_FUNC_1ARG_DECLARE(void, CollectCallStart, ARG_UNUSED int, interval);
ENTERPRISE_VOID_FUNC_0ARG_DECLARE(void, CollectCallStop);
ENTERPRISE_FUNC_0ARG_DECLARE(bool, CollectCallHasPending);
ENTERPRISE_FUNC_1ARG_DECLARE(int, CollectCallGetPending, ARG_UNUSED int *, queue_length);
ENTERPRISE_VOID_FUNC_0ARG_DECLARE(void, CollectCallMarkProcessed);
#endif
cfengine-3.12.1/cf-serverd/server_tls.h 0000644 0000000 0000000 00000005015 13377750461 017771 0 ustar 00root root 0000000 0000000 /*
Copyright 2018 Northern.tech AS
This file is part of CFEngine 3 - written and maintained by Northern.tech AS.
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; version 3.
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, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
To the extent this program is licensed as part of the Enterprise
versions of CFEngine, the applicable Commercial Open Source License
(COSL) may apply to this file if you as a licensee so wish it. See
included file COSL.txt.
*/
#ifndef CFENGINE_SERVER_TLS_H
#define CFENGINE_SERVER_TLS_H
#include
#include /* EvalContext */
#include /* ConnectionInfo */
#include /* ServerConnectionState */
typedef enum
{
PROTOCOL_COMMAND_EXEC = 0,
PROTOCOL_COMMAND_GET,
PROTOCOL_COMMAND_OPENDIR,
PROTOCOL_COMMAND_SYNCH,
PROTOCOL_COMMAND_MD5,
PROTOCOL_COMMAND_VERSION,
PROTOCOL_COMMAND_VAR,
PROTOCOL_COMMAND_CONTEXT,
PROTOCOL_COMMAND_QUERY,
PROTOCOL_COMMAND_CALL_ME_BACK,
PROTOCOL_COMMAND_BAD
} ProtocolCommandNew;
static const char *const PROTOCOL_NEW[PROTOCOL_COMMAND_BAD + 1] =
{
"EXEC",
"GET",
"OPENDIR",
"SYNCH",
"MD5",
"VERSION",
"VAR",
"CONTEXT",
"QUERY",
"SCALLBACK",
NULL
};
bool ServerTLSInitialize(RSA *priv_key, RSA *pub_key, SSL_CTX **ctx);
void ServerTLSDeInitialize(RSA **priv_key, RSA **pub_key, SSL_CTX **ctx);
bool ServerTLSPeek(ConnectionInfo *conn_info);
bool BasicServerTLSSessionEstablish(ServerConnectionState *conn, SSL_CTX *ssl_ctx);
bool ServerTLSSessionEstablish(ServerConnectionState *conn, SSL_CTX *ssl_ctx);
bool BusyWithNewProtocol(EvalContext *ctx, ServerConnectionState *conn);
bool ServerSendWelcome(const ServerConnectionState *conn);
bool ServerIdentificationDialog(ConnectionInfo *conn_info,
char *username, size_t username_size);
ProtocolCommandNew GetCommandNew(char *str);
#endif /* CFENGINE_SERVER_TLS_H */
cfengine-3.12.1/depcomp 0000755 0000000 0000000 00000056016 13377750517 014756 0 ustar 00root root 0000000 0000000 #! /bin/sh
# depcomp - compile a program generating dependencies as side-effects
scriptversion=2013-05-30.07; # UTC
# Copyright (C) 1999-2013 Free Software Foundation, Inc.
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
# As a special exception to the GNU General Public License, if you
# distribute this file as part of a program that contains a
# configuration script generated by Autoconf, you may include it under
# the same distribution terms that you use for the rest of that program.
# Originally written by Alexandre Oliva .
case $1 in
'')
echo "$0: No command. Try '$0 --help' for more information." 1>&2
exit 1;
;;
-h | --h*)
cat <<\EOF
Usage: depcomp [--help] [--version] PROGRAM [ARGS]
Run PROGRAMS ARGS to compile a file, generating dependencies
as side-effects.
Environment variables:
depmode Dependency tracking mode.
source Source file read by 'PROGRAMS ARGS'.
object Object file output by 'PROGRAMS ARGS'.
DEPDIR directory where to store dependencies.
depfile Dependency file to output.
tmpdepfile Temporary file to use when outputting dependencies.
libtool Whether libtool is used (yes/no).
Report bugs to .
EOF
exit $?
;;
-v | --v*)
echo "depcomp $scriptversion"
exit $?
;;
esac
# Get the directory component of the given path, and save it in the
# global variables '$dir'. Note that this directory component will
# be either empty or ending with a '/' character. This is deliberate.
set_dir_from ()
{
case $1 in
*/*) dir=`echo "$1" | sed -e 's|/[^/]*$|/|'`;;
*) dir=;;
esac
}
# Get the suffix-stripped basename of the given path, and save it the
# global variable '$base'.
set_base_from ()
{
base=`echo "$1" | sed -e 's|^.*/||' -e 's/\.[^.]*$//'`
}
# If no dependency file was actually created by the compiler invocation,
# we still have to create a dummy depfile, to avoid errors with the
# Makefile "include basename.Plo" scheme.
make_dummy_depfile ()
{
echo "#dummy" > "$depfile"
}
# Factor out some common post-processing of the generated depfile.
# Requires the auxiliary global variable '$tmpdepfile' to be set.
aix_post_process_depfile ()
{
# If the compiler actually managed to produce a dependency file,
# post-process it.
if test -f "$tmpdepfile"; then
# Each line is of the form 'foo.o: dependency.h'.
# Do two passes, one to just change these to
# $object: dependency.h
# and one to simply output
# dependency.h:
# which is needed to avoid the deleted-header problem.
{ sed -e "s,^.*\.[$lower]*:,$object:," < "$tmpdepfile"
sed -e "s,^.*\.[$lower]*:[$tab ]*,," -e 's,$,:,' < "$tmpdepfile"
} > "$depfile"
rm -f "$tmpdepfile"
else
make_dummy_depfile
fi
}
# A tabulation character.
tab=' '
# A newline character.
nl='
'
# Character ranges might be problematic outside the C locale.
# These definitions help.
upper=ABCDEFGHIJKLMNOPQRSTUVWXYZ
lower=abcdefghijklmnopqrstuvwxyz
digits=0123456789
alpha=${upper}${lower}
if test -z "$depmode" || test -z "$source" || test -z "$object"; then
echo "depcomp: Variables source, object and depmode must be set" 1>&2
exit 1
fi
# Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po.
depfile=${depfile-`echo "$object" |
sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`}
tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`}
rm -f "$tmpdepfile"
# Avoid interferences from the environment.
gccflag= dashmflag=
# Some modes work just like other modes, but use different flags. We
# parameterize here, but still list the modes in the big case below,
# to make depend.m4 easier to write. Note that we *cannot* use a case
# here, because this file can only contain one case statement.
if test "$depmode" = hp; then
# HP compiler uses -M and no extra arg.
gccflag=-M
depmode=gcc
fi
if test "$depmode" = dashXmstdout; then
# This is just like dashmstdout with a different argument.
dashmflag=-xM
depmode=dashmstdout
fi
cygpath_u="cygpath -u -f -"
if test "$depmode" = msvcmsys; then
# This is just like msvisualcpp but w/o cygpath translation.
# Just convert the backslash-escaped backslashes to single forward
# slashes to satisfy depend.m4
cygpath_u='sed s,\\\\,/,g'
depmode=msvisualcpp
fi
if test "$depmode" = msvc7msys; then
# This is just like msvc7 but w/o cygpath translation.
# Just convert the backslash-escaped backslashes to single forward
# slashes to satisfy depend.m4
cygpath_u='sed s,\\\\,/,g'
depmode=msvc7
fi
if test "$depmode" = xlc; then
# IBM C/C++ Compilers xlc/xlC can output gcc-like dependency information.
gccflag=-qmakedep=gcc,-MF
depmode=gcc
fi
case "$depmode" in
gcc3)
## gcc 3 implements dependency tracking that does exactly what
## we want. Yay! Note: for some reason libtool 1.4 doesn't like
## it if -MD -MP comes after the -MF stuff. Hmm.
## Unfortunately, FreeBSD c89 acceptance of flags depends upon
## the command line argument order; so add the flags where they
## appear in depend2.am. Note that the slowdown incurred here
## affects only configure: in makefiles, %FASTDEP% shortcuts this.
for arg
do
case $arg in
-c) set fnord "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" "$arg" ;;
*) set fnord "$@" "$arg" ;;
esac
shift # fnord
shift # $arg
done
"$@"
stat=$?
if test $stat -ne 0; then
rm -f "$tmpdepfile"
exit $stat
fi
mv "$tmpdepfile" "$depfile"
;;
gcc)
## Note that this doesn't just cater to obsosete pre-3.x GCC compilers.
## but also to in-use compilers like IMB xlc/xlC and the HP C compiler.
## (see the conditional assignment to $gccflag above).
## There are various ways to get dependency output from gcc. Here's
## why we pick this rather obscure method:
## - Don't want to use -MD because we'd like the dependencies to end
## up in a subdir. Having to rename by hand is ugly.
## (We might end up doing this anyway to support other compilers.)
## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like
## -MM, not -M (despite what the docs say). Also, it might not be
## supported by the other compilers which use the 'gcc' depmode.
## - Using -M directly means running the compiler twice (even worse
## than renaming).
if test -z "$gccflag"; then
gccflag=-MD,
fi
"$@" -Wp,"$gccflag$tmpdepfile"
stat=$?
if test $stat -ne 0; then
rm -f "$tmpdepfile"
exit $stat
fi
rm -f "$depfile"
echo "$object : \\" > "$depfile"
# The second -e expression handles DOS-style file names with drive
# letters.
sed -e 's/^[^:]*: / /' \
-e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile"
## This next piece of magic avoids the "deleted header file" problem.
## The problem is that when a header file which appears in a .P file
## is deleted, the dependency causes make to die (because there is
## typically no way to rebuild the header). We avoid this by adding
## dummy dependencies for each header file. Too bad gcc doesn't do
## this for us directly.
## Some versions of gcc put a space before the ':'. On the theory
## that the space means something, we add a space to the output as
## well. hp depmode also adds that space, but also prefixes the VPATH
## to the object. Take care to not repeat it in the output.
## Some versions of the HPUX 10.20 sed can't process this invocation
## correctly. Breaking it into two sed invocations is a workaround.
tr ' ' "$nl" < "$tmpdepfile" \
| sed -e 's/^\\$//' -e '/^$/d' -e "s|.*$object$||" -e '/:$/d' \
| sed -e 's/$/ :/' >> "$depfile"
rm -f "$tmpdepfile"
;;
hp)
# This case exists only to let depend.m4 do its work. It works by
# looking at the text of this script. This case will never be run,
# since it is checked for above.
exit 1
;;
sgi)
if test "$libtool" = yes; then
"$@" "-Wp,-MDupdate,$tmpdepfile"
else
"$@" -MDupdate "$tmpdepfile"
fi
stat=$?
if test $stat -ne 0; then
rm -f "$tmpdepfile"
exit $stat
fi
rm -f "$depfile"
if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files
echo "$object : \\" > "$depfile"
# Clip off the initial element (the dependent). Don't try to be
# clever and replace this with sed code, as IRIX sed won't handle
# lines with more than a fixed number of characters (4096 in
# IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines;
# the IRIX cc adds comments like '#:fec' to the end of the
# dependency line.
tr ' ' "$nl" < "$tmpdepfile" \
| sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' \
| tr "$nl" ' ' >> "$depfile"
echo >> "$depfile"
# The second pass generates a dummy entry for each header file.
tr ' ' "$nl" < "$tmpdepfile" \
| sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \
>> "$depfile"
else
make_dummy_depfile
fi
rm -f "$tmpdepfile"
;;
xlc)
# This case exists only to let depend.m4 do its work. It works by
# looking at the text of this script. This case will never be run,
# since it is checked for above.
exit 1
;;
aix)
# The C for AIX Compiler uses -M and outputs the dependencies
# in a .u file. In older versions, this file always lives in the
# current directory. Also, the AIX compiler puts '$object:' at the
# start of each line; $object doesn't have directory information.
# Version 6 uses the directory in both cases.
set_dir_from "$object"
set_base_from "$object"
if test "$libtool" = yes; then
tmpdepfile1=$dir$base.u
tmpdepfile2=$base.u
tmpdepfile3=$dir.libs/$base.u
"$@" -Wc,-M
else
tmpdepfile1=$dir$base.u
tmpdepfile2=$dir$base.u
tmpdepfile3=$dir$base.u
"$@" -M
fi
stat=$?
if test $stat -ne 0; then
rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
exit $stat
fi
for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
do
test -f "$tmpdepfile" && break
done
aix_post_process_depfile
;;
tcc)
# tcc (Tiny C Compiler) understand '-MD -MF file' since version 0.9.26
# FIXME: That version still under development at the moment of writing.
# Make that this statement remains true also for stable, released
# versions.
# It will wrap lines (doesn't matter whether long or short) with a
# trailing '\', as in:
#
# foo.o : \
# foo.c \
# foo.h \
#
# It will put a trailing '\' even on the last line, and will use leading
# spaces rather than leading tabs (at least since its commit 0394caf7
# "Emit spaces for -MD").
"$@" -MD -MF "$tmpdepfile"
stat=$?
if test $stat -ne 0; then
rm -f "$tmpdepfile"
exit $stat
fi
rm -f "$depfile"
# Each non-empty line is of the form 'foo.o : \' or ' dep.h \'.
# We have to change lines of the first kind to '$object: \'.
sed -e "s|.*:|$object :|" < "$tmpdepfile" > "$depfile"
# And for each line of the second kind, we have to emit a 'dep.h:'
# dummy dependency, to avoid the deleted-header problem.
sed -n -e 's|^ *\(.*\) *\\$|\1:|p' < "$tmpdepfile" >> "$depfile"
rm -f "$tmpdepfile"
;;
## The order of this option in the case statement is important, since the
## shell code in configure will try each of these formats in the order
## listed in this file. A plain '-MD' option would be understood by many
## compilers, so we must ensure this comes after the gcc and icc options.
pgcc)
# Portland's C compiler understands '-MD'.
# Will always output deps to 'file.d' where file is the root name of the
# source file under compilation, even if file resides in a subdirectory.
# The object file name does not affect the name of the '.d' file.
# pgcc 10.2 will output
# foo.o: sub/foo.c sub/foo.h
# and will wrap long lines using '\' :
# foo.o: sub/foo.c ... \
# sub/foo.h ... \
# ...
set_dir_from "$object"
# Use the source, not the object, to determine the base name, since
# that's sadly what pgcc will do too.
set_base_from "$source"
tmpdepfile=$base.d
# For projects that build the same source file twice into different object
# files, the pgcc approach of using the *source* file root name can cause
# problems in parallel builds. Use a locking strategy to avoid stomping on
# the same $tmpdepfile.
lockdir=$base.d-lock
trap "
echo '$0: caught signal, cleaning up...' >&2
rmdir '$lockdir'
exit 1
" 1 2 13 15
numtries=100
i=$numtries
while test $i -gt 0; do
# mkdir is a portable test-and-set.
if mkdir "$lockdir" 2>/dev/null; then
# This process acquired the lock.
"$@" -MD
stat=$?
# Release the lock.
rmdir "$lockdir"
break
else
# If the lock is being held by a different process, wait
# until the winning process is done or we timeout.
while test -d "$lockdir" && test $i -gt 0; do
sleep 1
i=`expr $i - 1`
done
fi
i=`expr $i - 1`
done
trap - 1 2 13 15
if test $i -le 0; then
echo "$0: failed to acquire lock after $numtries attempts" >&2
echo "$0: check lockdir '$lockdir'" >&2
exit 1
fi
if test $stat -ne 0; then
rm -f "$tmpdepfile"
exit $stat
fi
rm -f "$depfile"
# Each line is of the form `foo.o: dependent.h',
# or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'.
# Do two passes, one to just change these to
# `$object: dependent.h' and one to simply `dependent.h:'.
sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile"
# Some versions of the HPUX 10.20 sed can't process this invocation
# correctly. Breaking it into two sed invocations is a workaround.
sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" \
| sed -e 's/$/ :/' >> "$depfile"
rm -f "$tmpdepfile"
;;
hp2)
# The "hp" stanza above does not work with aCC (C++) and HP's ia64
# compilers, which have integrated preprocessors. The correct option
# to use with these is +Maked; it writes dependencies to a file named
# 'foo.d', which lands next to the object file, wherever that
# happens to be.
# Much of this is similar to the tru64 case; see comments there.
set_dir_from "$object"
set_base_from "$object"
if test "$libtool" = yes; then
tmpdepfile1=$dir$base.d
tmpdepfile2=$dir.libs/$base.d
"$@" -Wc,+Maked
else
tmpdepfile1=$dir$base.d
tmpdepfile2=$dir$base.d
"$@" +Maked
fi
stat=$?
if test $stat -ne 0; then
rm -f "$tmpdepfile1" "$tmpdepfile2"
exit $stat
fi
for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2"
do
test -f "$tmpdepfile" && break
done
if test -f "$tmpdepfile"; then
sed -e "s,^.*\.[$lower]*:,$object:," "$tmpdepfile" > "$depfile"
# Add 'dependent.h:' lines.
sed -ne '2,${
s/^ *//
s/ \\*$//
s/$/:/
p
}' "$tmpdepfile" >> "$depfile"
else
make_dummy_depfile
fi
rm -f "$tmpdepfile" "$tmpdepfile2"
;;
tru64)
# The Tru64 compiler uses -MD to generate dependencies as a side
# effect. 'cc -MD -o foo.o ...' puts the dependencies into 'foo.o.d'.
# At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put
# dependencies in 'foo.d' instead, so we check for that too.
# Subdirectories are respected.
set_dir_from "$object"
set_base_from "$object"
if test "$libtool" = yes; then
# Libtool generates 2 separate objects for the 2 libraries. These
# two compilations output dependencies in $dir.libs/$base.o.d and
# in $dir$base.o.d. We have to check for both files, because
# one of the two compilations can be disabled. We should prefer
# $dir$base.o.d over $dir.libs/$base.o.d because the latter is
# automatically cleaned when .libs/ is deleted, while ignoring
# the former would cause a distcleancheck panic.
tmpdepfile1=$dir$base.o.d # libtool 1.5
tmpdepfile2=$dir.libs/$base.o.d # Likewise.
tmpdepfile3=$dir.libs/$base.d # Compaq CCC V6.2-504
"$@" -Wc,-MD
else
tmpdepfile1=$dir$base.d
tmpdepfile2=$dir$base.d
tmpdepfile3=$dir$base.d
"$@" -MD
fi
stat=$?
if test $stat -ne 0; then
rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
exit $stat
fi
for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
do
test -f "$tmpdepfile" && break
done
# Same post-processing that is required for AIX mode.
aix_post_process_depfile
;;
msvc7)
if test "$libtool" = yes; then
showIncludes=-Wc,-showIncludes
else
showIncludes=-showIncludes
fi
"$@" $showIncludes > "$tmpdepfile"
stat=$?
grep -v '^Note: including file: ' "$tmpdepfile"
if test $stat -ne 0; then
rm -f "$tmpdepfile"
exit $stat
fi
rm -f "$depfile"
echo "$object : \\" > "$depfile"
# The first sed program below extracts the file names and escapes
# backslashes for cygpath. The second sed program outputs the file
# name when reading, but also accumulates all include files in the
# hold buffer in order to output them again at the end. This only
# works with sed implementations that can handle large buffers.
sed < "$tmpdepfile" -n '
/^Note: including file: *\(.*\)/ {
s//\1/
s/\\/\\\\/g
p
}' | $cygpath_u | sort -u | sed -n '
s/ /\\ /g
s/\(.*\)/'"$tab"'\1 \\/p
s/.\(.*\) \\/\1:/
H
$ {
s/.*/'"$tab"'/
G
p
}' >> "$depfile"
echo >> "$depfile" # make sure the fragment doesn't end with a backslash
rm -f "$tmpdepfile"
;;
msvc7msys)
# This case exists only to let depend.m4 do its work. It works by
# looking at the text of this script. This case will never be run,
# since it is checked for above.
exit 1
;;
#nosideeffect)
# This comment above is used by automake to tell side-effect
# dependency tracking mechanisms from slower ones.
dashmstdout)
# Important note: in order to support this mode, a compiler *must*
# always write the preprocessed file to stdout, regardless of -o.
"$@" || exit $?
# Remove the call to Libtool.
if test "$libtool" = yes; then
while test "X$1" != 'X--mode=compile'; do
shift
done
shift
fi
# Remove '-o $object'.
IFS=" "
for arg
do
case $arg in
-o)
shift
;;
$object)
shift
;;
*)
set fnord "$@" "$arg"
shift # fnord
shift # $arg
;;
esac
done
test -z "$dashmflag" && dashmflag=-M
# Require at least two characters before searching for ':'
# in the target name. This is to cope with DOS-style filenames:
# a dependency such as 'c:/foo/bar' could be seen as target 'c' otherwise.
"$@" $dashmflag |
sed "s|^[$tab ]*[^:$tab ][^:][^:]*:[$tab ]*|$object: |" > "$tmpdepfile"
rm -f "$depfile"
cat < "$tmpdepfile" > "$depfile"
# Some versions of the HPUX 10.20 sed can't process this sed invocation
# correctly. Breaking it into two sed invocations is a workaround.
tr ' ' "$nl" < "$tmpdepfile" \
| sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \
| sed -e 's/$/ :/' >> "$depfile"
rm -f "$tmpdepfile"
;;
dashXmstdout)
# This case only exists to satisfy depend.m4. It is never actually
# run, as this mode is specially recognized in the preamble.
exit 1
;;
makedepend)
"$@" || exit $?
# Remove any Libtool call
if test "$libtool" = yes; then
while test "X$1" != 'X--mode=compile'; do
shift
done
shift
fi
# X makedepend
shift
cleared=no eat=no
for arg
do
case $cleared in
no)
set ""; shift
cleared=yes ;;
esac
if test $eat = yes; then
eat=no
continue
fi
case "$arg" in
-D*|-I*)
set fnord "$@" "$arg"; shift ;;
# Strip any option that makedepend may not understand. Remove
# the object too, otherwise makedepend will parse it as a source file.
-arch)
eat=yes ;;
-*|$object)
;;
*)
set fnord "$@" "$arg"; shift ;;
esac
done
obj_suffix=`echo "$object" | sed 's/^.*\././'`
touch "$tmpdepfile"
${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@"
rm -f "$depfile"
# makedepend may prepend the VPATH from the source file name to the object.
# No need to regex-escape $object, excess matching of '.' is harmless.
sed "s|^.*\($object *:\)|\1|" "$tmpdepfile" > "$depfile"
# Some versions of the HPUX 10.20 sed can't process the last invocation
# correctly. Breaking it into two sed invocations is a workaround.
sed '1,2d' "$tmpdepfile" \
| tr ' ' "$nl" \
| sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \
| sed -e 's/$/ :/' >> "$depfile"
rm -f "$tmpdepfile" "$tmpdepfile".bak
;;
cpp)
# Important note: in order to support this mode, a compiler *must*
# always write the preprocessed file to stdout.
"$@" || exit $?
# Remove the call to Libtool.
if test "$libtool" = yes; then
while test "X$1" != 'X--mode=compile'; do
shift
done
shift
fi
# Remove '-o $object'.
IFS=" "
for arg
do
case $arg in
-o)
shift
;;
$object)
shift
;;
*)
set fnord "$@" "$arg"
shift # fnord
shift # $arg
;;
esac
done
"$@" -E \
| sed -n -e '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \
-e '/^#line [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \
| sed '$ s: \\$::' > "$tmpdepfile"
rm -f "$depfile"
echo "$object : \\" > "$depfile"
cat < "$tmpdepfile" >> "$depfile"
sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile"
rm -f "$tmpdepfile"
;;
msvisualcpp)
# Important note: in order to support this mode, a compiler *must*
# always write the preprocessed file to stdout.
"$@" || exit $?
# Remove the call to Libtool.
if test "$libtool" = yes; then
while test "X$1" != 'X--mode=compile'; do
shift
done
shift
fi
IFS=" "
for arg
do
case "$arg" in
-o)
shift
;;
$object)
shift
;;
"-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI")
set fnord "$@"
shift
shift
;;
*)
set fnord "$@" "$arg"
shift
shift
;;
esac
done
"$@" -E 2>/dev/null |
sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::\1:p' | $cygpath_u | sort -u > "$tmpdepfile"
rm -f "$depfile"
echo "$object : \\" > "$depfile"
sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::'"$tab"'\1 \\:p' >> "$depfile"
echo "$tab" >> "$depfile"
sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::\1\::p' >> "$depfile"
rm -f "$tmpdepfile"
;;
msvcmsys)
# This case exists only to let depend.m4 do its work. It works by
# looking at the text of this script. This case will never be run,
# since it is checked for above.
exit 1
;;
none)
exec "$@"
;;
*)
echo "Unknown depmode $depmode" 1>&2
exit 1
;;
esac
exit 0
# Local Variables:
# mode: shell-script
# sh-indentation: 2
# eval: (add-hook 'write-file-hooks 'time-stamp)
# time-stamp-start: "scriptversion="
# time-stamp-format: "%:y-%02m-%02d.%02H"
# time-stamp-time-zone: "UTC"
# time-stamp-end: "; # UTC"
# End:
cfengine-3.12.1/AUTHORS 0000644 0000000 0000000 00000014442 13377750461 014444 0 ustar 00root root 0000000 0000000 Authors list
============
The following lists were obtained from `git shortlog`. In case of any errors and
omissions please fix them and submit a pull request. In order to fix an e-mail
or a name, please adjust .mailmap file in top level directory.
Authors (people with more than 10 commits registered), sorted alphabetically:
Kristian Amlie
Nick Anderson
Dimitrios Apostolou
Mark Burgess
Mikhail Gusarov
Volker Hilsheimer
Maciej Mrowiec
Geir Nygård
Maciej Patucha
Loic Pefferkorn
Bryce Petrini
Nakarin Phooripoom
Bishwa Shrestha
Eystein Måløy Stenberg
Sigurd Teigen
Shauna Thomas
Carlos Manuel Duclos Vergara
Bas van der Vlies
Diego Zamboni
Ted Zlatanov
Contributors (people with less than 10 commits registered), sorted alphabetically:
Trond Hasle Amundsen
Cédric Cabessa
Matthieu CERDA
P. Christeas
Jonathan CLARKE
Jeramey Crawford
Remi Debay
dolanor
Brian Bennett
Franz Bettag
Gonéri Le Bouder
Bernard Brandl
Melinda Fancsal
George Gensure
hicham
Klaus Kämpf
Daniel V. Klein
jkrabbe
Kuba
David Lee
Matt Lesko
Riccardo Murri
William Orr
Michael V. Pelletier
Russ Poyner
Frerich Raabe
Laurent Raufaste
Jean Remond
Andrew Stribblehill
James Thompson
Neil H Watson
yac
Copyright
=========
The cfengine 3 design and code is by Cfengine AS and all rights are
reserved.
In order to offer commercial support of cfengine to customers it is
important for Cfengine AS to have an uncomplicated ownership of rights
to cfengine 3 code in future products. For that reason we will require
that substantial code contrbutions (contributions of sufficient size
to warrant copyright) be accompanied by a signed transfer of rights
form to cfengine AS.
Such a transfer will not take away any of your freedoms under the GNU
public licence, but will guarantee that community contributions can be
included in cfengine's commercial future, without the need to split
cfengine into multiple versions i.e. this allows cfengine AS to make
money on commercial versions of cfengine thus supporting future
in-house development.
========================================================================
Cfengine AS Contributor statement
The terms stated below apply to your contribution of computer code and other
material to software or projects owned or managed by Cfengine AS (“project”),
and set out the intellectual property rights in the contributed material you
transfer to Cfengine. If this contribution is on behalf of a company, “you” will
also mean the company you identify below.
1. "Material" and "contribution" shall mean any source code, object code, patch,
tool, sample, graphic, specification, manual, documentation, or any other
code or other material posted or submitted by you to the project or us.
2. Regarding any worldwide copyrights, or copyright applications and
registrations, in your contribution:
* You hereby assign to us joint ownership, and to the extent that such
assignment is or becomes invalid, ineffective or unenforceable, you hereby
grant to us a perpetual, irrevocable, non-exclusive, worldwide, no-charge,
royalty-free, unrestricted license to exercise all rights under those
copyrights. This includes, at our option, the right to sublicense these same
rights to third parties through multiple levels of sublicensees or other
licensing arrangements;
* You agree that each of us can do all things in relation to your contribution
as if each of us were the sole right holder, and if one of us makes a
derivative work of your contribution, the one who makes the derivative work
(or has it made) will be the sole owner of that derivative work, hereunder
make, have made, use, sell, offer to sell, import, and otherwise transfer
your contribution in whole or in part;
* You agree that neither of us has any duty to consult with, obtain the
consent of, pay or render an accounting to the other for any use or
distribution of the material.
3. If you own or may license any patent without payment to any third party, you
hereby grant us a perpetual, irrevocable, non-exclusive, worldwide,
no-charge, royalty-free license to use, transfer and otherwise control such
material, to the same extent as described above for copyright.
4. You keep all right, title, and interest in your contribution, exempted only
as stated above. The rights that you grant to us under these terms are
effective on the date you first submitted a contribution to us, even if your
submission took place before the date you sign these terms. Any contribution
we make available under any license will also be made available under a
suitable FSF (Free Software Foundation) or OSI (Open Source Initiative)
approved license.
5. With respect to your contribution, you represent that:
* it is an original work and that you can legally grant the rights set out in
these terms;
* it does not to the best of your knowledge violate any third party's
copyrights, trademarks, patents, or other intellectual property rights; and
* you are authorized to sign this contract on behalf of your company (if
identified below).
6. These terms will be governed by the laws of Norway.
Legal venue is Oslo, Norway.
If available, please list your cfengine.com username(s) and the name of the
project(s) (or project website(s)) for which you would like to contribute
materials.
Your username: Project name (or project website) and nature of contribution:
______________ _____________________________________________________________
______________ _____________________________________________________________
______________ _____________________________________________________________
Your contact information (Please print clearly):
Your name: _____________________________________________________________________
Your company's name (if relevant): _____________________________________________
Physical mail address: _________________________________________________________
Phone, fax and email address: __________________________________________________
________________________________________________________________________________
Signature: _____________________________________________________________________
Date: __________________________________________________________________________
To send these terms to us, scan and email the signed agreement as PDF to
contact@cfengine.com
cfengine-3.12.1/config.sub 0000755 0000000 0000000 00000105775 13377750516 015372 0 ustar 00root root 0000000 0000000 #! /bin/sh
# Configuration validation subroutine script.
# Copyright 1992-2014 Free Software Foundation, Inc.
timestamp='2014-09-11'
# This file 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 .
#
# As a special exception to the GNU General Public License, if you
# distribute this file as part of a program that contains a
# configuration script generated by Autoconf, you may include it under
# the same distribution terms that you use for the rest of that
# program. This Exception is an additional permission under section 7
# of the GNU General Public License, version 3 ("GPLv3").
# Please send patches with a ChangeLog entry to config-patches@gnu.org.
#
# Configuration subroutine to validate and canonicalize a configuration type.
# Supply the specified configuration type as an argument.
# If it is invalid, we print an error message on stderr and exit with code 1.
# Otherwise, we print the canonical config type on stdout and succeed.
# You can get the latest version of this script from:
# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD
# This file is supposed to be the same for all GNU packages
# and recognize all the CPU types, system types and aliases
# that are meaningful with *any* GNU software.
# Each package is responsible for reporting which valid configurations
# it does not support. The user should be able to distinguish
# a failure to support a valid configuration from a meaningless
# configuration.
# The goal of this file is to map all the various variations of a given
# machine specification into a single specification in the form:
# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM
# or in some cases, the newer four-part form:
# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM
# It is wrong to echo any other type of specification.
me=`echo "$0" | sed -e 's,.*/,,'`
usage="\
Usage: $0 [OPTION] CPU-MFR-OPSYS
$0 [OPTION] ALIAS
Canonicalize a configuration name.
Operation modes:
-h, --help print this help, then exit
-t, --time-stamp print date of last modification, then exit
-v, --version print version number, then exit
Report bugs and patches to ."
version="\
GNU config.sub ($timestamp)
Copyright 1992-2014 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
help="
Try \`$me --help' for more information."
# Parse command line
while test $# -gt 0 ; do
case $1 in
--time-stamp | --time* | -t )
echo "$timestamp" ; exit ;;
--version | -v )
echo "$version" ; exit ;;
--help | --h* | -h )
echo "$usage"; exit ;;
-- ) # Stop option processing
shift; break ;;
- ) # Use stdin as input.
break ;;
-* )
echo "$me: invalid option $1$help"
exit 1 ;;
*local*)
# First pass through any local machine types.
echo $1
exit ;;
* )
break ;;
esac
done
case $# in
0) echo "$me: missing argument$help" >&2
exit 1;;
1) ;;
*) echo "$me: too many arguments$help" >&2
exit 1;;
esac
# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any).
# Here we must recognize all the valid KERNEL-OS combinations.
maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
case $maybe_os in
nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \
linux-musl* | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \
knetbsd*-gnu* | netbsd*-gnu* | \
kopensolaris*-gnu* | \
storm-chaos* | os2-emx* | rtmk-nova*)
os=-$maybe_os
basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
;;
android-linux)
os=-linux-android
basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`-unknown
;;
*)
basic_machine=`echo $1 | sed 's/-[^-]*$//'`
if [ $basic_machine != $1 ]
then os=`echo $1 | sed 's/.*-/-/'`
else os=; fi
;;
esac
### Let's recognize common machines as not being operating systems so
### that things like config.sub decstation-3100 work. We also
### recognize some manufacturers as not being operating systems, so we
### can provide default operating systems below.
case $os in
-sun*os*)
# Prevent following clause from handling this invalid input.
;;
-dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \
-att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \
-unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \
-convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
-c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
-harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \
-apple | -axis | -knuth | -cray | -microblaze*)
os=
basic_machine=$1
;;
-bluegene*)
os=-cnk
;;
-sim | -cisco | -oki | -wec | -winbond)
os=
basic_machine=$1
;;
-scout)
;;
-wrs)
os=-vxworks
basic_machine=$1
;;
-chorusos*)
os=-chorusos
basic_machine=$1
;;
-chorusrdb)
os=-chorusrdb
basic_machine=$1
;;
-hiux*)
os=-hiuxwe2
;;
-sco6)
os=-sco5v6
basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
;;
-sco5)
os=-sco3.2v5
basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
;;
-sco4)
os=-sco3.2v4
basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
;;
-sco3.2.[4-9]*)
os=`echo $os | sed -e 's/sco3.2./sco3.2v/'`
basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
;;
-sco3.2v[4-9]*)
# Don't forget version if it is 3.2v4 or newer.
basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
;;
-sco5v6*)
# Don't forget version if it is 3.2v4 or newer.
basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
;;
-sco*)
os=-sco3.2v2
basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
;;
-udk*)
basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
;;
-isc)
os=-isc2.2
basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
;;
-clix*)
basic_machine=clipper-intergraph
;;
-isc*)
basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
;;
-lynx*178)
os=-lynxos178
;;
-lynx*5)
os=-lynxos5
;;
-lynx*)
os=-lynxos
;;
-ptx*)
basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'`
;;
-windowsnt*)
os=`echo $os | sed -e 's/windowsnt/winnt/'`
;;
-psos*)
os=-psos
;;
-mint | -mint[0-9]*)
basic_machine=m68k-atari
os=-mint
;;
esac
# Decode aliases for certain CPU-COMPANY combinations.
case $basic_machine in
# Recognize the basic CPU types without company name.
# Some are omitted here because they have special meanings below.
1750a | 580 \
| a29k \
| aarch64 | aarch64_be \
| alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \
| alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \
| am33_2.0 \
| arc | arceb \
| arm | arm[bl]e | arme[lb] | armv[2-8] | armv[3-8][lb] | armv7[arm] \
| avr | avr32 \
| be32 | be64 \
| bfin \
| c4x | c8051 | clipper \
| d10v | d30v | dlx | dsp16xx \
| epiphany \
| fido | fr30 | frv \
| h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
| hexagon \
| i370 | i860 | i960 | ia64 \
| ip2k | iq2000 \
| k1om \
| le32 | le64 \
| lm32 \
| m32c | m32r | m32rle | m68000 | m68k | m88k \
| maxq | mb | microblaze | microblazeel | mcore | mep | metag \
| mips | mipsbe | mipseb | mipsel | mipsle \
| mips16 \
| mips64 | mips64el \
| mips64octeon | mips64octeonel \
| mips64orion | mips64orionel \
| mips64r5900 | mips64r5900el \
| mips64vr | mips64vrel \
| mips64vr4100 | mips64vr4100el \
| mips64vr4300 | mips64vr4300el \
| mips64vr5000 | mips64vr5000el \
| mips64vr5900 | mips64vr5900el \
| mipsisa32 | mipsisa32el \
| mipsisa32r2 | mipsisa32r2el \
| mipsisa32r6 | mipsisa32r6el \
| mipsisa64 | mipsisa64el \
| mipsisa64r2 | mipsisa64r2el \
| mipsisa64r6 | mipsisa64r6el \
| mipsisa64sb1 | mipsisa64sb1el \
| mipsisa64sr71k | mipsisa64sr71kel \
| mipsr5900 | mipsr5900el \
| mipstx39 | mipstx39el \
| mn10200 | mn10300 \
| moxie \
| mt \
| msp430 \
| nds32 | nds32le | nds32be \
| nios | nios2 | nios2eb | nios2el \
| ns16k | ns32k \
| open8 | or1k | or1knd | or32 \
| pdp10 | pdp11 | pj | pjl \
| powerpc | powerpc64 | powerpc64le | powerpcle \
| pyramid \
| riscv32 | riscv64 \
| rl78 | rx \
| score \
| sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \
| sh64 | sh64le \
| sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \
| sparcv8 | sparcv9 | sparcv9b | sparcv9v \
| spu \
| tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \
| ubicom32 \
| v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \
| we32k \
| x86 | xc16x | xstormy16 | xtensa \
| z8k | z80)
basic_machine=$basic_machine-unknown
;;
c54x)
basic_machine=tic54x-unknown
;;
c55x)
basic_machine=tic55x-unknown
;;
c6x)
basic_machine=tic6x-unknown
;;
m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | nvptx | picochip)
basic_machine=$basic_machine-unknown
os=-none
;;
m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k)
;;
ms1)
basic_machine=mt-unknown
;;
strongarm | thumb | xscale)
basic_machine=arm-unknown
;;
xgate)
basic_machine=$basic_machine-unknown
os=-none
;;
xscaleeb)
basic_machine=armeb-unknown
;;
xscaleel)
basic_machine=armel-unknown
;;
# We use `pc' rather than `unknown'
# because (1) that's what they normally are, and
# (2) the word "unknown" tends to confuse beginning users.
i*86 | x86_64)
basic_machine=$basic_machine-pc
;;
# Object if more than one company name word.
*-*-*)
echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
exit 1
;;
# Recognize the basic CPU types with company name.
580-* \
| a29k-* \
| aarch64-* | aarch64_be-* \
| alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \
| alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \
| alphapca5[67]-* | alpha64pca5[67]-* | arc-* | arceb-* \
| arm-* | armbe-* | armle-* | armeb-* | armv*-* \
| avr-* | avr32-* \
| be32-* | be64-* \
| bfin-* | bs2000-* \
| c[123]* | c30-* | [cjt]90-* | c4x-* \
| c8051-* | clipper-* | craynv-* | cydra-* \
| d10v-* | d30v-* | dlx-* \
| elxsi-* \
| f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \
| h8300-* | h8500-* \
| hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \
| hexagon-* \
| i*86-* | i860-* | i960-* | ia64-* \
| ip2k-* | iq2000-* \
| k1om-* \
| le32-* | le64-* \
| lm32-* \
| m32c-* | m32r-* | m32rle-* \
| m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \
| m88110-* | m88k-* | maxq-* | mcore-* | metag-* \
| microblaze-* | microblazeel-* \
| mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \
| mips16-* \
| mips64-* | mips64el-* \
| mips64octeon-* | mips64octeonel-* \
| mips64orion-* | mips64orionel-* \
| mips64r5900-* | mips64r5900el-* \
| mips64vr-* | mips64vrel-* \
| mips64vr4100-* | mips64vr4100el-* \
| mips64vr4300-* | mips64vr4300el-* \
| mips64vr5000-* | mips64vr5000el-* \
| mips64vr5900-* | mips64vr5900el-* \
| mipsisa32-* | mipsisa32el-* \
| mipsisa32r2-* | mipsisa32r2el-* \
| mipsisa32r6-* | mipsisa32r6el-* \
| mipsisa64-* | mipsisa64el-* \
| mipsisa64r2-* | mipsisa64r2el-* \
| mipsisa64r6-* | mipsisa64r6el-* \
| mipsisa64sb1-* | mipsisa64sb1el-* \
| mipsisa64sr71k-* | mipsisa64sr71kel-* \
| mipsr5900-* | mipsr5900el-* \
| mipstx39-* | mipstx39el-* \
| mmix-* \
| mt-* \
| msp430-* \
| nds32-* | nds32le-* | nds32be-* \
| nios-* | nios2-* | nios2eb-* | nios2el-* \
| none-* | np1-* | ns16k-* | ns32k-* \
| open8-* \
| or1k*-* \
| orion-* \
| pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \
| powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \
| pyramid-* \
| rl78-* | romp-* | rs6000-* | rx-* \
| sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \
| shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \
| sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \
| sparclite-* \
| sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx?-* \
| tahoe-* \
| tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \
| tile*-* \
| tron-* \
| ubicom32-* \
| v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \
| vax-* \
| we32k-* \
| x86-* | x86_64-* | xc16x-* | xps100-* \
| xstormy16-* | xtensa*-* \
| ymp-* \
| z8k-* | z80-*)
;;
# Recognize the basic CPU types without company name, with glob match.
xtensa*)
basic_machine=$basic_machine-unknown
;;
# Recognize the various machine names and aliases which stand
# for a CPU type and a company and sometimes even an OS.
386bsd)
basic_machine=i386-unknown
os=-bsd
;;
3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc)
basic_machine=m68000-att
;;
3b*)
basic_machine=we32k-att
;;
a29khif)
basic_machine=a29k-amd
os=-udi
;;
abacus)
basic_machine=abacus-unknown
;;
adobe68k)
basic_machine=m68010-adobe
os=-scout
;;
alliant | fx80)
basic_machine=fx80-alliant
;;
altos | altos3068)
basic_machine=m68k-altos
;;
am29k)
basic_machine=a29k-none
os=-bsd
;;
amd64)
basic_machine=x86_64-pc
;;
amd64-*)
basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'`
;;
amdahl)
basic_machine=580-amdahl
os=-sysv
;;
amiga | amiga-*)
basic_machine=m68k-unknown
;;
amigaos | amigados)
basic_machine=m68k-unknown
os=-amigaos
;;
amigaunix | amix)
basic_machine=m68k-unknown
os=-sysv4
;;
apollo68)
basic_machine=m68k-apollo
os=-sysv
;;
apollo68bsd)
basic_machine=m68k-apollo
os=-bsd
;;
aros)
basic_machine=i386-pc
os=-aros
;;
aux)
basic_machine=m68k-apple
os=-aux
;;
balance)
basic_machine=ns32k-sequent
os=-dynix
;;
blackfin)
basic_machine=bfin-unknown
os=-linux
;;
blackfin-*)
basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'`
os=-linux
;;
bluegene*)
basic_machine=powerpc-ibm
os=-cnk
;;
c54x-*)
basic_machine=tic54x-`echo $basic_machine | sed 's/^[^-]*-//'`
;;
c55x-*)
basic_machine=tic55x-`echo $basic_machine | sed 's/^[^-]*-//'`
;;
c6x-*)
basic_machine=tic6x-`echo $basic_machine | sed 's/^[^-]*-//'`
;;
c90)
basic_machine=c90-cray
os=-unicos
;;
cegcc)
basic_machine=arm-unknown
os=-cegcc
;;
convex-c1)
basic_machine=c1-convex
os=-bsd
;;
convex-c2)
basic_machine=c2-convex
os=-bsd
;;
convex-c32)
basic_machine=c32-convex
os=-bsd
;;
convex-c34)
basic_machine=c34-convex
os=-bsd
;;
convex-c38)
basic_machine=c38-convex
os=-bsd
;;
cray | j90)
basic_machine=j90-cray
os=-unicos
;;
craynv)
basic_machine=craynv-cray
os=-unicosmp
;;
cr16 | cr16-*)
basic_machine=cr16-unknown
os=-elf
;;
crds | unos)
basic_machine=m68k-crds
;;
crisv32 | crisv32-* | etraxfs*)
basic_machine=crisv32-axis
;;
cris | cris-* | etrax*)
basic_machine=cris-axis
;;
crx)
basic_machine=crx-unknown
os=-elf
;;
da30 | da30-*)
basic_machine=m68k-da30
;;
decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn)
basic_machine=mips-dec
;;
decsystem10* | dec10*)
basic_machine=pdp10-dec
os=-tops10
;;
decsystem20* | dec20*)
basic_machine=pdp10-dec
os=-tops20
;;
delta | 3300 | motorola-3300 | motorola-delta \
| 3300-motorola | delta-motorola)
basic_machine=m68k-motorola
;;
delta88)
basic_machine=m88k-motorola
os=-sysv3
;;
dicos)
basic_machine=i686-pc
os=-dicos
;;
djgpp)
basic_machine=i586-pc
os=-msdosdjgpp
;;
dpx20 | dpx20-*)
basic_machine=rs6000-bull
os=-bosx
;;
dpx2* | dpx2*-bull)
basic_machine=m68k-bull
os=-sysv3
;;
ebmon29k)
basic_machine=a29k-amd
os=-ebmon
;;
elxsi)
basic_machine=elxsi-elxsi
os=-bsd
;;
encore | umax | mmax)
basic_machine=ns32k-encore
;;
es1800 | OSE68k | ose68k | ose | OSE)
basic_machine=m68k-ericsson
os=-ose
;;
fx2800)
basic_machine=i860-alliant
;;
genix)
basic_machine=ns32k-ns
;;
gmicro)
basic_machine=tron-gmicro
os=-sysv
;;
go32)
basic_machine=i386-pc
os=-go32
;;
h3050r* | hiux*)
basic_machine=hppa1.1-hitachi
os=-hiuxwe2
;;
h8300hms)
basic_machine=h8300-hitachi
os=-hms
;;
h8300xray)
basic_machine=h8300-hitachi
os=-xray
;;
h8500hms)
basic_machine=h8500-hitachi
os=-hms
;;
harris)
basic_machine=m88k-harris
os=-sysv3
;;
hp300-*)
basic_machine=m68k-hp
;;
hp300bsd)
basic_machine=m68k-hp
os=-bsd
;;
hp300hpux)
basic_machine=m68k-hp
os=-hpux
;;
hp3k9[0-9][0-9] | hp9[0-9][0-9])
basic_machine=hppa1.0-hp
;;
hp9k2[0-9][0-9] | hp9k31[0-9])
basic_machine=m68000-hp
;;
hp9k3[2-9][0-9])
basic_machine=m68k-hp
;;
hp9k6[0-9][0-9] | hp6[0-9][0-9])
basic_machine=hppa1.0-hp
;;
hp9k7[0-79][0-9] | hp7[0-79][0-9])
basic_machine=hppa1.1-hp
;;
hp9k78[0-9] | hp78[0-9])
# FIXME: really hppa2.0-hp
basic_machine=hppa1.1-hp
;;
hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893)
# FIXME: really hppa2.0-hp
basic_machine=hppa1.1-hp
;;
hp9k8[0-9][13679] | hp8[0-9][13679])
basic_machine=hppa1.1-hp
;;
hp9k8[0-9][0-9] | hp8[0-9][0-9])
basic_machine=hppa1.0-hp
;;
hppa-next)
os=-nextstep3
;;
hppaosf)
basic_machine=hppa1.1-hp
os=-osf
;;
hppro)
basic_machine=hppa1.1-hp
os=-proelf
;;
i370-ibm* | ibm*)
basic_machine=i370-ibm
;;
i*86v32)
basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
os=-sysv32
;;
i*86v4*)
basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
os=-sysv4
;;
i*86v)
basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
os=-sysv
;;
i*86sol2)
basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
os=-solaris2
;;
i386mach)
basic_machine=i386-mach
os=-mach
;;
i386-vsta | vsta)
basic_machine=i386-unknown
os=-vsta
;;
iris | iris4d)
basic_machine=mips-sgi
case $os in
-irix*)
;;
*)
os=-irix4
;;
esac
;;
isi68 | isi)
basic_machine=m68k-isi
os=-sysv
;;
m68knommu)
basic_machine=m68k-unknown
os=-linux
;;
m68knommu-*)
basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'`
os=-linux
;;
m88k-omron*)
basic_machine=m88k-omron
;;
magnum | m3230)
basic_machine=mips-mips
os=-sysv
;;
merlin)
basic_machine=ns32k-utek
os=-sysv
;;
microblaze*)
basic_machine=microblaze-xilinx
;;
mingw64)
basic_machine=x86_64-pc
os=-mingw64
;;
mingw32)
basic_machine=i686-pc
os=-mingw32
;;
mingw32ce)
basic_machine=arm-unknown
os=-mingw32ce
;;
miniframe)
basic_machine=m68000-convergent
;;
*mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*)
basic_machine=m68k-atari
os=-mint
;;
mips3*-*)
basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`
;;
mips3*)
basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown
;;
monitor)
basic_machine=m68k-rom68k
os=-coff
;;
morphos)
basic_machine=powerpc-unknown
os=-morphos
;;
moxiebox)
basic_machine=moxie-unknown
os=-moxiebox
;;
msdos)
basic_machine=i386-pc
os=-msdos
;;
ms1-*)
basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'`
;;
msys)
basic_machine=i686-pc
os=-msys
;;
mvs)
basic_machine=i370-ibm
os=-mvs
;;
nacl)
basic_machine=le32-unknown
os=-nacl
;;
ncr3000)
basic_machine=i486-ncr
os=-sysv4
;;
netbsd386)
basic_machine=i386-unknown
os=-netbsd
;;
netwinder)
basic_machine=armv4l-rebel
os=-linux
;;
news | news700 | news800 | news900)
basic_machine=m68k-sony
os=-newsos
;;
news1000)
basic_machine=m68030-sony
os=-newsos
;;
news-3600 | risc-news)
basic_machine=mips-sony
os=-newsos
;;
necv70)
basic_machine=v70-nec
os=-sysv
;;
next | m*-next )
basic_machine=m68k-next
case $os in
-nextstep* )
;;
-ns2*)
os=-nextstep2
;;
*)
os=-nextstep3
;;
esac
;;
nh3000)
basic_machine=m68k-harris
os=-cxux
;;
nh[45]000)
basic_machine=m88k-harris
os=-cxux
;;
nindy960)
basic_machine=i960-intel
os=-nindy
;;
mon960)
basic_machine=i960-intel
os=-mon960
;;
nonstopux)
basic_machine=mips-compaq
os=-nonstopux
;;
np1)
basic_machine=np1-gould
;;
neo-tandem)
basic_machine=neo-tandem
;;
nse-tandem)
basic_machine=nse-tandem
;;
nsr-tandem)
basic_machine=nsr-tandem
;;
op50n-* | op60c-*)
basic_machine=hppa1.1-oki
os=-proelf
;;
openrisc | openrisc-*)
basic_machine=or32-unknown
;;
os400)
basic_machine=powerpc-ibm
os=-os400
;;
OSE68000 | ose68000)
basic_machine=m68000-ericsson
os=-ose
;;
os68k)
basic_machine=m68k-none
os=-os68k
;;
pa-hitachi)
basic_machine=hppa1.1-hitachi
os=-hiuxwe2
;;
paragon)
basic_machine=i860-intel
os=-osf
;;
parisc)
basic_machine=hppa-unknown
os=-linux
;;
parisc-*)
basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'`
os=-linux
;;
pbd)
basic_machine=sparc-tti
;;
pbb)
basic_machine=m68k-tti
;;
pc532 | pc532-*)
basic_machine=ns32k-pc532
;;
pc98)
basic_machine=i386-pc
;;
pc98-*)
basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'`
;;
pentium | p5 | k5 | k6 | nexgen | viac3)
basic_machine=i586-pc
;;
pentiumpro | p6 | 6x86 | athlon | athlon_*)
basic_machine=i686-pc
;;
pentiumii | pentium2 | pentiumiii | pentium3)
basic_machine=i686-pc
;;
pentium4)
basic_machine=i786-pc
;;
pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*)
basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'`
;;
pentiumpro-* | p6-* | 6x86-* | athlon-*)
basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
;;
pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*)
basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
;;
pentium4-*)
basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'`
;;
pn)
basic_machine=pn-gould
;;
power) basic_machine=power-ibm
;;
ppc | ppcbe) basic_machine=powerpc-unknown
;;
ppc-* | ppcbe-*)
basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
;;
ppcle | powerpclittle | ppc-le | powerpc-little)
basic_machine=powerpcle-unknown
;;
ppcle-* | powerpclittle-*)
basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'`
;;
ppc64) basic_machine=powerpc64-unknown
;;
ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'`
;;
ppc64le | powerpc64little | ppc64-le | powerpc64-little)
basic_machine=powerpc64le-unknown
;;
ppc64le-* | powerpc64little-*)
basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'`
;;
ps2)
basic_machine=i386-ibm
;;
pw32)
basic_machine=i586-unknown
os=-pw32
;;
rdos | rdos64)
basic_machine=x86_64-pc
os=-rdos
;;
rdos32)
basic_machine=i386-pc
os=-rdos
;;
rom68k)
basic_machine=m68k-rom68k
os=-coff
;;
rm[46]00)
basic_machine=mips-siemens
;;
rtpc | rtpc-*)
basic_machine=romp-ibm
;;
s390 | s390-*)
basic_machine=s390-ibm
;;
s390x | s390x-*)
basic_machine=s390x-ibm
;;
sa29200)
basic_machine=a29k-amd
os=-udi
;;
sb1)
basic_machine=mipsisa64sb1-unknown
;;
sb1el)
basic_machine=mipsisa64sb1el-unknown
;;
sde)
basic_machine=mipsisa32-sde
os=-elf
;;
sei)
basic_machine=mips-sei
os=-seiux
;;
sequent)
basic_machine=i386-sequent
;;
sh)
basic_machine=sh-hitachi
os=-hms
;;
sh5el)
basic_machine=sh5le-unknown
;;
sh64)
basic_machine=sh64-unknown
;;
sparclite-wrs | simso-wrs)
basic_machine=sparclite-wrs
os=-vxworks
;;
sps7)
basic_machine=m68k-bull
os=-sysv2
;;
spur)
basic_machine=spur-unknown
;;
st2000)
basic_machine=m68k-tandem
;;
stratus)
basic_machine=i860-stratus
os=-sysv4
;;
strongarm-* | thumb-*)
basic_machine=arm-`echo $basic_machine | sed 's/^[^-]*-//'`
;;
sun2)
basic_machine=m68000-sun
;;
sun2os3)
basic_machine=m68000-sun
os=-sunos3
;;
sun2os4)
basic_machine=m68000-sun
os=-sunos4
;;
sun3os3)
basic_machine=m68k-sun
os=-sunos3
;;
sun3os4)
basic_machine=m68k-sun
os=-sunos4
;;
sun4os3)
basic_machine=sparc-sun
os=-sunos3
;;
sun4os4)
basic_machine=sparc-sun
os=-sunos4
;;
sun4sol2)
basic_machine=sparc-sun
os=-solaris2
;;
sun3 | sun3-*)
basic_machine=m68k-sun
;;
sun4)
basic_machine=sparc-sun
;;
sun386 | sun386i | roadrunner)
basic_machine=i386-sun
;;
sv1)
basic_machine=sv1-cray
os=-unicos
;;
symmetry)
basic_machine=i386-sequent
os=-dynix
;;
t3e)
basic_machine=alphaev5-cray
os=-unicos
;;
t90)
basic_machine=t90-cray
os=-unicos
;;
tile*)
basic_machine=$basic_machine-unknown
os=-linux-gnu
;;
tx39)
basic_machine=mipstx39-unknown
;;
tx39el)
basic_machine=mipstx39el-unknown
;;
toad1)
basic_machine=pdp10-xkl
os=-tops20
;;
tower | tower-32)
basic_machine=m68k-ncr
;;
tpf)
basic_machine=s390x-ibm
os=-tpf
;;
udi29k)
basic_machine=a29k-amd
os=-udi
;;
ultra3)
basic_machine=a29k-nyu
os=-sym1
;;
v810 | necv810)
basic_machine=v810-nec
os=-none
;;
vaxv)
basic_machine=vax-dec
os=-sysv
;;
vms)
basic_machine=vax-dec
os=-vms
;;
vpp*|vx|vx-*)
basic_machine=f301-fujitsu
;;
vxworks960)
basic_machine=i960-wrs
os=-vxworks
;;
vxworks68)
basic_machine=m68k-wrs
os=-vxworks
;;
vxworks29k)
basic_machine=a29k-wrs
os=-vxworks
;;
w65*)
basic_machine=w65-wdc
os=-none
;;
w89k-*)
basic_machine=hppa1.1-winbond
os=-proelf
;;
xbox)
basic_machine=i686-pc
os=-mingw32
;;
xps | xps100)
basic_machine=xps100-honeywell
;;
xscale-* | xscalee[bl]-*)
basic_machine=`echo $basic_machine | sed 's/^xscale/arm/'`
;;
ymp)
basic_machine=ymp-cray
os=-unicos
;;
z8k-*-coff)
basic_machine=z8k-unknown
os=-sim
;;
z80-*-coff)
basic_machine=z80-unknown
os=-sim
;;
none)
basic_machine=none-none
os=-none
;;
# Here we handle the default manufacturer of certain CPU types. It is in
# some cases the only manufacturer, in others, it is the most popular.
w89k)
basic_machine=hppa1.1-winbond
;;
op50n)
basic_machine=hppa1.1-oki
;;
op60c)
basic_machine=hppa1.1-oki
;;
romp)
basic_machine=romp-ibm
;;
mmix)
basic_machine=mmix-knuth
;;
rs6000)
basic_machine=rs6000-ibm
;;
vax)
basic_machine=vax-dec
;;
pdp10)
# there are many clones, so DEC is not a safe bet
basic_machine=pdp10-unknown
;;
pdp11)
basic_machine=pdp11-dec
;;
we32k)
basic_machine=we32k-att
;;
sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele)
basic_machine=sh-unknown
;;
sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v)
basic_machine=sparc-sun
;;
cydra)
basic_machine=cydra-cydrome
;;
orion)
basic_machine=orion-highlevel
;;
orion105)
basic_machine=clipper-highlevel
;;
mac | mpw | mac-mpw)
basic_machine=m68k-apple
;;
pmac | pmac-mpw)
basic_machine=powerpc-apple
;;
*-unknown)
# Make sure to match an already-canonicalized machine name.
;;
*)
echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
exit 1
;;
esac
# Here we canonicalize certain aliases for manufacturers.
case $basic_machine in
*-digital*)
basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'`
;;
*-commodore*)
basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'`
;;
*)
;;
esac
# Decode manufacturer-specific aliases for certain operating systems.
if [ x"$os" != x"" ]
then
case $os in
# First match some system type aliases
# that might get confused with valid system types.
# -solaris* is a basic system type, with this one exception.
-auroraux)
os=-auroraux
;;
-solaris1 | -solaris1.*)
os=`echo $os | sed -e 's|solaris1|sunos4|'`
;;
-solaris)
os=-solaris2
;;
-svr4*)
os=-sysv4
;;
-unixware*)
os=-sysv4.2uw
;;
-gnu/linux*)
os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'`
;;
# First accept the basic system types.
# The portable systems comes first.
# Each alternative MUST END IN A *, to match a version number.
# -sysv* is not here because it comes later, after sysvr4.
-gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \
| -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\
| -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \
| -sym* | -kopensolaris* | -plan9* \
| -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
| -aos* | -aros* \
| -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
| -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
| -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \
| -bitrig* | -openbsd* | -solidbsd* \
| -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \
| -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
| -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
| -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
| -chorusos* | -chorusrdb* | -cegcc* \
| -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
| -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \
| -linux-newlib* | -linux-musl* | -linux-uclibc* \
| -uxpv* | -beos* | -mpeix* | -udk* | -moxiebox* \
| -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \
| -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \
| -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \
| -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \
| -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \
| -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \
| -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es* | -tirtos*)
# Remember, each alternative MUST END IN *, to match a version number.
;;
-qnx*)
case $basic_machine in
x86-* | i*86-*)
;;
*)
os=-nto$os
;;
esac
;;
-nto-qnx*)
;;
-nto*)
os=`echo $os | sed -e 's|nto|nto-qnx|'`
;;
-sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \
| -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \
| -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*)
;;
-mac*)
os=`echo $os | sed -e 's|mac|macos|'`
;;
-linux-dietlibc)
os=-linux-dietlibc
;;
-linux*)
os=`echo $os | sed -e 's|linux|linux-gnu|'`
;;
-sunos5*)
os=`echo $os | sed -e 's|sunos5|solaris2|'`
;;
-sunos6*)
os=`echo $os | sed -e 's|sunos6|solaris3|'`
;;
-opened*)
os=-openedition
;;
-os400*)
os=-os400
;;
-wince*)
os=-wince
;;
-osfrose*)
os=-osfrose
;;
-osf*)
os=-osf
;;
-utek*)
os=-bsd
;;
-dynix*)
os=-bsd
;;
-acis*)
os=-aos
;;
-atheos*)
os=-atheos
;;
-syllable*)
os=-syllable
;;
-386bsd)
os=-bsd
;;
-ctix* | -uts*)
os=-sysv
;;
-nova*)
os=-rtmk-nova
;;
-ns2 )
os=-nextstep2
;;
-nsk*)
os=-nsk
;;
# Preserve the version number of sinix5.
-sinix5.*)
os=`echo $os | sed -e 's|sinix|sysv|'`
;;
-sinix*)
os=-sysv4
;;
-tpf*)
os=-tpf
;;
-triton*)
os=-sysv3
;;
-oss*)
os=-sysv3
;;
-svr4)
os=-sysv4
;;
-svr3)
os=-sysv3
;;
-sysvr4)
os=-sysv4
;;
# This must come after -sysvr4.
-sysv*)
;;
-ose*)
os=-ose
;;
-es1800*)
os=-ose
;;
-xenix)
os=-xenix
;;
-*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
os=-mint
;;
-aros*)
os=-aros
;;
-zvmoe)
os=-zvmoe
;;
-dicos*)
os=-dicos
;;
-nacl*)
;;
-none)
;;
*)
# Get rid of the `-' at the beginning of $os.
os=`echo $os | sed 's/[^-]*-//'`
echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2
exit 1
;;
esac
else
# Here we handle the default operating systems that come with various machines.
# The value should be what the vendor currently ships out the door with their
# machine or put another way, the most popular os provided with the machine.
# Note that if you're going to try to match "-MANUFACTURER" here (say,
# "-sun"), then you have to tell the case statement up towards the top
# that MANUFACTURER isn't an operating system. Otherwise, code above
# will signal an error saying that MANUFACTURER isn't an operating
# system, and we'll never get to this point.
case $basic_machine in
score-*)
os=-elf
;;
spu-*)
os=-elf
;;
*-acorn)
os=-riscix1.2
;;
arm*-rebel)
os=-linux
;;
arm*-semi)
os=-aout
;;
c4x-* | tic4x-*)
os=-coff
;;
c8051-*)
os=-elf
;;
hexagon-*)
os=-elf
;;
tic54x-*)
os=-coff
;;
tic55x-*)
os=-coff
;;
tic6x-*)
os=-coff
;;
# This must come before the *-dec entry.
pdp10-*)
os=-tops20
;;
pdp11-*)
os=-none
;;
*-dec | vax-*)
os=-ultrix4.2
;;
m68*-apollo)
os=-domain
;;
i386-sun)
os=-sunos4.0.2
;;
m68000-sun)
os=-sunos3
;;
m68*-cisco)
os=-aout
;;
mep-*)
os=-elf
;;
mips*-cisco)
os=-elf
;;
mips*-*)
os=-elf
;;
or32-*)
os=-coff
;;
*-tti) # must be before sparc entry or we get the wrong os.
os=-sysv3
;;
sparc-* | *-sun)
os=-sunos4.1.1
;;
*-be)
os=-beos
;;
*-haiku)
os=-haiku
;;
*-ibm)
os=-aix
;;
*-knuth)
os=-mmixware
;;
*-wec)
os=-proelf
;;
*-winbond)
os=-proelf
;;
*-oki)
os=-proelf
;;
*-hp)
os=-hpux
;;
*-hitachi)
os=-hiux
;;
i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent)
os=-sysv
;;
*-cbm)
os=-amigaos
;;
*-dg)
os=-dgux
;;
*-dolphin)
os=-sysv3
;;
m68k-ccur)
os=-rtu
;;
m88k-omron*)
os=-luna
;;
*-next )
os=-nextstep
;;
*-sequent)
os=-ptx
;;
*-crds)
os=-unos
;;
*-ns)
os=-genix
;;
i370-*)
os=-mvs
;;
*-next)
os=-nextstep3
;;
*-gould)
os=-sysv
;;
*-highlevel)
os=-bsd
;;
*-encore)
os=-bsd
;;
*-sgi)
os=-irix
;;
*-siemens)
os=-sysv4
;;
*-masscomp)
os=-rtu
;;
f30[01]-fujitsu | f700-fujitsu)
os=-uxpv
;;
*-rom68k)
os=-coff
;;
*-*bug)
os=-coff
;;
*-apple)
os=-macos
;;
*-atari*)
os=-mint
;;
*)
os=-none
;;
esac
fi
# Here we handle the case where we know the os, and the CPU type, but not the
# manufacturer. We pick the logical manufacturer.
vendor=unknown
case $basic_machine in
*-unknown)
case $os in
-riscix*)
vendor=acorn
;;
-sunos*)
vendor=sun
;;
-cnk*|-aix*)
vendor=ibm
;;
-beos*)
vendor=be
;;
-hpux*)
vendor=hp
;;
-mpeix*)
vendor=hp
;;
-hiux*)
vendor=hitachi
;;
-unos*)
vendor=crds
;;
-dgux*)
vendor=dg
;;
-luna*)
vendor=omron
;;
-genix*)
vendor=ns
;;
-mvs* | -opened*)
vendor=ibm
;;
-os400*)
vendor=ibm
;;
-ptx*)
vendor=sequent
;;
-tpf*)
vendor=ibm
;;
-vxsim* | -vxworks* | -windiss*)
vendor=wrs
;;
-aux*)
vendor=apple
;;
-hms*)
vendor=hitachi
;;
-mpw* | -macos*)
vendor=apple
;;
-*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
vendor=atari
;;
-vos*)
vendor=stratus
;;
esac
basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"`
;;
esac
echo $basic_machine$os
exit
# Local variables:
# eval: (add-hook 'write-file-hooks 'time-stamp)
# time-stamp-start: "timestamp='"
# time-stamp-format: "%:y-%02m-%02d"
# time-stamp-end: "'"
# End:
cfengine-3.12.1/configure_flags.env.in 0000644 0000000 0000000 00000001356 13377750461 017650 0 ustar 00root root 0000000 0000000 CORE_CPPFLAGS="@CORE_CPPFLAGS@"
CORE_CFLAGS="@CORE_CFLAGS@"
CORE_LDFLAGS="@CORE_LDFLAGS@"
CORE_LIBS="@CORE_LIBS@"
CORE_VERSION="@VERSION@"
AGENT_CPPFLAGS="@LIBVIRT_CPPFLAGS@ @POSTGRESQL_CPPFLAGS@ @MYSQL_CPPFLAGS@ @LIBXML2_CPPFLAGS@ @PAM_CPPFLAGS@"
AGENT_CFLAGS="@LIBVIRT_CFLAGS@ @POSTGRESQL_CFLAGS@ @MYSQL_CFLAGS@ @LIBXML2_CFLAGS@ @PAM_CFLAGS@"
AGENT_LDFLAGS="@LIBVIRT_LDFLAGS@ @POSTGRESQL_LDFLAGS@ @MYSQL_LDFLAGS@ @LIBXML2_LDFLAGS@ @PAM_LDFLAGS@"
AGENT_LDADD="@LIBVIRT_LIBS@ @POSTGRESQL_LIBS@ @MYSQL_LIBS@ @LIBXML2_LIBS@ @PAM_LIBS@"
hw_cv_func_mkdir_proper="@hw_cv_func_mkdir_proper@"
hw_cv_func_stat_proper="@hw_cv_func_stat_proper@"
hw_cv_func_rename_proper="@hw_cv_func_rename_proper@"
enable_builtin_extensions="@enable_builtin_extensions@"
cfengine-3.12.1/missing 0000755 0000000 0000000 00000015330 13377750516 014771 0 ustar 00root root 0000000 0000000 #! /bin/sh
# Common wrapper for a few potentially missing GNU programs.
scriptversion=2013-10-28.13; # UTC
# Copyright (C) 1996-2013 Free Software Foundation, Inc.
# Originally written by Fran,cois Pinard , 1996.
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
# As a special exception to the GNU General Public License, if you
# distribute this file as part of a program that contains a
# configuration script generated by Autoconf, you may include it under
# the same distribution terms that you use for the rest of that program.
if test $# -eq 0; then
echo 1>&2 "Try '$0 --help' for more information"
exit 1
fi
case $1 in
--is-lightweight)
# Used by our autoconf macros to check whether the available missing
# script is modern enough.
exit 0
;;
--run)
# Back-compat with the calling convention used by older automake.
shift
;;
-h|--h|--he|--hel|--help)
echo "\
$0 [OPTION]... PROGRAM [ARGUMENT]...
Run 'PROGRAM [ARGUMENT]...', returning a proper advice when this fails due
to PROGRAM being missing or too old.
Options:
-h, --help display this help and exit
-v, --version output version information and exit
Supported PROGRAM values:
aclocal autoconf autoheader autom4te automake makeinfo
bison yacc flex lex help2man
Version suffixes to PROGRAM as well as the prefixes 'gnu-', 'gnu', and
'g' are ignored when checking the name.
Send bug reports to ."
exit $?
;;
-v|--v|--ve|--ver|--vers|--versi|--versio|--version)
echo "missing $scriptversion (GNU Automake)"
exit $?
;;
-*)
echo 1>&2 "$0: unknown '$1' option"
echo 1>&2 "Try '$0 --help' for more information"
exit 1
;;
esac
# Run the given program, remember its exit status.
"$@"; st=$?
# If it succeeded, we are done.
test $st -eq 0 && exit 0
# Also exit now if we it failed (or wasn't found), and '--version' was
# passed; such an option is passed most likely to detect whether the
# program is present and works.
case $2 in --version|--help) exit $st;; esac
# Exit code 63 means version mismatch. This often happens when the user
# tries to use an ancient version of a tool on a file that requires a
# minimum version.
if test $st -eq 63; then
msg="probably too old"
elif test $st -eq 127; then
# Program was missing.
msg="missing on your system"
else
# Program was found and executed, but failed. Give up.
exit $st
fi
perl_URL=http://www.perl.org/
flex_URL=http://flex.sourceforge.net/
gnu_software_URL=http://www.gnu.org/software
program_details ()
{
case $1 in
aclocal|automake)
echo "The '$1' program is part of the GNU Automake package:"
echo "<$gnu_software_URL/automake>"
echo "It also requires GNU Autoconf, GNU m4 and Perl in order to run:"
echo "<$gnu_software_URL/autoconf>"
echo "<$gnu_software_URL/m4/>"
echo "<$perl_URL>"
;;
autoconf|autom4te|autoheader)
echo "The '$1' program is part of the GNU Autoconf package:"
echo "<$gnu_software_URL/autoconf/>"
echo "It also requires GNU m4 and Perl in order to run:"
echo "<$gnu_software_URL/m4/>"
echo "<$perl_URL>"
;;
esac
}
give_advice ()
{
# Normalize program name to check for.
normalized_program=`echo "$1" | sed '
s/^gnu-//; t
s/^gnu//; t
s/^g//; t'`
printf '%s\n' "'$1' is $msg."
configure_deps="'configure.ac' or m4 files included by 'configure.ac'"
case $normalized_program in
autoconf*)
echo "You should only need it if you modified 'configure.ac',"
echo "or m4 files included by it."
program_details 'autoconf'
;;
autoheader*)
echo "You should only need it if you modified 'acconfig.h' or"
echo "$configure_deps."
program_details 'autoheader'
;;
automake*)
echo "You should only need it if you modified 'Makefile.am' or"
echo "$configure_deps."
program_details 'automake'
;;
aclocal*)
echo "You should only need it if you modified 'acinclude.m4' or"
echo "$configure_deps."
program_details 'aclocal'
;;
autom4te*)
echo "You might have modified some maintainer files that require"
echo "the 'autom4te' program to be rebuilt."
program_details 'autom4te'
;;
bison*|yacc*)
echo "You should only need it if you modified a '.y' file."
echo "You may want to install the GNU Bison package:"
echo "<$gnu_software_URL/bison/>"
;;
lex*|flex*)
echo "You should only need it if you modified a '.l' file."
echo "You may want to install the Fast Lexical Analyzer package:"
echo "<$flex_URL>"
;;
help2man*)
echo "You should only need it if you modified a dependency" \
"of a man page."
echo "You may want to install the GNU Help2man package:"
echo "<$gnu_software_URL/help2man/>"
;;
makeinfo*)
echo "You should only need it if you modified a '.texi' file, or"
echo "any other file indirectly affecting the aspect of the manual."
echo "You might want to install the Texinfo package:"
echo "<$gnu_software_URL/texinfo/>"
echo "The spurious makeinfo call might also be the consequence of"
echo "using a buggy 'make' (AIX, DU, IRIX), in which case you might"
echo "want to install GNU make:"
echo "<$gnu_software_URL/make/>"
;;
*)
echo "You might have modified some files without having the proper"
echo "tools for further handling them. Check the 'README' file, it"
echo "often tells you about the needed prerequisites for installing"
echo "this package. You may also peek at any GNU archive site, in"
echo "case some other package contains this missing '$1' program."
;;
esac
}
give_advice "$1" | sed -e '1s/^/WARNING: /' \
-e '2,$s/^/ /' >&2
# Propagate the correct exit status (expected to be 127 for a program
# not found, 63 for a program that failed due to version mismatch).
exit $st
# Local variables:
# eval: (add-hook 'write-file-hooks 'time-stamp)
# time-stamp-start: "scriptversion="
# time-stamp-format: "%:y-%02m-%02d.%02H"
# time-stamp-time-zone: "UTC"
# time-stamp-end: "; # UTC"
# End:
cfengine-3.12.1/install-sh 0000755 0000000 0000000 00000034137 13377750516 015404 0 ustar 00root root 0000000 0000000 #!/bin/sh
# install - install a program, script, or datafile
scriptversion=2011-11-20.07; # UTC
# This originates from X11R5 (mit/util/scripts/install.sh), which was
# later released in X11R6 (xc/config/util/install.sh) with the
# following copyright and license.
#
# Copyright (C) 1994 X Consortium
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to
# deal in the Software without restriction, including without limitation the
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
# sell copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC-
# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
# Except as contained in this notice, the name of the X Consortium shall not
# be used in advertising or otherwise to promote the sale, use or other deal-
# ings in this Software without prior written authorization from the X Consor-
# tium.
#
#
# FSF changes to this file are in the public domain.
#
# 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.
nl='
'
IFS=" "" $nl"
# set DOITPROG to echo to test this script
# Don't use :- since 4.3BSD and earlier shells don't like it.
doit=${DOITPROG-}
if test -z "$doit"; then
doit_exec=exec
else
doit_exec=$doit
fi
# Put in absolute file names if you don't have them in your path;
# or use environment vars.
chgrpprog=${CHGRPPROG-chgrp}
chmodprog=${CHMODPROG-chmod}
chownprog=${CHOWNPROG-chown}
cmpprog=${CMPPROG-cmp}
cpprog=${CPPROG-cp}
mkdirprog=${MKDIRPROG-mkdir}
mvprog=${MVPROG-mv}
rmprog=${RMPROG-rm}
stripprog=${STRIPPROG-strip}
posix_glob='?'
initialize_posix_glob='
test "$posix_glob" != "?" || {
if (set -f) 2>/dev/null; then
posix_glob=
else
posix_glob=:
fi
}
'
posix_mkdir=
# Desired mode of installed file.
mode=0755
chgrpcmd=
chmodcmd=$chmodprog
chowncmd=
mvcmd=$mvprog
rmcmd="$rmprog -f"
stripcmd=
src=
dst=
dir_arg=
dst_arg=
copy_on_change=false
no_target_directory=
usage="\
Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE
or: $0 [OPTION]... SRCFILES... DIRECTORY
or: $0 [OPTION]... -t DIRECTORY SRCFILES...
or: $0 [OPTION]... -d DIRECTORIES...
In the 1st form, copy SRCFILE to DSTFILE.
In the 2nd and 3rd, copy all SRCFILES to DIRECTORY.
In the 4th, create DIRECTORIES.
Options:
--help display this help and exit.
--version display version info and exit.
-c (ignored)
-C install only if different (preserve the last data modification time)
-d create directories instead of installing files.
-g GROUP $chgrpprog installed files to GROUP.
-m MODE $chmodprog installed files to MODE.
-o USER $chownprog installed files to USER.
-s $stripprog installed files.
-t DIRECTORY install into DIRECTORY.
-T report an error if DSTFILE is a directory.
Environment variables override the default commands:
CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG
RMPROG STRIPPROG
"
while test $# -ne 0; do
case $1 in
-c) ;;
-C) copy_on_change=true;;
-d) dir_arg=true;;
-g) chgrpcmd="$chgrpprog $2"
shift;;
--help) echo "$usage"; exit $?;;
-m) mode=$2
case $mode in
*' '* | *' '* | *'
'* | *'*'* | *'?'* | *'['*)
echo "$0: invalid mode: $mode" >&2
exit 1;;
esac
shift;;
-o) chowncmd="$chownprog $2"
shift;;
-s) stripcmd=$stripprog;;
-t) dst_arg=$2
# Protect names problematic for 'test' and other utilities.
case $dst_arg in
-* | [=\(\)!]) dst_arg=./$dst_arg;;
esac
shift;;
-T) no_target_directory=true;;
--version) echo "$0 $scriptversion"; exit $?;;
--) shift
break;;
-*) echo "$0: invalid option: $1" >&2
exit 1;;
*) break;;
esac
shift
done
if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then
# When -d is used, all remaining arguments are directories to create.
# When -t is used, the destination is already specified.
# Otherwise, the last argument is the destination. Remove it from $@.
for arg
do
if test -n "$dst_arg"; then
# $@ is not empty: it contains at least $arg.
set fnord "$@" "$dst_arg"
shift # fnord
fi
shift # arg
dst_arg=$arg
# Protect names problematic for 'test' and other utilities.
case $dst_arg in
-* | [=\(\)!]) dst_arg=./$dst_arg;;
esac
done
fi
if test $# -eq 0; then
if test -z "$dir_arg"; then
echo "$0: no input file specified." >&2
exit 1
fi
# It's OK to call 'install-sh -d' without argument.
# This can happen when creating conditional directories.
exit 0
fi
if test -z "$dir_arg"; then
do_exit='(exit $ret); exit $ret'
trap "ret=129; $do_exit" 1
trap "ret=130; $do_exit" 2
trap "ret=141; $do_exit" 13
trap "ret=143; $do_exit" 15
# Set umask so as not to create temps with too-generous modes.
# However, 'strip' requires both read and write access to temps.
case $mode in
# Optimize common cases.
*644) cp_umask=133;;
*755) cp_umask=22;;
*[0-7])
if test -z "$stripcmd"; then
u_plus_rw=
else
u_plus_rw='% 200'
fi
cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;;
*)
if test -z "$stripcmd"; then
u_plus_rw=
else
u_plus_rw=,u+rw
fi
cp_umask=$mode$u_plus_rw;;
esac
fi
for src
do
# Protect names problematic for 'test' and other utilities.
case $src in
-* | [=\(\)!]) src=./$src;;
esac
if test -n "$dir_arg"; then
dst=$src
dstdir=$dst
test -d "$dstdir"
dstdir_status=$?
else
# Waiting for this to be detected by the "$cpprog $src $dsttmp" command
# might cause directories to be created, which would be especially bad
# if $src (and thus $dsttmp) contains '*'.
if test ! -f "$src" && test ! -d "$src"; then
echo "$0: $src does not exist." >&2
exit 1
fi
if test -z "$dst_arg"; then
echo "$0: no destination specified." >&2
exit 1
fi
dst=$dst_arg
# If destination is a directory, append the input filename; won't work
# if double slashes aren't ignored.
if test -d "$dst"; then
if test -n "$no_target_directory"; then
echo "$0: $dst_arg: Is a directory" >&2
exit 1
fi
dstdir=$dst
dst=$dstdir/`basename "$src"`
dstdir_status=0
else
# Prefer dirname, but fall back on a substitute if dirname fails.
dstdir=`
(dirname "$dst") 2>/dev/null ||
expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
X"$dst" : 'X\(//\)[^/]' \| \
X"$dst" : 'X\(//\)$' \| \
X"$dst" : 'X\(/\)' \| . 2>/dev/null ||
echo X"$dst" |
sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
s//\1/
q
}
/^X\(\/\/\)[^/].*/{
s//\1/
q
}
/^X\(\/\/\)$/{
s//\1/
q
}
/^X\(\/\).*/{
s//\1/
q
}
s/.*/./; q'
`
test -d "$dstdir"
dstdir_status=$?
fi
fi
obsolete_mkdir_used=false
if test $dstdir_status != 0; then
case $posix_mkdir in
'')
# Create intermediate dirs using mode 755 as modified by the umask.
# This is like FreeBSD 'install' as of 1997-10-28.
umask=`umask`
case $stripcmd.$umask in
# Optimize common cases.
*[2367][2367]) mkdir_umask=$umask;;
.*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;;
*[0-7])
mkdir_umask=`expr $umask + 22 \
- $umask % 100 % 40 + $umask % 20 \
- $umask % 10 % 4 + $umask % 2
`;;
*) mkdir_umask=$umask,go-w;;
esac
# With -d, create the new directory with the user-specified mode.
# Otherwise, rely on $mkdir_umask.
if test -n "$dir_arg"; then
mkdir_mode=-m$mode
else
mkdir_mode=
fi
posix_mkdir=false
case $umask in
*[123567][0-7][0-7])
# POSIX mkdir -p sets u+wx bits regardless of umask, which
# is incompatible with FreeBSD 'install' when (umask & 300) != 0.
;;
*)
# $RANDOM is not portable (e.g. dash); use it when possible to
# lower collision chance
tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$
trap 'ret=$?; rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" 2>/dev/null; exit $ret' 0
# As "mkdir -p" follows symlinks and we work in /tmp possibly; so
# create the $tmpdir first (and fail if unsuccessful) to make sure
# that nobody tries to guess the $tmpdir name.
if (umask $mkdir_umask &&
$mkdirprog $mkdir_mode "$tmpdir" &&
exec $mkdirprog $mkdir_mode -p -- "$tmpdir/a/b") >/dev/null 2>&1
then
if test -z "$dir_arg" || {
# Check for POSIX incompatibilities with -m.
# HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or
# other-writable bit of parent directory when it shouldn't.
# FreeBSD 6.1 mkdir -m -p sets mode of existing directory.
test_tmpdir="$tmpdir/a"
ls_ld_tmpdir=`ls -ld "$test_tmpdir"`
case $ls_ld_tmpdir in
d????-?r-*) different_mode=700;;
d????-?--*) different_mode=755;;
*) false;;
esac &&
$mkdirprog -m$different_mode -p -- "$test_tmpdir" && {
ls_ld_tmpdir_1=`ls -ld "$test_tmpdir"`
test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1"
}
}
then posix_mkdir=:
fi
rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir"
else
# Remove any dirs left behind by ancient mkdir implementations.
rmdir ./$mkdir_mode ./-p ./-- "$tmpdir" 2>/dev/null
fi
trap '' 0;;
esac;;
esac
if
$posix_mkdir && (
umask $mkdir_umask &&
$doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir"
)
then :
else
# The umask is ridiculous, or mkdir does not conform to POSIX,
# or it failed possibly due to a race condition. Create the
# directory the slow way, step by step, checking for races as we go.
case $dstdir in
/*) prefix='/';;
[-=\(\)!]*) prefix='./';;
*) prefix='';;
esac
eval "$initialize_posix_glob"
oIFS=$IFS
IFS=/
$posix_glob set -f
set fnord $dstdir
shift
$posix_glob set +f
IFS=$oIFS
prefixes=
for d
do
test X"$d" = X && continue
prefix=$prefix$d
if test -d "$prefix"; then
prefixes=
else
if $posix_mkdir; then
(umask=$mkdir_umask &&
$doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break
# Don't fail if two instances are running concurrently.
test -d "$prefix" || exit 1
else
case $prefix in
*\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;;
*) qprefix=$prefix;;
esac
prefixes="$prefixes '$qprefix'"
fi
fi
prefix=$prefix/
done
if test -n "$prefixes"; then
# Don't fail if two instances are running concurrently.
(umask $mkdir_umask &&
eval "\$doit_exec \$mkdirprog $prefixes") ||
test -d "$dstdir" || exit 1
obsolete_mkdir_used=true
fi
fi
fi
if test -n "$dir_arg"; then
{ test -z "$chowncmd" || $doit $chowncmd "$dst"; } &&
{ test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } &&
{ test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false ||
test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1
else
# Make a couple of temp file names in the proper directory.
dsttmp=$dstdir/_inst.$$_
rmtmp=$dstdir/_rm.$$_
# Trap to clean up those temp files at exit.
trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0
# Copy the file name to the temp name.
(umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") &&
# 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 $cpprog $src $dsttmp" command.
#
{ test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } &&
{ test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } &&
{ test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } &&
{ test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } &&
# If -C, don't bother to copy if it wouldn't change the file.
if $copy_on_change &&
old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` &&
new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` &&
eval "$initialize_posix_glob" &&
$posix_glob set -f &&
set X $old && old=:$2:$4:$5:$6 &&
set X $new && new=:$2:$4:$5:$6 &&
$posix_glob set +f &&
test "$old" = "$new" &&
$cmpprog "$dst" "$dsttmp" >/dev/null 2>&1
then
rm -f "$dsttmp"
else
# Rename the file to the real destination.
$doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null ||
# The rename failed, perhaps because mv can't rename something else
# to itself, or perhaps because mv is so ancient that it does not
# support -f.
{
# Now remove or move aside any old file at destination location.
# We try this two ways since rm can't unlink itself on some
# systems and the destination file might be busy for other
# reasons. In this case, the final cleanup might fail but the new
# file should still install successfully.
{
test ! -f "$dst" ||
$doit $rmcmd -f "$dst" 2>/dev/null ||
{ $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null &&
{ $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; }
} ||
{ echo "$0: cannot unlink or rename $dst" >&2
(exit 1); exit 1
}
} &&
# Now rename the file to the real destination.
$doit $mvcmd "$dsttmp" "$dst"
}
fi || exit 1
trap '' 0
fi
done
# Local variables:
# eval: (add-hook 'write-file-hooks 'time-stamp)
# time-stamp-start: "scriptversion="
# time-stamp-format: "%:y-%02m-%02d.%02H"
# time-stamp-time-zone: "UTC"
# time-stamp-end: "; # UTC"
# End:
cfengine-3.12.1/cf-check/ 0000755 0000000 0000000 00000000000 13377750567 015041 5 ustar 00root root 0000000 0000000 cfengine-3.12.1/cf-check/diagnose.h 0000644 0000000 0000000 00000000141 13377750461 016770 0 ustar 00root root 0000000 0000000 #ifndef __DIAGNOSE_H__
#define __DIAGNOSE_H__
int diagnose_main(int argc, char **argv);
#endif
cfengine-3.12.1/cf-check/Makefile.in 0000644 0000000 0000000 00000066173 13377750516 017115 0 ustar 00root root 0000000 0000000 # Makefile.in generated by automake 1.14.1 from Makefile.am.
# @configure_input@
# Copyright (C) 1994-2013 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
# PARTICULAR PURPOSE.
@SET_MAKE@
VPATH = @srcdir@
am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
am__make_running_with_option = \
case $${target_option-} in \
?) ;; \
*) echo "am__make_running_with_option: internal error: invalid" \
"target option '$${target_option-}' specified" >&2; \
exit 1;; \
esac; \
has_opt=no; \
sane_makeflags=$$MAKEFLAGS; \
if $(am__is_gnu_make); then \
sane_makeflags=$$MFLAGS; \
else \
case $$MAKEFLAGS in \
*\\[\ \ ]*) \
bs=\\; \
sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
| sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
esac; \
fi; \
skip_next=no; \
strip_trailopt () \
{ \
flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
}; \
for flg in $$sane_makeflags; do \
test $$skip_next = yes && { skip_next=no; continue; }; \
case $$flg in \
*=*|--*) continue;; \
-*I) strip_trailopt 'I'; skip_next=yes;; \
-*I?*) strip_trailopt 'I';; \
-*O) strip_trailopt 'O'; skip_next=yes;; \
-*O?*) strip_trailopt 'O';; \
-*l) strip_trailopt 'l'; skip_next=yes;; \
-*l?*) strip_trailopt 'l';; \
-[dEDm]) skip_next=yes;; \
-[JT]) skip_next=yes;; \
esac; \
case $$flg in \
*$$target_option*) has_opt=yes; break;; \
esac; \
done; \
test $$has_opt = yes
am__make_dryrun = (target_option=n; $(am__make_running_with_option))
am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
pkgdatadir = $(datadir)/@PACKAGE@
pkgincludedir = $(includedir)/@PACKAGE@
pkglibdir = $(libdir)/@PACKAGE@
pkglibexecdir = $(libexecdir)/@PACKAGE@
am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
install_sh_DATA = $(install_sh) -c -m 644
install_sh_PROGRAM = $(install_sh) -c
install_sh_SCRIPT = $(install_sh) -c
INSTALL_HEADER = $(INSTALL_DATA)
transform = $(program_transform_name)
NORMAL_INSTALL = :
PRE_INSTALL = :
POST_INSTALL = :
NORMAL_UNINSTALL = :
PRE_UNINSTALL = :
POST_UNINSTALL = :
build_triplet = @build@
host_triplet = @host@
target_triplet = @target@
@BUILTIN_EXTENSIONS_FALSE@bin_PROGRAMS = cf-check$(EXEEXT)
subdir = cf-check
DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
$(top_srcdir)/depcomp
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/m4/acinclude.m4 \
$(top_srcdir)/m4/adl_recursive_eval.m4 \
$(top_srcdir)/m4/cf3_check_proper_func.m4 \
$(top_srcdir)/m4/cf3_path_root_prog.m4 \
$(top_srcdir)/m4/cf3_with_library.m4 \
$(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
$(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
$(top_srcdir)/m4/lt~obsolete.m4 \
$(top_srcdir)/m4/old-autoconf.m4 $(top_srcdir)/m4/snprintf.m4 \
$(top_srcdir)/m4/strndup.m4 $(top_srcdir)/m4/tar.m4 \
$(top_srcdir)/m4/cf3_gcc_flags.m4 \
$(top_srcdir)/m4/cf3_platforms.m4 $(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4)
mkinstalldirs = $(install_sh) -d
CONFIG_HEADER = $(top_builddir)/libutils/config.h
CONFIG_CLEAN_FILES =
CONFIG_CLEAN_VPATH_FILES =
LTLIBRARIES = $(noinst_LTLIBRARIES)
am__DEPENDENCIES_1 =
libcf_check_la_DEPENDENCIES = ../libutils/libutils.la \
$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
am_libcf_check_la_OBJECTS = lmdump.lo diagnose.lo cf-check.lo
libcf_check_la_OBJECTS = $(am_libcf_check_la_OBJECTS)
AM_V_lt = $(am__v_lt_@AM_V@)
am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
am__v_lt_0 = --silent
am__v_lt_1 =
am__installdirs = "$(DESTDIR)$(bindir)"
PROGRAMS = $(bin_PROGRAMS)
cf_check_SOURCES = cf-check.c
cf_check_OBJECTS = cf_check-cf-check.$(OBJEXT)
@BUILTIN_EXTENSIONS_FALSE@cf_check_DEPENDENCIES = libcf-check.la
cf_check_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=link $(CCLD) $(cf_check_CFLAGS) \
$(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
AM_V_P = $(am__v_P_@AM_V@)
am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
am__v_P_0 = false
am__v_P_1 = :
AM_V_GEN = $(am__v_GEN_@AM_V@)
am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
am__v_GEN_0 = @echo " GEN " $@;
am__v_GEN_1 =
AM_V_at = $(am__v_at_@AM_V@)
am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
am__v_at_0 = @
am__v_at_1 =
DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/libutils
depcomp = $(SHELL) $(top_srcdir)/depcomp
am__depfiles_maybe = depfiles
am__mv = mv -f
COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
$(AM_CFLAGS) $(CFLAGS)
AM_V_CC = $(am__v_CC_@AM_V@)
am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
am__v_CC_0 = @echo " CC " $@;
am__v_CC_1 =
CCLD = $(CC)
LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
$(AM_LDFLAGS) $(LDFLAGS) -o $@
AM_V_CCLD = $(am__v_CCLD_@AM_V@)
am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
am__v_CCLD_0 = @echo " CCLD " $@;
am__v_CCLD_1 =
SOURCES = $(libcf_check_la_SOURCES) cf-check.c
DIST_SOURCES = $(libcf_check_la_SOURCES) cf-check.c
am__can_run_installinfo = \
case $$AM_UPDATE_INFO_DIR in \
n|no|NO) false;; \
*) (install-info --version) >/dev/null 2>&1;; \
esac
am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
# Read a list of newline-separated strings from the standard input,
# and print each of them once, without duplicates. Input order is
# *not* preserved.
am__uniquify_input = $(AWK) '\
BEGIN { nonempty = 0; } \
{ items[$$0] = 1; nonempty = 1; } \
END { if (nonempty) { for (i in items) print i; }; } \
'
# Make sure the list of sources is unique. This is necessary because,
# e.g., the same source file might be shared among _SOURCES variables
# for different programs/libraries.
am__define_uniq_tagged_files = \
list='$(am__tagged_files)'; \
unique=`for i in $$list; do \
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
done | $(am__uniquify_input)`
ETAGS = etags
CTAGS = ctags
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
ACLOCAL = @ACLOCAL@
AMTAR = @AMTAR@
AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
AR = @AR@
AUTOCONF = @AUTOCONF@
AUTOHEADER = @AUTOHEADER@
AUTOMAKE = @AUTOMAKE@
AWK = @AWK@
CC = @CC@
CCDEPMODE = @CCDEPMODE@
CFLAGS = @CFLAGS@
CORE_CFLAGS = @CORE_CFLAGS@
CORE_CPPFLAGS = @CORE_CPPFLAGS@
CORE_LDFLAGS = @CORE_LDFLAGS@
CORE_LIBS = @CORE_LIBS@
CPP = @CPP@
CPPFLAGS = @CPPFLAGS@
CYGPATH_W = @CYGPATH_W@
DEFS = @DEFS@
DEPDIR = @DEPDIR@
DLLTOOL = @DLLTOOL@
DSYMUTIL = @DSYMUTIL@
DUMPBIN = @DUMPBIN@
ECHO_C = @ECHO_C@
ECHO_N = @ECHO_N@
ECHO_T = @ECHO_T@
EGREP = @EGREP@
EXEEXT = @EXEEXT@
FGREP = @FGREP@
GETCONF = @GETCONF@
GETLOADAVG_LIBS = @GETLOADAVG_LIBS@
GREP = @GREP@
HOSTNAME = @HOSTNAME@
INIT_D_PATH = @INIT_D_PATH@
INSTALL = @INSTALL@
INSTALL_DATA = @INSTALL_DATA@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_SCRIPT = @INSTALL_SCRIPT@
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
KMEM_GROUP = @KMEM_GROUP@
LCOV = @LCOV@
LCOV_GENHTML = @LCOV_GENHTML@
LD = @LD@
LDFLAGS = @LDFLAGS@
LEX = @LEX@
LEXLIB = @LEXLIB@
LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
LIBACL_CFLAGS = @LIBACL_CFLAGS@
LIBACL_CPPFLAGS = @LIBACL_CPPFLAGS@
LIBACL_LDFLAGS = @LIBACL_LDFLAGS@
LIBACL_LIBS = @LIBACL_LIBS@
LIBACL_PATH = @LIBACL_PATH@
LIBCURL_CFLAGS = @LIBCURL_CFLAGS@
LIBCURL_CPPFLAGS = @LIBCURL_CPPFLAGS@
LIBCURL_LDFLAGS = @LIBCURL_LDFLAGS@
LIBCURL_LIBS = @LIBCURL_LIBS@
LIBCURL_PATH = @LIBCURL_PATH@
LIBOBJS = @LIBOBJS@
LIBS = @LIBS@
LIBTOOL = @LIBTOOL@
LIBVIRT_CFLAGS = @LIBVIRT_CFLAGS@
LIBVIRT_CPPFLAGS = @LIBVIRT_CPPFLAGS@
LIBVIRT_LDFLAGS = @LIBVIRT_LDFLAGS@
LIBVIRT_LIBS = @LIBVIRT_LIBS@
LIBVIRT_PATH = @LIBVIRT_PATH@
LIBXML2_CFLAGS = @LIBXML2_CFLAGS@
LIBXML2_CPPFLAGS = @LIBXML2_CPPFLAGS@
LIBXML2_LDFLAGS = @LIBXML2_LDFLAGS@
LIBXML2_LIBS = @LIBXML2_LIBS@
LIBXML2_PATH = @LIBXML2_PATH@
LIBYAML_CFLAGS = @LIBYAML_CFLAGS@
LIBYAML_CPPFLAGS = @LIBYAML_CPPFLAGS@
LIBYAML_LDFLAGS = @LIBYAML_LDFLAGS@
LIBYAML_LIBS = @LIBYAML_LIBS@
LIBYAML_PATH = @LIBYAML_PATH@
LIPO = @LIPO@
LMDB_CFLAGS = @LMDB_CFLAGS@
LMDB_CPPFLAGS = @LMDB_CPPFLAGS@
LMDB_LDFLAGS = @LMDB_LDFLAGS@
LMDB_LIBS = @LMDB_LIBS@
LMDB_PATH = @LMDB_PATH@
LN_S = @LN_S@
LTLIBOBJS = @LTLIBOBJS@
MAINT = @MAINT@
MAKEINFO = @MAKEINFO@
MANIFEST_TOOL = @MANIFEST_TOOL@
MKDIR_P = @MKDIR_P@
MYSQL_CFLAGS = @MYSQL_CFLAGS@
MYSQL_CPPFLAGS = @MYSQL_CPPFLAGS@
MYSQL_LDFLAGS = @MYSQL_LDFLAGS@
MYSQL_LIBS = @MYSQL_LIBS@
MYSQL_PATH = @MYSQL_PATH@
NEED_SETGID = @NEED_SETGID@
NM = @NM@
NMEDIT = @NMEDIT@
OBJDUMP = @OBJDUMP@
OBJEXT = @OBJEXT@
OPENSSL_CFLAGS = @OPENSSL_CFLAGS@
OPENSSL_CPPFLAGS = @OPENSSL_CPPFLAGS@
OPENSSL_LDFLAGS = @OPENSSL_LDFLAGS@
OPENSSL_LIBS = @OPENSSL_LIBS@
OPENSSL_PATH = @OPENSSL_PATH@
OS_ENVIRONMENT_PATH = @OS_ENVIRONMENT_PATH@
OTOOL = @OTOOL@
OTOOL64 = @OTOOL64@
PACKAGE = @PACKAGE@
PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
PACKAGE_NAME = @PACKAGE_NAME@
PACKAGE_STRING = @PACKAGE_STRING@
PACKAGE_TARNAME = @PACKAGE_TARNAME@
PACKAGE_URL = @PACKAGE_URL@
PACKAGE_VERSION = @PACKAGE_VERSION@
PAM_CFLAGS = @PAM_CFLAGS@
PAM_CPPFLAGS = @PAM_CPPFLAGS@
PAM_LDFLAGS = @PAM_LDFLAGS@
PAM_LIBS = @PAM_LIBS@
PAM_PATH = @PAM_PATH@
PATH_SEPARATOR = @PATH_SEPARATOR@
PCRE_CFLAGS = @PCRE_CFLAGS@
PCRE_CPPFLAGS = @PCRE_CPPFLAGS@
PCRE_LDFLAGS = @PCRE_LDFLAGS@
PCRE_LIBS = @PCRE_LIBS@
PCRE_PATH = @PCRE_PATH@
PERL = @PERL@
POSTGRESQL_CFLAGS = @POSTGRESQL_CFLAGS@
POSTGRESQL_CPPFLAGS = @POSTGRESQL_CPPFLAGS@
POSTGRESQL_LDFLAGS = @POSTGRESQL_LDFLAGS@
POSTGRESQL_LIBS = @POSTGRESQL_LIBS@
POSTGRESQL_PATH = @POSTGRESQL_PATH@
PTHREAD_CC = @PTHREAD_CC@
PTHREAD_CFLAGS = @PTHREAD_CFLAGS@
PTHREAD_LIBS = @PTHREAD_LIBS@
QDBM_CFLAGS = @QDBM_CFLAGS@
QDBM_CPPFLAGS = @QDBM_CPPFLAGS@
QDBM_LDFLAGS = @QDBM_LDFLAGS@
QDBM_LIBS = @QDBM_LIBS@
QDBM_PATH = @QDBM_PATH@
RANLIB = @RANLIB@
SED = @SED@
SET_MAKE = @SET_MAKE@
SHELL = @SHELL@
STRIP = @STRIP@
SYSTEMD_SERVICE_PATH = @SYSTEMD_SERVICE_PATH@
TOKYOCABINET_CFLAGS = @TOKYOCABINET_CFLAGS@
TOKYOCABINET_CPPFLAGS = @TOKYOCABINET_CPPFLAGS@
TOKYOCABINET_LDFLAGS = @TOKYOCABINET_LDFLAGS@
TOKYOCABINET_LIBS = @TOKYOCABINET_LIBS@
TOKYOCABINET_PATH = @TOKYOCABINET_PATH@
VERSION = @VERSION@
YACC = @YACC@
YFLAGS = @YFLAGS@
abs_builddir = @abs_builddir@
abs_srcdir = @abs_srcdir@
abs_top_builddir = @abs_top_builddir@
abs_top_srcdir = @abs_top_srcdir@
ac_ct_AR = @ac_ct_AR@
ac_ct_CC = @ac_ct_CC@
ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
acx_pthread_config = @acx_pthread_config@
am__include = @am__include@
am__leading_dot = @am__leading_dot@
am__quote = @am__quote@
am__tar = @am__tar@
am__untar = @am__untar@
bindir = @bindir@
build = @build@
build_alias = @build_alias@
build_cpu = @build_cpu@
build_os = @build_os@
build_vendor = @build_vendor@
builddir = @builddir@
datadir = @datadir@
datarootdir = @datarootdir@
docdir = @docdir@
dvidir = @dvidir@
enable_builtin_extensions = @enable_builtin_extensions@
exec_prefix = @exec_prefix@
host = @host@
host_alias = @host_alias@
host_cpu = @host_cpu@
host_os = @host_os@
host_vendor = @host_vendor@
htmldir = @htmldir@
hw_cv_func_ctime_proper = @hw_cv_func_ctime_proper@
hw_cv_func_mkdir_proper = @hw_cv_func_mkdir_proper@
hw_cv_func_rename_proper = @hw_cv_func_rename_proper@
hw_cv_func_stat_proper = @hw_cv_func_stat_proper@
includedir = @includedir@
infodir = @infodir@
inputdir = @inputdir@
install_sh = @install_sh@
libdir = @libdir@
libexecdir = @libexecdir@
localedir = @localedir@
localstatedir = @localstatedir@
logdir = @logdir@
mandir = @mandir@
masterdir = @masterdir@
mkdir_p = @mkdir_p@
oldincludedir = @oldincludedir@
pdfdir = @pdfdir@
piddir = @piddir@
prefix = @prefix@
program_transform_name = @program_transform_name@
projlibdir = @projlibdir@
psdir = @psdir@
sbindir = @sbindir@
sharedstatedir = @sharedstatedir@
srcdir = @srcdir@
statedir = @statedir@
sysconfdir = @sysconfdir@
target = @target@
target_alias = @target_alias@
target_cpu = @target_cpu@
target_os = @target_os@
target_vendor = @target_vendor@
top_build_prefix = @top_build_prefix@
top_builddir = @top_builddir@
top_srcdir = @top_srcdir@
workdir = @workdir@
#
# Copyright 2018 Northern.tech AS
#
# This file is part of CFEngine 3 - written and maintained by Northern.tech AS.
#
# 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; version 3.
#
# 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, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
#
# To the extent this program is licensed as part of the Enterprise
# versions of CFEngine, the applicable Commercial Open Source License
# (COSL) may apply to this file if you as a licensee so wish it. See
# included file COSL.txt.
#
noinst_LTLIBRARIES = libcf-check.la
AM_CPPFLAGS = -I$(srcdir)/../libutils \
$(LMDB_CPPFLAGS)
AM_CFLAGS = \
$(LMDB_CFLAGS) \
$(PTHREAD_CFLAGS)
AM_LDFLAGS = \
$(LMDB_LDFLAGS)
libcf_check_la_LIBADD = ../libutils/libutils.la \
$(LMDB_LIBS) \
$(PTHREAD_LIBS)
libcf_check_la_SOURCES = \
lmdump.c lmdump.h \
diagnose.c diagnose.h \
cf-check.c
@BUILTIN_EXTENSIONS_FALSE@cf_check_CFLAGS = $(AM_CFLAGS)
@BUILTIN_EXTENSIONS_FALSE@cf_check_LDADD = libcf-check.la
CLEANFILES = *.gcno *.gcda
#
# Some basic clean ups
#
MOSTLYCLEANFILES = *~ *.orig *.rej
all: all-am
.SUFFIXES:
.SUFFIXES: .c .lo .o .obj
$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
@for dep in $?; do \
case '$(am__configure_deps)' in \
*$$dep*) \
( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
&& { if test -f $@; then exit 0; else break; fi; }; \
exit 1;; \
esac; \
done; \
echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu cf-check/Makefile'; \
$(am__cd) $(top_srcdir) && \
$(AUTOMAKE) --gnu cf-check/Makefile
.PRECIOUS: Makefile
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
@case '$?' in \
*config.status*) \
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
*) \
echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
esac;
$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(am__aclocal_m4_deps):
clean-noinstLTLIBRARIES:
-test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
@list='$(noinst_LTLIBRARIES)'; \
locs=`for p in $$list; do echo $$p; done | \
sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
sort -u`; \
test -z "$$locs" || { \
echo rm -f $${locs}; \
rm -f $${locs}; \
}
libcf-check.la: $(libcf_check_la_OBJECTS) $(libcf_check_la_DEPENDENCIES) $(EXTRA_libcf_check_la_DEPENDENCIES)
$(AM_V_CCLD)$(LINK) $(libcf_check_la_OBJECTS) $(libcf_check_la_LIBADD) $(LIBS)
install-binPROGRAMS: $(bin_PROGRAMS)
@$(NORMAL_INSTALL)
@list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \
if test -n "$$list"; then \
echo " $(MKDIR_P) '$(DESTDIR)$(bindir)'"; \
$(MKDIR_P) "$(DESTDIR)$(bindir)" || exit 1; \
fi; \
for p in $$list; do echo "$$p $$p"; done | \
sed 's/$(EXEEXT)$$//' | \
while read p p1; do if test -f $$p \
|| test -f $$p1 \
; then echo "$$p"; echo "$$p"; else :; fi; \
done | \
sed -e 'p;s,.*/,,;n;h' \
-e 's|.*|.|' \
-e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \
sed 'N;N;N;s,\n, ,g' | \
$(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \
{ d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \
if ($$2 == $$4) files[d] = files[d] " " $$1; \
else { print "f", $$3 "/" $$4, $$1; } } \
END { for (d in files) print "f", d, files[d] }' | \
while read type dir files; do \
if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \
test -z "$$files" || { \
echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \
$(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \
} \
; done
uninstall-binPROGRAMS:
@$(NORMAL_UNINSTALL)
@list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \
files=`for p in $$list; do echo "$$p"; done | \
sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \
-e 's/$$/$(EXEEXT)/' \
`; \
test -n "$$list" || exit 0; \
echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \
cd "$(DESTDIR)$(bindir)" && rm -f $$files
clean-binPROGRAMS:
@list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \
echo " rm -f" $$list; \
rm -f $$list || exit $$?; \
test -n "$(EXEEXT)" || exit 0; \
list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
echo " rm -f" $$list; \
rm -f $$list
cf-check$(EXEEXT): $(cf_check_OBJECTS) $(cf_check_DEPENDENCIES) $(EXTRA_cf_check_DEPENDENCIES)
@rm -f cf-check$(EXEEXT)
$(AM_V_CCLD)$(cf_check_LINK) $(cf_check_OBJECTS) $(cf_check_LDADD) $(LIBS)
mostlyclean-compile:
-rm -f *.$(OBJEXT)
distclean-compile:
-rm -f *.tab.c
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cf-check.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cf_check-cf-check.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/diagnose.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lmdump.Plo@am__quote@
.c.o:
@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
.c.obj:
@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
.c.lo:
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
cf_check-cf-check.o: cf-check.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(cf_check_CFLAGS) $(CFLAGS) -MT cf_check-cf-check.o -MD -MP -MF $(DEPDIR)/cf_check-cf-check.Tpo -c -o cf_check-cf-check.o `test -f 'cf-check.c' || echo '$(srcdir)/'`cf-check.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/cf_check-cf-check.Tpo $(DEPDIR)/cf_check-cf-check.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cf-check.c' object='cf_check-cf-check.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(cf_check_CFLAGS) $(CFLAGS) -c -o cf_check-cf-check.o `test -f 'cf-check.c' || echo '$(srcdir)/'`cf-check.c
cf_check-cf-check.obj: cf-check.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(cf_check_CFLAGS) $(CFLAGS) -MT cf_check-cf-check.obj -MD -MP -MF $(DEPDIR)/cf_check-cf-check.Tpo -c -o cf_check-cf-check.obj `if test -f 'cf-check.c'; then $(CYGPATH_W) 'cf-check.c'; else $(CYGPATH_W) '$(srcdir)/cf-check.c'; fi`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/cf_check-cf-check.Tpo $(DEPDIR)/cf_check-cf-check.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cf-check.c' object='cf_check-cf-check.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(cf_check_CFLAGS) $(CFLAGS) -c -o cf_check-cf-check.obj `if test -f 'cf-check.c'; then $(CYGPATH_W) 'cf-check.c'; else $(CYGPATH_W) '$(srcdir)/cf-check.c'; fi`
mostlyclean-libtool:
-rm -f *.lo
clean-libtool:
-rm -rf .libs _libs
ID: $(am__tagged_files)
$(am__define_uniq_tagged_files); mkid -fID $$unique
tags: tags-am
TAGS: tags
tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
set x; \
here=`pwd`; \
$(am__define_uniq_tagged_files); \
shift; \
if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
test -n "$$unique" || unique=$$empty_fix; \
if test $$# -gt 0; then \
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
"$$@" $$unique; \
else \
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
$$unique; \
fi; \
fi
ctags: ctags-am
CTAGS: ctags
ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
$(am__define_uniq_tagged_files); \
test -z "$(CTAGS_ARGS)$$unique" \
|| $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
$$unique
GTAGS:
here=`$(am__cd) $(top_builddir) && pwd` \
&& $(am__cd) $(top_srcdir) \
&& gtags -i $(GTAGS_ARGS) "$$here"
cscopelist: cscopelist-am
cscopelist-am: $(am__tagged_files)
list='$(am__tagged_files)'; \
case "$(srcdir)" in \
[\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
*) sdir=$(subdir)/$(srcdir) ;; \
esac; \
for i in $$list; do \
if test -f "$$i"; then \
echo "$(subdir)/$$i"; \
else \
echo "$$sdir/$$i"; \
fi; \
done >> $(top_builddir)/cscope.files
distclean-tags:
-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
distdir: $(DISTFILES)
@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
list='$(DISTFILES)'; \
dist_files=`for file in $$list; do echo $$file; done | \
sed -e "s|^$$srcdirstrip/||;t" \
-e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
case $$dist_files in \
*/*) $(MKDIR_P) `echo "$$dist_files" | \
sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
sort -u` ;; \
esac; \
for file in $$dist_files; do \
if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
if test -d $$d/$$file; then \
dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
if test -d "$(distdir)/$$file"; then \
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
fi; \
if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
fi; \
cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
else \
test -f "$(distdir)/$$file" \
|| cp -p $$d/$$file "$(distdir)/$$file" \
|| exit 1; \
fi; \
done
check-am: all-am
check: check-am
all-am: Makefile $(LTLIBRARIES) $(PROGRAMS)
installdirs:
for dir in "$(DESTDIR)$(bindir)"; do \
test -z "$$dir" || $(MKDIR_P) "$$dir"; \
done
install: install-am
install-exec: install-exec-am
install-data: install-data-am
uninstall: uninstall-am
install-am: all-am
@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
installcheck: installcheck-am
install-strip:
if test -z '$(STRIP)'; then \
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
install; \
else \
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
"INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
fi
mostlyclean-generic:
-test -z "$(MOSTLYCLEANFILES)" || rm -f $(MOSTLYCLEANFILES)
clean-generic:
-test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
distclean-generic:
-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
maintainer-clean-generic:
@echo "This command is intended for maintainers to use"
@echo "it deletes files that may require special tools to rebuild."
clean: clean-am
clean-am: clean-binPROGRAMS clean-generic clean-libtool \
clean-noinstLTLIBRARIES mostlyclean-am
distclean: distclean-am
-rm -rf ./$(DEPDIR)
-rm -f Makefile
distclean-am: clean-am distclean-compile distclean-generic \
distclean-tags
dvi: dvi-am
dvi-am:
html: html-am
html-am:
info: info-am
info-am:
install-data-am:
install-dvi: install-dvi-am
install-dvi-am:
install-exec-am: install-binPROGRAMS
install-html: install-html-am
install-html-am:
install-info: install-info-am
install-info-am:
install-man:
install-pdf: install-pdf-am
install-pdf-am:
install-ps: install-ps-am
install-ps-am:
installcheck-am:
maintainer-clean: maintainer-clean-am
-rm -rf ./$(DEPDIR)
-rm -f Makefile
maintainer-clean-am: distclean-am maintainer-clean-generic
mostlyclean: mostlyclean-am
mostlyclean-am: mostlyclean-compile mostlyclean-generic \
mostlyclean-libtool
pdf: pdf-am
pdf-am:
ps: ps-am
ps-am:
uninstall-am: uninstall-binPROGRAMS
.MAKE: install-am install-strip
.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean \
clean-binPROGRAMS clean-generic clean-libtool \
clean-noinstLTLIBRARIES cscopelist-am ctags ctags-am distclean \
distclean-compile distclean-generic distclean-libtool \
distclean-tags distdir dvi dvi-am html html-am info info-am \
install install-am install-binPROGRAMS install-data \
install-data-am install-dvi install-dvi-am install-exec \
install-exec-am install-html install-html-am install-info \
install-info-am install-man install-pdf install-pdf-am \
install-ps install-ps-am install-strip installcheck \
installcheck-am installdirs maintainer-clean \
maintainer-clean-generic mostlyclean mostlyclean-compile \
mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
tags tags-am uninstall uninstall-am uninstall-binPROGRAMS
@BUILTIN_EXTENSIONS_FALSE@ # Workaround for automake madness (try removing it if you want to know why).
@BUILTIN_EXTENSIONS_FALSE@ # Build both a libcf-check.la library, and a cf-check executable
# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.
.NOEXPORT:
cfengine-3.12.1/cf-check/lmdump.h 0000644 0000000 0000000 00000000533 13377750461 016502 0 ustar 00root root 0000000 0000000 #ifndef __LMDUMP_H__
#define __LMDUMP_H__
#include
typedef enum
{
LMDUMP_KEYS_ASCII,
LMDUMP_VALUES_ASCII,
LMDUMP_VALUES_HEX,
LMDUMP_SIZES,
LMDUMP_UNKNOWN
} lmdump_mode;
lmdump_mode lmdump_char_to_mode(char mode);
int lmdump(lmdump_mode mode, const char *file);
int lmdump_main(int argc, char * argv[]);
#endif
cfengine-3.12.1/cf-check/diagnose.c 0000644 0000000 0000000 00000024617 13377750461 017001 0 ustar 00root root 0000000 0000000 #include
#include
#if defined (__MINGW32__)
int diagnose_main(int argc, char **argv)
{
printf("diagnose not supported on Windows\n");
return 1;
}
#elif ! defined (LMDB)
int diagnose_main(int argc, char **argv)
{
printf("diagnose only implemented for LMDB.\n");
return 1;
}
#else
#include
#include
#include
#include
#include
#define CF_CHECK_RUN_CODES(macro) \
macro(OK) \
macro(SIGNAL_HANGUP) \
macro(SIGNAL_INTERRUPT) \
macro(SIGNAL_QUIT) \
macro(SIGNAL_ILLEGAL_INSTRUCTION) \
macro(SIGNAL_TRACE_TRAP) \
macro(SIGNAL_ABORT) \
macro(SIGNAL_EMULATE_INSTRUCTION) \
macro(SIGNAL_FLOATING_POINT_EXCEPTION) \
macro(SIGNAL_KILL) \
macro(SIGNAL_BUS_ERROR) \
macro(SIGNAL_SEGFAULT) \
macro(SIGNAL_NON_EXISTENT_SYSCALL) \
macro(SIGNAL_INVALID_PIPE) \
macro(SIGNAL_TIMER_EXPIRED) \
macro(SIGNAL_TERMINATE) \
macro(SIGNAL_URGENT_SOCKET_CONDITION) \
macro(SIGNAL_STOP) \
macro(SIGNAL_KEYBOARD_STOP) \
macro(SIGNAL_CONTINUE) \
macro(SIGNAL_CHILD_STATUS_CHANGE) \
macro(SIGNAL_BACKGROUND_READ_ATTEMPT) \
macro(SIGNAL_BACKGROUND_WRITE_ATTEMPT) \
macro(SIGNAL_IO_POSSIBLE_ON_DESCRIPTOR) \
macro(SIGNAL_CPU_TIME_EXCEEDED) \
macro(SIGNAL_FILE_SIZE_EXCEEDED) \
macro(SIGNAL_VIRTUAL_TIME_ALARM) \
macro(SIGNAL_PROFILING_TIMER_ALARM) \
macro(SIGNAL_WINDOW_SIZE_CHANGE) \
macro(SIGNAL_STATUS_REQUEST) \
macro(SIGNAL_OTHER) \
macro(LMDB_KEY_EXISTS) \
macro(LMDB_KEY_NOT_FOUND) \
macro(LMDB_PAGE_NOT_FOUND) \
macro(LMDB_CORRUPT_PAGE) \
macro(LMDB_PANIC_FATAL_ERROR) \
macro(LMDB_VERSION_MISMATCH) \
macro(LMDB_INVALID_DATABASE) \
macro(LMDB_MAP_FULL) \
macro(LMDB_DBS_FULL) \
macro(LMDB_READERS_FULL) \
macro(LMDB_TLS_KEYS_FULL) \
macro(LMDB_TRANSACTION_FULL) \
macro(LMDB_CURSOR_STACK_TOO_DEEP) \
macro(LMDB_PAGE_FULL) \
macro(LMDB_MAP_RESIZE_BEYOND_SIZE) \
macro(LMDB_INCOMPATIBLE_OPERATION) \
macro(LMDB_INVALID_REUSE_OF_READER_LOCKTABLE_SLOT) \
macro(LMDB_BAD_OR_INVALID_TRANSACTION) \
macro(LMDB_WRONG_KEY_OR_VALUE_SIZE) \
macro(LMDB_BAD_DBI) \
macro(LMDUMP_UNKNOWN_ERROR) \
macro(PID_ERROR) \
macro(PERMISSION_ERROR) \
macro(DOES_NOT_EXIST) \
macro(UNKNOWN)
#define CF_CHECK_MAX CF_CHECK_UNKNOWN
#define CF_CHECK_CREATE_ENUM(name) \
CF_CHECK_##name,
#define CF_CHECK_CREATE_STRING(name) \
#name,
typedef enum {
CF_CHECK_RUN_CODES(CF_CHECK_CREATE_ENUM)
} CFCheckCode;
static const char *CF_CHECK_STR[] = {
CF_CHECK_RUN_CODES(CF_CHECK_CREATE_STRING)
};
static bool code_is_errno(int r)
{
return (r > CF_CHECK_MAX);
}
// Better strerror, returns NULL if it doesn't know.
static const char *strerror_or_null(int r)
{
const char *strerror_string = strerror(r);
if (strerror_string == NULL)
{
return NULL;
}
const char *unknown = "Unknown error";
if (strncmp(strerror_string, unknown, strlen(unknown)) == 0)
{
return NULL;
}
return strerror_string;
}
static int errno_to_code(int r)
{
assert(r != 0);
return r + CF_CHECK_MAX;
}
static int code_to_errno(int r)
{
assert(code_is_errno(r));
return r - CF_CHECK_MAX;
}
static const char *CF_CHECK_STRING(int code)
{
static char unknown[1024];
if (code <= 0 || code < CF_CHECK_MAX)
{
return CF_CHECK_STR[code];
}
else if (code_is_errno(code)) // code > CF_CHECK_MAX
{
code = code_to_errno(code);
const char *str = strerror_or_null(code);
if (str == NULL)
{
str = "Unknown";
}
snprintf(unknown, sizeof(unknown), "SYSTEM_ERROR %d - %s", code, str);
return unknown;
}
return CF_CHECK_STR[CF_CHECK_UNKNOWN];
}
static int signal_to_code(int sig)
{
switch (sig) {
case SIGHUP:
return CF_CHECK_SIGNAL_HANGUP;
case SIGINT:
return CF_CHECK_SIGNAL_INTERRUPT;
case SIGQUIT:
return CF_CHECK_SIGNAL_QUIT;
case SIGILL:
return CF_CHECK_SIGNAL_ILLEGAL_INSTRUCTION;
case SIGTRAP:
return CF_CHECK_SIGNAL_TRACE_TRAP;
case SIGABRT:
return CF_CHECK_SIGNAL_ABORT;
case SIGFPE:
return CF_CHECK_SIGNAL_FLOATING_POINT_EXCEPTION;
case SIGKILL:
return CF_CHECK_SIGNAL_KILL;
case SIGBUS:
return CF_CHECK_SIGNAL_BUS_ERROR;
case SIGSEGV:
return CF_CHECK_SIGNAL_SEGFAULT;
case SIGSYS:
return CF_CHECK_SIGNAL_NON_EXISTENT_SYSCALL;
case SIGPIPE:
return CF_CHECK_SIGNAL_INVALID_PIPE;
case SIGALRM:
return CF_CHECK_SIGNAL_TIMER_EXPIRED;
case SIGTERM:
return CF_CHECK_SIGNAL_TERMINATE;
case SIGURG:
return CF_CHECK_SIGNAL_URGENT_SOCKET_CONDITION;
case SIGSTOP:
return CF_CHECK_SIGNAL_STOP;
case SIGTSTP:
return CF_CHECK_SIGNAL_KEYBOARD_STOP;
case SIGCONT:
return CF_CHECK_SIGNAL_CONTINUE;
case SIGCHLD:
return CF_CHECK_SIGNAL_CHILD_STATUS_CHANGE;
case SIGTTIN:
return CF_CHECK_SIGNAL_BACKGROUND_READ_ATTEMPT;
case SIGTTOU:
return CF_CHECK_SIGNAL_BACKGROUND_WRITE_ATTEMPT;
case SIGIO:
return CF_CHECK_SIGNAL_IO_POSSIBLE_ON_DESCRIPTOR;
case SIGXCPU:
return CF_CHECK_SIGNAL_CPU_TIME_EXCEEDED;
case SIGXFSZ:
return CF_CHECK_SIGNAL_FILE_SIZE_EXCEEDED;
case SIGVTALRM:
return CF_CHECK_SIGNAL_VIRTUAL_TIME_ALARM;
case SIGPROF:
return CF_CHECK_SIGNAL_PROFILING_TIMER_ALARM;
case SIGWINCH:
return CF_CHECK_SIGNAL_WINDOW_SIZE_CHANGE;
// Some signals are present on OS X / BSD but not Ubuntu 14, omitting:
// case SIGEMT:
// return CF_CHECK_SIGNAL_EMULATE_INSTRUCTION;
// case SIGINFO:
// return CF_CHECK_SIGNAL_STATUS_REQUEST;
default:
break;
}
return CF_CHECK_SIGNAL_OTHER;
}
static int lmdump_errno_to_code(int r)
{
switch (r) {
case 0:
return CF_CHECK_OK;
// LMDB-specific error codes:
case MDB_KEYEXIST:
return CF_CHECK_LMDB_KEY_EXISTS;
case MDB_NOTFOUND:
return CF_CHECK_LMDB_KEY_NOT_FOUND;
case MDB_PAGE_NOTFOUND:
return CF_CHECK_LMDB_PAGE_NOT_FOUND;
case MDB_CORRUPTED:
return CF_CHECK_LMDB_CORRUPT_PAGE;
case MDB_PANIC:
return CF_CHECK_LMDB_PANIC_FATAL_ERROR;
case MDB_VERSION_MISMATCH:
return CF_CHECK_LMDB_VERSION_MISMATCH;
case MDB_INVALID:
return CF_CHECK_LMDB_INVALID_DATABASE;
case MDB_MAP_FULL:
return CF_CHECK_LMDB_MAP_FULL;
case MDB_DBS_FULL:
return CF_CHECK_LMDB_DBS_FULL;
case MDB_READERS_FULL:
return CF_CHECK_LMDB_READERS_FULL;
case MDB_TLS_FULL:
return CF_CHECK_LMDB_TLS_KEYS_FULL;
case MDB_TXN_FULL:
return CF_CHECK_LMDB_TRANSACTION_FULL;
case MDB_CURSOR_FULL:
return CF_CHECK_LMDB_CURSOR_STACK_TOO_DEEP;
case MDB_PAGE_FULL:
return CF_CHECK_LMDB_PAGE_FULL;
case MDB_MAP_RESIZED:
return CF_CHECK_LMDB_MAP_RESIZE_BEYOND_SIZE;
case MDB_INCOMPATIBLE:
return CF_CHECK_LMDB_INCOMPATIBLE_OPERATION;
case MDB_BAD_RSLOT:
return CF_CHECK_LMDB_INVALID_REUSE_OF_READER_LOCKTABLE_SLOT;
case MDB_BAD_TXN:
return CF_CHECK_LMDB_BAD_OR_INVALID_TRANSACTION;
case MDB_BAD_VALSIZE:
return CF_CHECK_LMDB_WRONG_KEY_OR_VALUE_SIZE;
// Doesn't exist in earlier versions of LMDB:
// case MDB_BAD_DBI:
// return CF_CHECK_LMDB_BAD_DBI;
default:
break;
}
const int s = errno_to_code(r);
if (s == CF_CHECK_UNKNOWN)
{
return CF_CHECK_LMDUMP_UNKNOWN_ERROR;
}
return s;
}
static int diagnose(const char *path)
{
freopen("/dev/null", "w", stdout);
return lmdump(LMDUMP_VALUES_ASCII, path);
}
static int fork_and_diagnose(const char *path)
{
const pid_t child_pid = fork();
if (child_pid == 0)
{
// Child
exit(diagnose(path));
}
else
{
// Parent
int status;
pid_t pid = waitpid(child_pid, &status, 0);
if (pid != child_pid)
{
return CF_CHECK_PID_ERROR;
}
if (WIFEXITED(status) && WEXITSTATUS(status) != CF_CHECK_OK)
{
return lmdump_errno_to_code(WEXITSTATUS(status));
}
if (WIFSIGNALED(status))
{
return signal_to_code(WTERMSIG(status));
}
}
return CF_CHECK_OK;
}
int diagnose_main(int argc, char **argv)
{
if (argc <= 1)
{
printf("Need to supply filename(s)\n");
return 1;
}
int corruptions = 0;
const int total = argc - 1;
for (int i = 1; i < argc; ++i)
{
const int r = fork_and_diagnose(argv[i]);
printf("Status of '%s': %s\n", argv[i], CF_CHECK_STRING(r));
if (r != CF_CHECK_OK)
{
++corruptions;
}
}
if (corruptions == 0)
{
printf("All %d databases healthy\n", total);
}
else
{
printf("Problems detected in %d/%d databases\n", corruptions, total);
}
return corruptions;
}
#endif
cfengine-3.12.1/cf-check/Makefile.am 0000644 0000000 0000000 00000003263 13377750461 017072 0 ustar 00root root 0000000 0000000 #
# Copyright 2018 Northern.tech AS
#
# This file is part of CFEngine 3 - written and maintained by Northern.tech AS.
#
# 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; version 3.
#
# 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, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
#
# To the extent this program is licensed as part of the Enterprise
# versions of CFEngine, the applicable Commercial Open Source License
# (COSL) may apply to this file if you as a licensee so wish it. See
# included file COSL.txt.
#
noinst_LTLIBRARIES = libcf-check.la
AM_CPPFLAGS = -I$(srcdir)/../libutils \
$(LMDB_CPPFLAGS)
AM_CFLAGS = \
$(LMDB_CFLAGS) \
$(PTHREAD_CFLAGS)
AM_LDFLAGS = \
$(LMDB_LDFLAGS)
libcf_check_la_LIBADD = ../libutils/libutils.la \
$(LMDB_LIBS) \
$(PTHREAD_LIBS)
libcf_check_la_SOURCES = \
lmdump.c lmdump.h \
diagnose.c diagnose.h \
cf-check.c
if !BUILTIN_EXTENSIONS
bin_PROGRAMS = cf-check
# Workaround for automake madness (try removing it if you want to know why).
cf_check_CFLAGS = $(AM_CFLAGS)
# Build both a libcf-check.la library, and a cf-check executable
cf_check_LDADD = libcf-check.la
endif
CLEANFILES = *.gcno *.gcda
#
# Some basic clean ups
#
MOSTLYCLEANFILES = *~ *.orig *.rej
cfengine-3.12.1/cf-check/cf-check.c 0000644 0000000 0000000 00000004121 13377750461 016637 0 ustar 00root root 0000000 0000000 #include
#include
#include
static void print_version()
{
printf("cf-check BETA version %s\n", VERSION);
}
static void print_help()
{
printf(
"\n"
"cf-check:\n"
"\tUtility for diagnosis and repair of local CFEngine databases.\n"
"\tThis BETA version of the tool is for testing purposes only.\n"
"\n"
"Commands:\n"
"\tdump - Print the contents of a database file\n"
"\tdiagnose - Assess the health of one or more database files\n"
"\tversion - Print version information\n"
"\thelp - Print this help menu\n"
"\n"
"Usage:\n"
"\t$ cf-check command [options]\n"
"\n"
"Examples:\n"
"\t$ cf-check dump -a /var/cfengine/state/cf_lastseen.lmdb\n"
"\t$ cf-check diagnose /var/cfengine/state/*.lmdb\n"
"\n"
);
}
int main(int argc, char **argv)
{
if (StringEndsWith(argv[0], "lmdump"))
{
// Compatibility mode; act like lmdump if symlinked or renamed:
return lmdump_main(argc, argv);
}
if (argc < 2)
{
print_help();
printf("No command given.\n");
return 1;
}
const int cmd_argc = argc - 1;
char **cmd_argv = argv + 1;
char *command = cmd_argv[0];
if (StringSafeEqual_IgnoreCase(command, "lmdump") ||
StringSafeEqual_IgnoreCase(command, "dump"))
{
return lmdump_main(cmd_argc, cmd_argv);
}
if (StringSafeEqual_IgnoreCase(command, "diagnose"))
{
return diagnose_main(cmd_argc, cmd_argv);
}
if (StringSafeEqual_IgnoreCase(command, "help") ||
StringSafeEqual_IgnoreCase(command, "--help") ||
StringSafeEqual_IgnoreCase(command, "-h"))
{
print_help();
return 0;
}
if (StringSafeEqual_IgnoreCase(command, "version") ||
StringSafeEqual_IgnoreCase(command, "--version") ||
StringSafeEqual_IgnoreCase(command, "-V"))
{
print_version();
return 0;
}
print_help();
printf("Unrecognized command: '%s'\n", command);
return 1;
}
cfengine-3.12.1/cf-check/lmdump.c 0000644 0000000 0000000 00000007703 13377750461 016503 0 ustar 00root root 0000000 0000000 #include
#include
#include
#ifdef LMDB
#include
#include
#include
#include
static void lmdump_print_hex(const char *s, size_t len)
{
for (int i = 0; i < len; i++)
{
printf("%02x", s[i]);
}
}
static void lmdump_print_usage(void)
{
printf("Lmdb database dumper\n");
printf("Usage: lmdump -d|-x|-a|-A filename\n\n");
printf("Has three modes :\n");
printf(" -A : print keys in ascii form\n");
printf(" -a : print keys and values in ascii form\n");
printf(" -x : print keys and values in hexadecimal form\n");
printf(" -d : print only the size of keys and values\n");
}
lmdump_mode lmdump_char_to_mode(char mode)
{
switch (mode) {
case 'A':
return LMDUMP_KEYS_ASCII;
case 'a':
return LMDUMP_VALUES_ASCII;
case 'x':
return LMDUMP_VALUES_HEX;
case 'd':
return LMDUMP_SIZES;
default:
break;
}
return LMDUMP_UNKNOWN;
}
static int lmdump_report_error(int rc)
{
printf("err(%d): %s\n", rc, mdb_strerror(rc));
return rc;
}
void lmdump_print_line(lmdump_mode mode, MDB_val key, MDB_val data)
{
assert(mode >= 0 && mode < LMDUMP_UNKNOWN);
switch (mode) {
case LMDUMP_KEYS_ASCII:
printf("key: %p[%d] %.*s\n",
key.mv_data, (int) key.mv_size, (int) key.mv_size, (char *) key.mv_data);
break;
case LMDUMP_VALUES_ASCII:
printf("key: %p[%d] %.*s, data: %p[%d] %.*s\n",
key.mv_data, (int) key.mv_size, (int) key.mv_size, (char *) key.mv_data,
data.mv_data, (int) data.mv_size, (int) data.mv_size, (char *) data.mv_data);
break;
case LMDUMP_VALUES_HEX:
printf("key: %p[%d] ", key.mv_data, (int) key.mv_size);
lmdump_print_hex(key.mv_data, (int) key.mv_size);
printf(" ,data: %p[%d] ", data.mv_data, (int) data.mv_size);
lmdump_print_hex(data.mv_data, (int) data.mv_size);
printf("\n");
break;
case LMDUMP_SIZES:
printf("key: %p[%d] ,data: %p[%d]\n",
key.mv_data, (int) key.mv_size,
data.mv_data, (int) data.mv_size);
break;
default:
break;
}
}
int lmdump(lmdump_mode mode, const char *file)
{
assert(mode >= 0 && mode < LMDUMP_UNKNOWN);
assert(file != NULL);
int rc;
MDB_env *env;
rc = mdb_env_create(&env);
if (rc) return lmdump_report_error(rc);
rc = mdb_env_open(env, file, MDB_NOSUBDIR | MDB_RDONLY, 0644);
if (rc) return lmdump_report_error(rc);
MDB_txn *txn;
rc = mdb_txn_begin(env, NULL, MDB_RDONLY, &txn);
if (rc) return lmdump_report_error(rc);
MDB_dbi dbi;
rc = mdb_open(txn, NULL, 0, &dbi);
if (rc) return lmdump_report_error(rc);
MDB_cursor *cursor;
rc = mdb_cursor_open(txn, dbi, &cursor);
if (rc) return lmdump_report_error(rc);
MDB_val key, data;
while ( (rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == MDB_SUCCESS )
{
lmdump_print_line(mode, key, data);
}
if (rc != MDB_NOTFOUND)
{
// At this point, not found is expected, anything else is an error
return lmdump_report_error(rc);
}
mdb_cursor_close(cursor);
mdb_close(env, dbi);
mdb_txn_abort(txn);
mdb_env_close(env);
return 0;
}
int lmdump_main(int argc, char * argv[])
{
assert(argv != NULL);
if (argc != 3 || argv[1][0] != '-')
{
lmdump_print_usage();
return 1;
}
const char *filename = argv[2];
const lmdump_mode mode = lmdump_char_to_mode(argv[1][1]);
if (mode == LMDUMP_UNKNOWN)
{
lmdump_print_usage();
return 1;
}
return lmdump(mode, filename);
}
#else
int lmdump_main(ARG_UNUSED int argc, ARG_UNUSED char * argv[])
{
printf("lmdump only implemented for LMDB.\n");
return 1;
}
#endif
cfengine-3.12.1/cf-agent/ 0000755 0000000 0000000 00000000000 13377750567 015062 5 ustar 00root root 0000000 0000000 cfengine-3.12.1/cf-agent/files_edit.c 0000644 0000000 0000000 00000020270 13377750461 017327 0 ustar 00root root 0000000 0000000 /*
Copyright 2018 Northern.tech AS
This file is part of CFEngine 3 - written and maintained by Northern.tech AS.
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; version 3.
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, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
To the extent this program is licensed as part of the Enterprise
versions of CFEngine, the applicable Commercial Open Source License
(COSL) may apply to this file if you as a licensee so wish it. See
included file COSL.txt.
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
/*****************************************************************************/
EditContext *NewEditContext(char *filename, Attributes a)
{
EditContext *ec;
if (!IsAbsoluteFileName(filename))
{
Log(LOG_LEVEL_ERR, "Relative file name '%s' was marked for editing but has no invariant meaning", filename);
return NULL;
}
ec = xcalloc(1, sizeof(EditContext));
ec->filename = filename;
ec->new_line_mode = FileNewLineMode(filename);
if (a.haveeditline)
{
if (!LoadFileAsItemList(&(ec->file_start), filename, a.edits))
{
free(ec);
return NULL;
}
}
if (a.haveeditxml)
{
#ifdef HAVE_LIBXML2
if (!LoadFileAsXmlDoc(&(ec->xmldoc), filename, a.edits))
{
free(ec);
return NULL;
}
#else
Log(LOG_LEVEL_ERR, "Cannot edit XML files without LIBXML2");
free(ec);
return NULL;
#endif
}
if (a.edits.empty_before_use)
{
Log(LOG_LEVEL_VERBOSE, "Build file model from a blank slate (emptying)");
DeleteItemList(ec->file_start);
ec->file_start = NULL;
}
return ec;
}
/*****************************************************************************/
void FinishEditContext(EvalContext *ctx, EditContext *ec, Attributes a, const Promise *pp,
PromiseResult *result)
{
if (*result == PROMISE_RESULT_NOOP || *result == PROMISE_RESULT_CHANGE)
{
// A sub promise with CHANGE status does not necessarily mean that the
// file has really changed.
*result = PROMISE_RESULT_NOOP;
}
else
{
// Failure or skipped. Don't update the file.
goto end;
}
if (DONTDO || (a.transaction.action == cfa_warn))
{
if (ec &&
!CompareToFile(ctx, ec->file_start, ec->filename, a, pp, result) &&
ec->num_edits > 0)
{
cfPS(ctx, LOG_LEVEL_WARNING, PROMISE_RESULT_WARN, pp, a,
"Should edit file '%s' but only a warning promised",
ec->filename);
*result = PROMISE_RESULT_WARN;
}
else
{
cfPS(ctx, LOG_LEVEL_VERBOSE, PROMISE_RESULT_NOOP, pp, a,
"No edit changes to file '%s' need saving", ec->filename);
*result = PROMISE_RESULT_NOOP;
}
}
else if (ec && (ec->num_edits > 0))
{
if (a.haveeditline || a.edit_template || a.edit_template_string)
{
if (CompareToFile(ctx, ec->file_start, ec->filename, a, pp, result))
{
cfPS(ctx, LOG_LEVEL_VERBOSE, PROMISE_RESULT_NOOP, pp, a,
"No edit changes to file '%s' need saving", ec->filename);
}
else if (SaveItemListAsFile(ec->file_start, ec->filename, a, ec->new_line_mode))
{
cfPS(ctx, LOG_LEVEL_INFO, PROMISE_RESULT_CHANGE, pp, a,
"Edit file '%s'", ec->filename);
*result = PromiseResultUpdate(*result, PROMISE_RESULT_CHANGE);
}
else
{
cfPS(ctx, LOG_LEVEL_ERR, PROMISE_RESULT_FAIL, pp, a,
"Unable to save file '%s' after editing", ec->filename);
*result = PromiseResultUpdate(*result, PROMISE_RESULT_FAIL);
}
}
if (a.haveeditxml)
{
#ifdef HAVE_LIBXML2
if (XmlCompareToFile(ec->xmldoc, ec->filename, a.edits))
{
if (ec)
{
cfPS(ctx, LOG_LEVEL_VERBOSE, PROMISE_RESULT_NOOP, pp, a,
"No edit changes to xml file '%s' need saving", ec->filename);
}
}
else if (SaveXmlDocAsFile(ec->xmldoc, ec->filename, a, ec->new_line_mode))
{
cfPS(ctx, LOG_LEVEL_INFO, PROMISE_RESULT_CHANGE, pp, a,
"Edited xml file '%s'", ec->filename);
*result = PromiseResultUpdate(*result, PROMISE_RESULT_CHANGE);
}
else
{
cfPS(ctx, LOG_LEVEL_ERR, PROMISE_RESULT_FAIL, pp, a,
"Failed to edit XML file '%s'", ec->filename);
*result = PromiseResultUpdate(*result, PROMISE_RESULT_FAIL);
}
xmlFreeDoc(ec->xmldoc);
#else
cfPS(ctx, LOG_LEVEL_ERR, PROMISE_RESULT_FAIL, pp, a,
"Cannot edit XML files without LIBXML2");
*result = PromiseResultUpdate(*result, PROMISE_RESULT_FAIL);
#endif
}
}
else if (ec)
{
cfPS(ctx, LOG_LEVEL_VERBOSE, PROMISE_RESULT_NOOP, pp, a,
"No edit changes to file '%s' need saving", ec->filename);
}
end:
if (ec != NULL)
{
DeleteItemList(ec->file_start);
free(ec);
}
}
/*********************************************************************/
/* Level */
/*********************************************************************/
#ifdef HAVE_LIBXML2
/***************************************************************************/
int LoadFileAsXmlDoc(xmlDocPtr *doc, const char *file, EditDefaults edits)
{
struct stat statbuf;
if (stat(file, &statbuf) == -1)
{
Log(LOG_LEVEL_ERR, "The proposed file '%s' could not be loaded. (stat: %s)", file, GetErrorStr());
return false;
}
if (edits.maxfilesize != 0 && statbuf.st_size > edits.maxfilesize)
{
Log(LOG_LEVEL_INFO, "File '%s' is bigger than the edit limit. max_file_size = '%jd' > '%d' bytes", file,
(intmax_t) statbuf.st_size, edits.maxfilesize);
return false;
}
if (!S_ISREG(statbuf.st_mode))
{
Log(LOG_LEVEL_INFO, "'%s' is not a plain file", file);
return false;
}
if (statbuf.st_size == 0)
{
if ((*doc = xmlNewDoc(BAD_CAST "1.0")) == NULL)
{
Log(LOG_LEVEL_INFO, "Document '%s' not parsed successfully. (xmlNewDoc: %s)", file, GetErrorStr());
return false;
}
}
else if ((*doc = xmlParseFile(file)) == NULL)
{
Log(LOG_LEVEL_INFO, "Document '%s' not parsed successfully. (xmlParseFile: %s)", file, GetErrorStr());
return false;
}
return true;
}
/*********************************************************************/
static bool SaveXmlCallback(const char *dest_filename, void *param,
ARG_UNUSED NewLineMode new_line_mode)
{
xmlDocPtr doc = param;
//saving xml to file
if (xmlSaveFile(dest_filename, doc) == -1)
{
Log(LOG_LEVEL_ERR, "Failed to write xml document to file '%s' after editing. (xmlSaveFile: %s)", dest_filename, GetErrorStr());
return false;
}
return true;
}
/*********************************************************************/
bool SaveXmlDocAsFile(xmlDocPtr doc, const char *file, Attributes a, NewLineMode new_line_mode)
{
return SaveAsFile(&SaveXmlCallback, doc, file, a, new_line_mode);
}
#endif /* HAVE_LIBXML2 */
cfengine-3.12.1/cf-agent/verify_services.c 0000644 0000000 0000000 00000015176 13377750461 020440 0 ustar 00root root 0000000 0000000 /*
Copyright 2018 Northern.tech AS
This file is part of CFEngine 3 - written and maintained by Northern.tech AS.
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; version 3.
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, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
To the extent this program is licensed as part of the Enterprise
versions of CFEngine, the applicable Commercial Open Source License
(COSL) may apply to this file if you as a licensee so wish it. See
included file COSL.txt.
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
static int ServicesSanityChecks(Attributes a, const Promise *pp);
static void SetServiceDefaults(Attributes *a);
static PromiseResult DoVerifyServices(EvalContext *ctx, Attributes a, const Promise *pp);
static PromiseResult VerifyServices(EvalContext *ctx, Attributes a, const Promise *pp);
/*****************************************************************************/
PromiseResult VerifyServicesPromise(EvalContext *ctx, const Promise *pp)
{
Attributes a = GetServicesAttributes(ctx, pp);
SetServiceDefaults(&a);
if (ServicesSanityChecks(a, pp))
{
return VerifyServices(ctx, a, pp);
}
else
{
return PROMISE_RESULT_NOOP;
}
}
/*****************************************************************************/
static int ServicesSanityChecks(Attributes a, const Promise *pp)
{
Rlist *dep;
for (dep = a.service.service_depend; dep != NULL; dep = dep->next)
{
if (strcmp(pp->promiser, RlistScalarValue(dep)) == 0)
{
Log(LOG_LEVEL_ERR, "Service promiser '%s' has itself as dependency", pp->promiser);
PromiseRef(LOG_LEVEL_ERR, pp);
return false;
}
}
if (a.service.service_type == NULL)
{
Log(LOG_LEVEL_ERR, "Service type for service '%s' is not known", pp->promiser);
PromiseRef(LOG_LEVEL_ERR, pp);
return false;
}
#ifdef __MINGW32__
if (strcmp(a.service.service_type, "windows") != 0)
{
Log(LOG_LEVEL_ERR, "Service type for promiser '%s' must be 'windows' on this system, but is '%s'",
pp->promiser, a.service.service_type);
PromiseRef(LOG_LEVEL_ERR, pp);
return false;
}
#endif /* __MINGW32__ */
return true;
}
/*****************************************************************************/
static void SetServiceDefaults(Attributes *a)
{
if ((a->service.service_policy == NULL) ||
strcmp(a->service.service_policy, "") == 0)
{
Log(LOG_LEVEL_VERBOSE,
"Attribute 'service_policy' was not set, defaulting to: 'start'");
a->service.service_policy = "start";
}
if (a->service.service_autostart_policy == NULL)
{
a->service.service_autostart_policy = "none";
}
if (a->service.service_depend_chain == NULL)
{
a->service.service_depend_chain = "ignore";
}
// default service type to "windows" on windows platforms
#ifdef __MINGW32__
if (a->service.service_type == NULL)
{
a->service.service_type = "windows";
}
#else
if (a->service.service_type == NULL)
{
a->service.service_type = "bundle";
}
#endif /* __MINGW32__ */
}
/*****************************************************************************/
/* Level */
/*****************************************************************************/
static PromiseResult VerifyServices(EvalContext *ctx, Attributes a, const Promise *pp)
{
CfLock thislock;
thislock = AcquireLock(ctx, pp->promiser, VUQNAME, CFSTARTTIME, a.transaction, pp, false);
if (thislock.lock == NULL)
{
return PROMISE_RESULT_SKIPPED;
}
PromiseBanner(ctx, pp);
PromiseResult result = PROMISE_RESULT_SKIPPED;
if (strcmp(a.service.service_type, "windows") == 0)
{
#ifdef __MINGW32__
result = PromiseResultUpdate(result, VerifyWindowsService(ctx, a, pp));
#else
Log(LOG_LEVEL_INFO, "Service type windows not supported on this platform.");
#endif
}
else
{
result = PromiseResultUpdate(result, DoVerifyServices(ctx, a, pp));
}
YieldCurrentLock(thislock);
return result;
}
/*****************************************************************************/
/* Level */
/*****************************************************************************/
static FnCall *DefaultServiceBundleCall(const Promise *pp, const char *service_policy)
{
Rlist *args = NULL;
FnCall *call = NULL;
RlistAppend(&args, pp->promiser, RVAL_TYPE_SCALAR);
RlistAppend(&args, service_policy, RVAL_TYPE_SCALAR);
Rval name = DefaultBundleConstraint(pp, "service");
if (PolicyGetBundle(PolicyFromPromise(pp), PromiseGetBundle(pp)->ns, "agent", (char *)name.item))
{
Log(LOG_LEVEL_VERBOSE, "Found service special bundle %s in ns %s\n", (char *)name.item, PromiseGetBundle(pp)->ns);
call = FnCallNew(name.item, args);
}
else
{
call = FnCallNew("standard_services", args);
}
return call;
}
static PromiseResult DoVerifyServices(EvalContext *ctx, Attributes a, const Promise *pp)
{
Rval call;
{
const Constraint *cp = PromiseGetConstraint(pp, "service_bundle");
if (cp)
{
call = RvalCopy(cp->rval);
}
else
{
call = (Rval) { DefaultServiceBundleCall(pp, a.service.service_policy), RVAL_TYPE_FNCALL };
}
}
a.havebundle = true;
EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_THIS, "service_policy", a.service.service_policy, CF_DATA_TYPE_STRING, "source=promise");
PromiseResult result = PROMISE_RESULT_NOOP;
result = PromiseResultUpdate(result, VerifyMethod(ctx, call, a, pp)); // Send list of classes to set privately?
RvalDestroy(call);
return result;
}
cfengine-3.12.1/cf-agent/findhub_priv.h 0000644 0000000 0000000 00000004452 13377750461 017710 0 ustar 00root root 0000000 0000000 /*
Copyright 2018 Northern.tech AS
This file is part of CFEngine 3 - written and maintained by Northern.tech AS.
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; version 3.
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, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
To the extent this program is licensed as part of the Enterprise
versions of CFEngine, the applicable Commercial Open Source License
(COSL) may apply to this file if you as a licensee so wish it. See
included file COSL.txt.
*/
#ifndef CFENGINE_FINDHUB_PRIV_H
#define CFENGINE_FINDHUB_PRIV_H
#include
#include
AvahiSimplePoll *spoll;
typedef struct
{
char Hostname[4096];
char IPAddress[AVAHI_ADDRESS_STR_MAX];
uint16_t Port;
} HostProperties;
void resolve_callback(AvahiServiceResolver *r,
AvahiIfIndex interface,
AvahiProtocol protocol,
AvahiResolverEvent event,
const char *name,
const char *type,
const char *domain,
const char *host_name,
const AvahiAddress *address,
uint16_t port,
AvahiStringList *txt,
AvahiLookupFlags flags,
void* userdata);
void browse_callback(AvahiServiceBrowser *b,
AvahiIfIndex interface,
AvahiProtocol protocol,
AvahiBrowserEvent event,
const char *name,
const char *type,
const char *domain,
AvahiLookupResultFlags flags,
void *userdata);
void client_callback(AvahiClient *c,
AvahiClientState state,
void *userdata);
#endif
cfengine-3.12.1/cf-agent/verify_databases.h 0000644 0000000 0000000 00000002234 13377750461 020540 0 ustar 00root root 0000000 0000000 /*
Copyright 2018 Northern.tech AS
This file is part of CFEngine 3 - written and maintained by Northern.tech AS.
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; version 3.
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, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
To the extent this program is licensed as part of the Enterprise
versions of CFEngine, the applicable Commercial Open Source License
(COSL) may apply to this file if you as a licensee so wish it. See
included file COSL.txt.
*/
#ifndef CFENGINE_VERIFY_DATABASES_H
#define CFENGINE_VERIFY_DATABASES_H
#include
PromiseResult VerifyDatabasePromises(EvalContext *ctx, const Promise *pp);
#endif
cfengine-3.12.1/cf-agent/load_avahi.h 0000644 0000000 0000000 00000005261 13377750461 017317 0 ustar 00root root 0000000 0000000 /*
Copyright 2018 Northern.tech AS
This file is part of CFEngine 3 - written and maintained by Northern.tech AS.
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; version 3.
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, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
To the extent this program is licensed as part of the Enterprise
versions of CFEngine, the applicable Commercial Open Source License
(COSL) may apply to this file if you as a licensee so wish it. See
included file COSL.txt.
*/
#ifndef CFENGINE_LOAD_AVAHI_H
#define CFENGINE_LOAD_AVAHI_H
#include
#include
#include