cfengine-3.2.4/ 0000755 0001750 0001750 00000000000 11715233356 010305 5 0000000 0000000 cfengine-3.2.4/install-sh 0000755 0001750 0001750 00000033256 11715232774 012245 0000000 0000000 #!/bin/sh
# install - install a program, script, or datafile
scriptversion=2011-01-19.21; # 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.
;;
*)
tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$
trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0
if (umask $mkdir_umask &&
exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/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-writeable bit of parent directory when it shouldn't.
# FreeBSD 6.1 mkdir -m -p sets mode of existing directory.
ls_ld_tmpdir=`ls -ld "$tmpdir"`
case $ls_ld_tmpdir in
d????-?r-*) different_mode=700;;
d????-?--*) different_mode=755;;
*) false;;
esac &&
$mkdirprog -m$different_mode -p -- "$tmpdir" && {
ls_ld_tmpdir_1=`ls -ld "$tmpdir"`
test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1"
}
}
then posix_mkdir=:
fi
rmdir "$tmpdir/d" "$tmpdir"
else
# Remove any dirs left behind by ancient mkdir implementations.
rmdir ./$mkdir_mode ./-p ./-- 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.2.4/LICENSE 0000644 0001750 0001750 00000126274 11707771421 011247 0000000 0000000 This file contains a copy of:
1) The GNU General Public License version 3
1) The Commericial Open Source License (COSL)
----------------------------------------------------------------------------
CFEngine is provided under the terms of the GNU General Public License (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
(/pub/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 edition Nova, Constellation and Galaxy 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 IDEMNINFICATION
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.2.4/src/ 0000755 0001750 0001750 00000000000 11715233355 011073 5 0000000 0000000 cfengine-3.2.4/src/nfs.c 0000644 0001750 0001750 00000042675 11715232734 011763 0000000 0000000 /*
Copyright (C) Cfengine AS
This file is part of Cfengine 3 - written and maintained by Cfengine 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 Commerical Open Source License
(COSL) may apply to this file if you as a licensee so wish it. See
included file COSL.txt.
*/
/*****************************************************************************/
/* */
/* File: nfs.c */
/* */
/*****************************************************************************/
#include "cf3.defs.h"
#include "cf3.extern.h"
#ifndef MINGW
static void AugmentMountInfo(struct Rlist **list,char *host,char *source,char *mounton,char *options);
static int MatchFSInFstab(char *match);
static void DeleteThisItem(struct Item **liststart,struct Item *entry);
#endif
/*******************************************************************/
#ifndef MINGW // use samba on windows ?
int LoadMountInfo(struct Rlist **list)
/* This is, in fact, the most portable way to read the mount info! */
/* Depressing, isn't it? */
{ FILE *pp;
char buf1[CF_BUFSIZE],buf2[CF_BUFSIZE],buf3[CF_BUFSIZE];
char host[CF_MAXVARSIZE],source[CF_BUFSIZE],mounton[CF_BUFSIZE],vbuff[CF_BUFSIZE];
int i, nfs = false;
for (i=0; VMOUNTCOMM[VSYSTEMHARDCLASS][i] != ' '; i++)
{
buf1[i] = VMOUNTCOMM[VSYSTEMHARDCLASS][i];
}
buf1[i] = '\0';
SetTimeOut(RPCTIMEOUT);
if ((pp = cf_popen(buf1,"r")) == NULL)
{
CfOut(cf_error,"cf_popen","Can't open %s\n",buf1);
return false;
}
do
{
vbuff[0] = buf1[0] = buf2[0] = buf3[0] = source[0] = '\0';
if (ferror(pp)) /* abortable */
{
CfOut(cf_error,"ferror","Error getting mount info\n");
break;
}
CfReadLine(vbuff,CF_BUFSIZE,pp);
if (ferror(pp)) /* abortable */
{
CfOut(cf_error,"ferror","Error getting mount info\n");
break;
}
if (strstr(vbuff,"nfs"))
{
nfs = true;
}
sscanf(vbuff,"%s%s%s",buf1,buf2,buf3);
if (vbuff[0] == '\0' || vbuff[0] == '\n')
{
break;
}
if (strstr(vbuff,"not responding"))
{
CfOut(cf_error,"","%s\n",vbuff);
}
if (strstr(vbuff,"be root"))
{
CfOut(cf_error,"","Mount access is denied. You must be root.\n");
CfOut(cf_error,"","Use the -n option to run safely.");
}
if (strstr(vbuff,"retrying") || strstr(vbuff,"denied") || strstr(vbuff,"backgrounding"))
{
continue;
}
if (strstr(vbuff,"exceeded") || strstr(vbuff,"busy"))
{
continue;
}
if (strstr(vbuff,"RPC"))
{
CfOut(cf_inform,"","There was an RPC timeout. Aborting mount operations.\n");
CfOut(cf_inform,"","Session failed while trying to talk to remote host\n");
CfOut(cf_inform,"","%s\n",vbuff);
cf_pclose(pp);
return false;
}
switch (VSYSTEMHARDCLASS)
{
case darwin:
case sun4:
case sun3:
case ultrx:
case irix:
case irix4:
case irix64:
case linuxx:
case GnU:
case unix_sv:
case freebsd:
case netbsd:
case openbsd:
case bsd_i:
case nextstep:
case bsd4_3:
case newsos:
case aos:
case osf:
case qnx:
case crayos:
case dragonfly:
if (IsAbsoluteFileName(buf1))
{
strcpy(host,"localhost");
strcpy(mounton,buf3);
}
else
{
sscanf(buf1,"%[^:]:%s",host,source);
strcpy(mounton,buf3);
}
break;
case solaris:
case solarisx86:
case hp:
if (IsAbsoluteFileName(buf3))
{
strcpy(host,"localhost");
strcpy(mounton,buf1);
}
else
{
sscanf(buf1,"%[^:]:%s",host,source);
strcpy(mounton,buf1);
}
break;
case aix:
/* skip header */
if (IsAbsoluteFileName(buf1))
{
strcpy(host,"localhost");
strcpy(mounton,buf2);
}
else
{
strcpy(host,buf1);
strcpy(source,buf1);
strcpy(mounton,buf3);
}
break;
case cfnt:
strcpy(mounton,buf2);
strcpy(host,buf1);
break;
case unused2:
case unused3:
break;
case cfsco: CfOut(cf_error,"","Don't understand SCO mount format, no data");
default:
printf("cfengine software error: case %d = %s\n",VSYSTEMHARDCLASS,CLASSTEXT[VSYSTEMHARDCLASS]);
FatalError("System error in GetMountInfo - no such class!");
}
Debug("GOT: host=%s, source=%s, mounton=%s\n",host,source,mounton);
if (nfs)
{
AugmentMountInfo(list,host,source,mounton,"nfs");
}
else
{
AugmentMountInfo(list,host,source,mounton,NULL);
}
}
while (!feof(pp));
alarm(0);
signal(SIGALRM,SIG_DFL);
cf_pclose(pp);
return true;
}
/*******************************************************************/
static void AugmentMountInfo(struct Rlist **list,char *host,char *source,char *mounton,char *options)
{ struct CfMount *entry;
if ((entry = malloc(sizeof(struct CfMount))) == NULL)
{
CfOut(cf_error,"malloc","Memory allocation error - augmenting mount info");
return;
}
entry->host = entry->source = entry->mounton = entry->options = NULL;
if (host)
{
entry->host = strdup(host);
}
if (source)
{
entry->source = strdup(source);
}
if (mounton)
{
entry->mounton = strdup(mounton);
}
if (options)
{
entry->options = strdup(options);
}
AppendRlistAlien(list,(void *)entry);
}
/*******************************************************************/
void DeleteMountInfo(struct Rlist *list)
{ struct Rlist *rp, *sp;
struct CfMount *entry;
for (rp = list; rp != NULL; rp = sp)
{
sp = rp->next;
entry = (struct CfMount *)rp->item;
if (entry->host)
{
free (entry->host);
}
if (entry->source)
{
free (entry->source);
}
if (entry->mounton)
{
free (entry->mounton);
}
if (entry->options)
{
free (entry->options);
}
free((char *)entry);
}
}
/*******************************************************************/
int VerifyInFstab(char *name,struct Attributes a,struct Promise *pp)
/* Ensure filesystem IS in fstab, and return no of changes */
{ char fstab[CF_BUFSIZE];
char *host,*rmountpt,*mountpt,*fstype,*opts;
if (!FSTABLIST)
{
if (!LoadFileAsItemList(&FSTABLIST,VFSTAB[VSYSTEMHARDCLASS],a,pp))
{
CfOut(cf_error,"","Couldn't open %s!\n",VFSTAB[VSYSTEMHARDCLASS]);
return false;
}
else
{
FSTAB_EDITS = 0;
}
}
if (a.mount.mount_options)
{
opts = Rlist2String(a.mount.mount_options,",");
}
else
{
opts = strdup(VMOUNTOPTS[VSYSTEMHARDCLASS]);
}
host = a.mount.mount_server;
rmountpt = a.mount.mount_source;
mountpt = name;
fstype = a.mount.mount_type;
switch (VSYSTEMHARDCLASS)
{
case osf:
case bsd4_3:
case irix:
case irix4:
case irix64:
case sun3:
case aos:
case nextstep:
case newsos:
case qnx:
case sun4: snprintf(fstab,CF_BUFSIZE,"%s:%s \t %s %s\t%s 0 0",host,rmountpt,mountpt,fstype,opts);
break;
case crayos:
snprintf(fstab,CF_BUFSIZE,"%s:%s \t %s %s\t%s",host,rmountpt,mountpt,ToUpperStr(fstype),opts);
break;
case ultrx: //snprintf(fstab,CF_BUFSIZE,"%s@%s:%s:%s:0:0:%s:%s",rmountpt,host,mountpt,mode,fstype,opts);
break;
case hp: snprintf(fstab,CF_BUFSIZE,"%s:%s %s \t %s \t %s 0 0",host,rmountpt,mountpt,fstype,opts);
break;
case aix: snprintf(fstab,CF_BUFSIZE,"%s:\n\tdev\t= %s\n\ttype\t= %s\n\tvfs\t= %s\n\tnodename\t= %s\n\tmount\t= true\n\toptions\t= %s\n\taccount\t= false\n",mountpt,rmountpt,fstype,fstype,host,opts);
break;
case GnU:
case linuxx: snprintf(fstab,CF_BUFSIZE,"%s:%s \t %s \t %s \t %s",host,rmountpt,mountpt,fstype,opts);
break;
case netbsd:
case openbsd:
case bsd_i:
case dragonfly:
case freebsd: snprintf(fstab,CF_BUFSIZE,"%s:%s \t %s \t %s \t %s 0 0",host,rmountpt,mountpt,fstype,opts);
break;
case unix_sv:
case solarisx86:
case solaris: snprintf(fstab,CF_BUFSIZE,"%s:%s - %s %s - yes %s",host,rmountpt,mountpt,fstype,opts);
break;
case cfnt: snprintf(fstab,CF_BUFSIZE,"/bin/mount %s:%s %s",host,rmountpt,mountpt);
break;
case cfsco: CfOut(cf_error,"","Don't understand filesystem format on SCO, no data - please fix me");
break;
case unused1:
case unused2:
case unused3:
default:
free(opts);
return false;
}
CfOut(cf_verbose,"","Verifying %s in %s\n",mountpt,VFSTAB[VSYSTEMHARDCLASS]);
if (!MatchFSInFstab(mountpt))
{
AppendItem(&FSTABLIST,fstab,NULL);
FSTAB_EDITS++;
cfPS(cf_inform,CF_CHG,"",pp,a,"Adding file system %s:%s seems to %s.\n",host,rmountpt,VFSTAB[VSYSTEMHARDCLASS]);
}
free(opts);
return 0;
}
/*******************************************************************/
int VerifyNotInFstab(char *name,struct Attributes a,struct Promise *pp)
/* Ensure filesystem is NOT in fstab, and return no of changes */
{ char regex[CF_BUFSIZE],aixcomm[CF_BUFSIZE],line[CF_BUFSIZE];
char *host,*rmountpt,*mountpt,*fstype,*opts;
FILE *pfp;
struct Item *ip;
if (!FSTABLIST)
{
if (!LoadFileAsItemList(&FSTABLIST,VFSTAB[VSYSTEMHARDCLASS],a,pp))
{
CfOut(cf_error,"","Couldn't open %s!\n",VFSTAB[VSYSTEMHARDCLASS]);
return false;
}
else
{
FSTAB_EDITS = 0;
}
}
if (a.mount.mount_options)
{
opts = Rlist2String(a.mount.mount_options,",");
}
else
{
opts = VMOUNTOPTS[VSYSTEMHARDCLASS];
}
host = a.mount.mount_server;
rmountpt = a.mount.mount_source;
mountpt = name;
fstype = a.mount.mount_type;
if (MatchFSInFstab(mountpt))
{
if (a.mount.editfstab)
{
switch (VSYSTEMHARDCLASS)
{
case aix:
snprintf(aixcomm, CF_BUFSIZE, "/usr/sbin/rmnfsmnt -f %s", mountpt);
if ((pfp = cf_popen(aixcomm,"r")) == NULL)
{
cfPS(cf_error,CF_FAIL,"",pp,a,"Failed to invoke /usr/sbin/rmnfsmnt to edit fstab");
return 0;
}
while(!feof(pfp))
{
CfReadLine(line,CF_BUFSIZE,pfp);
if (line[0] == '#')
{
continue;
}
if (strstr(line,"busy"))
{
cfPS(cf_inform,CF_INTERPT,"",pp,a,"The device under %s cannot be removed from %s\n",mountpt,VFSTAB[VSYSTEMHARDCLASS]);
return 0;
}
}
cf_pclose(pfp);
return 0; /* ignore internal editing for aix , always returns 0 changes */
break;
default:
snprintf(regex,CF_BUFSIZE,".*[\\s]+%s[\\s]+.*",mountpt);
for (ip = FSTABLIST; ip != NULL; ip=ip->next)
{
if (FullTextMatch(regex,ip->name))
{
cfPS(cf_inform,CF_CHG,"",pp,a,"Deleting file system mounted on %s.\n",host,rmountpt,VFSTAB[VSYSTEMHARDCLASS]);
// Check host name matches too?
DeleteThisItem(&FSTABLIST,ip);
FSTAB_EDITS++;
}
}
break;
}
}
}
if (a.mount.mount_options)
{
free(opts);
}
return 0;
}
/*******************************************************************/
int VerifyMount(char *name,struct Attributes a,struct Promise *pp)
{ char comm[CF_BUFSIZE],line[CF_BUFSIZE];
FILE *pfp;
char *host,*rmountpt,*mountpt,*fstype;
host = a.mount.mount_server;
rmountpt = a.mount.mount_source;
mountpt = name;
fstype = a.mount.mount_type;
if (! DONTDO)
{
snprintf(comm,CF_BUFSIZE,"%s %s:%s %s",GetArg0(VMOUNTCOMM[VSYSTEMHARDCLASS]),host,rmountpt,mountpt);
if ((pfp = cf_popen(comm,"r")) == NULL)
{
CfOut(cf_error,""," !! Failed to open pipe from %s\n",GetArg0(VMOUNTCOMM[VSYSTEMHARDCLASS]));
return 0;
}
CfReadLine(line,CF_BUFSIZE,pfp);
if (strstr(line,"busy") || strstr(line,"Busy"))
{
cfPS(cf_inform,CF_INTERPT,"",pp,a," !! The device under %s cannot be mounted\n",mountpt);
cf_pclose(pfp);
return 1;
}
cf_pclose(pfp);
}
cfPS(cf_inform,CF_CHG,"",pp,a," -> Mounting %s to keep promise\n",mountpt);
return 0;
}
/*******************************************************************/
int VerifyUnmount(char *name,struct Attributes a,struct Promise *pp)
{ char comm[CF_BUFSIZE],line[CF_BUFSIZE];
FILE *pfp;
char *host,*rmountpt,*mountpt,*fstype;
host = a.mount.mount_server;
rmountpt = a.mount.mount_source;
mountpt = name;
fstype = a.mount.mount_type;
if (! DONTDO)
{
snprintf(comm,CF_BUFSIZE,"%s %s",VUNMOUNTCOMM[VSYSTEMHARDCLASS],mountpt);
if ((pfp = cf_popen(comm,"r")) == NULL)
{
CfOut(cf_error,""," !! Failed to open pipe from %s\n",VUNMOUNTCOMM[VSYSTEMHARDCLASS]);
return 0;
}
CfReadLine(line,CF_BUFSIZE,pfp);
if (strstr(line,"busy") || strstr(line,"Busy"))
{
cfPS(cf_inform,CF_INTERPT,"",pp,a," !! The device under %s cannot be unmounted\n",mountpt);
cf_pclose(pfp);
return 1;
}
cf_pclose(pfp);
}
cfPS(cf_inform,CF_CHG,"",pp,a," -> Unmounting %s to keep promise\n",mountpt);
return 0;
}
/*******************************************************************/
static int MatchFSInFstab(char *match)
{ struct Item *ip;
for (ip = FSTABLIST; ip != NULL; ip=ip->next)
{
if (strstr(ip->name,match))
{
return true;
}
}
return false;
}
/*******************************************************************/
void MountAll()
{ struct stat sb;
char line[CF_BUFSIZE];
int fd;
FILE *pp;
if (DONTDO)
{
CfOut(cf_verbose,"","Promised to mount filesystem, but not on this trial run\n");
return;
}
else
{
CfOut(cf_verbose,""," -> Attempting to mount all filesystems.\n");
}
if (VSYSTEMHARDCLASS == cfnt)
{
/* This is a shell script. Make sure it hasn't been compromised. */
if (cfstat("/etc/fstab",&sb) == -1)
{
if ((fd = creat("/etc/fstab",0755)) > 0)
{
write(fd,"#!/bin/sh\n\n",10);
close(fd);
}
else
{
if (sb.st_mode & (S_IWOTH | S_IWGRP))
{
CfOut(cf_error,"","File /etc/fstab was insecure. Cannot mount filesystems.\n");
return;
}
}
}
}
SetTimeOut(RPCTIMEOUT);
if ((pp = cf_popen(VMOUNTCOMM[VSYSTEMHARDCLASS],"r")) == NULL)
{
CfOut(cf_error,"cf_popen","Failed to open pipe from %s\n",VMOUNTCOMM[VSYSTEMHARDCLASS]);
return;
}
while (!feof(pp))
{
if (ferror(pp)) /* abortable */
{
CfOut(cf_inform,"ferror","Error mounting filesystems\n");
break;
}
CfReadLine(line,CF_BUFSIZE,pp);
if (ferror(pp)) /* abortable */
{
CfOut(cf_inform,"ferror","Error mounting filesystems\n");
break;
}
if (strstr(line,"already mounted") || strstr(line,"exceeded") || strstr(line,"determined"))
{
continue;
}
if (strstr(line,"not supported"))
{
continue;
}
if (strstr(line,"denied") || strstr(line,"RPC"))
{
CfOut(cf_error,"","There was a mount error, trying to mount one of the filesystems on this host.\n");
break;
}
if (strstr(line,"trying") && !strstr(line,"NFS version 2")&& !strstr(line, "vers 3"))
{
CfOut(cf_error,"","Attempting abort because mount went into a retry loop.\n");
break;
}
}
alarm(0);
signal(SIGALRM,SIG_DFL);
cf_pclose(pp);
}
/*******************************************************************/
/* Addendum */
/*******************************************************************/
static void DeleteThisItem(struct Item **liststart,struct Item *entry)
{ struct Item *ip, *sp;
if (entry != NULL)
{
if (entry->name != NULL)
{
free(entry->name);
}
sp = entry->next;
if (entry == *liststart)
{
*liststart = sp;
}
else
{
for (ip = *liststart; ip->next != entry; ip=ip->next)
{
}
ip->next = sp;
}
free((char *)entry);
}
}
#endif /* NOT MINGW */
cfengine-3.2.4/src/mod_access.c 0000644 0001750 0001750 00000007520 11715232734 013263 0000000 0000000 /*
Copyright (C) Cfengine AS
This file is part of Cfengine 3 - written and maintained by Cfengine 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 Commerical Open Source License
(COSL) may apply to this file if you as a licensee so wish it. See
included file COSL.txt.
*/
/*****************************************************************************/
/* */
/* File: mod_access.c */
/* */
/*****************************************************************************/
/*
This file can act as a template for adding functionality to cfengine 3.
All functionality can be added by extending the main array
CF_MOD_SUBTYPES[CF3_MODULES]
and its array dimension, in mod_common, in the manner shown here.
*/
#define CF3_MOD_ACCESS
#include "cf3.defs.h"
#include "cf3.extern.h"
/***********************************************************/
/* Read this module file backwards, as dependencies have */
/* to be defined first - these arrays declare pairs of */
/* constraints */
/* */
/* lval => rval */
/* */
/* in the form (lval,type,range) */
/* */
/* If the type is cf_body then the range is a pointer */
/* to another array of pairs, like in a body "sub-routine" */
/* */
/***********************************************************/
/* This is the primary set of constraints for a server object */
struct BodySyntax CF_REMACCESS_BODIES[] =
{
{"admit",cf_slist,"","List of host names or IP addresses to grant access to file objects"},
{"deny",cf_slist,"","List of host names or IP addresses to deny access to file objects"},
{"maproot",cf_slist,"","List of host names or IP addresses to grant full read-privilege on the server"},
{"ifencrypted",cf_opts,CF_BOOL,"true/false whether the current file access promise is conditional on the connection from the client being encrypted"},
{"resource_type",cf_opts,"path,literal,context,query","The type of object being granted access (the default grants access to files)"},
{NULL,cf_notype,NULL,NULL}
};
/***************************************************************/
struct BodySyntax CF_REMROLE_BODIES[] =
{
{"authorize",cf_slist,"","List of public-key user names that are allowed to activate the promised class during remote agent activation"},
{NULL,cf_notype,NULL,NULL}
};
/***************************************************************/
/* This is the point of entry from mod_common.c */
/***************************************************************/
struct SubTypeSyntax CF_REMACCESS_SUBTYPES[] =
{
{"server","access",CF_REMACCESS_BODIES},
{"server","roles",CF_REMROLE_BODIES},
{NULL,NULL,NULL},
};
cfengine-3.2.4/src/exec.c 0000644 0001750 0001750 00000074033 11715232734 012112 0000000 0000000 /*
Copyright (C) Cfengine AS
This file is part of Cfengine 3 - written and maintained by Cfengine 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 Commerical Open Source License
(COSL) may apply to this file if you as a licensee so wish it. See
included file COSL.txt.
*/
/*****************************************************************************/
/* */
/* File: exec.c */
/* */
/*****************************************************************************/
#include "cf3.defs.h"
#include "cf3.extern.h"
int main (int argc,char *argv[]);
#ifdef NT
#include
#endif
/*******************************************************************/
/* GLOBAL VARIABLES */
/*******************************************************************/
int NO_FORK = false;
int ONCE = false;
char MAILTO[CF_BUFSIZE];
char MAILFROM[CF_BUFSIZE];
char EXECCOMMAND[CF_BUFSIZE];
char VMAILSERVER[CF_BUFSIZE];
struct Item *SCHEDULE = NULL;
pid_t MYTWIN = 0;
int MAXLINES = 30;
int SPLAYTIME = 0;
const int INF_LINES = -2;
int NOSPLAY = false;
int NOWINSERVICE = false;
int THREADS = 0;
extern struct BodySyntax CFEX_CONTROLBODY[];
/*******************************************************************/
void StartServer(int argc,char **argv);
int ScheduleRun(void);
void *LocalExec(void *scheduled_run);
int FileChecksum(char *filename,unsigned char digest[EVP_MAX_MD_SIZE+1],char type);
int CompareResult(char *filename,char *prev_file);
void MailResult(char *file,char *to);
int Dialogue(int sd,char *s);
void Apoptosis(void);
/*******************************************************************/
/* Command line options */
/*******************************************************************/
const char *ID = "The executor daemon is a scheduler and wrapper for\n"
"execution of cf-agent. It collects the output of the\n"
"agent and can email it to a specified address. It can\n"
"splay the start time of executions across the network\n"
"and work as a class-based clock for scheduling.";
const struct option OPTIONS[15] =
{
{ "help",no_argument,0,'h' },
{ "debug",optional_argument,0,'d' },
{ "verbose",no_argument,0,'v' },
{ "dry-run",no_argument,0,'n'},
{ "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' },
{ "no-winsrv",no_argument,0,'W' },
{ "ld-library-path",required_argument,0,'L'},
{ NULL,0,0,'\0' }
};
const char *HINTS[15] =
{
"Print the help message",
"Set debugging level 0,1,2,3",
"Output verbose information about the behaviour of the agent",
"All talk and no action mode - make no changes, only inform of promises not kept",
"Output the version of the software",
"Specify an alternative input file than the default",
"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)",
"Do not run as a service on windows - use this when running from a command shell (Cfengine Nova only)",
"Set the internal value of LD_LIBRARY_PATH for child processes",
NULL
};
/*****************************************************************************/
int main(int argc,char *argv[])
{
CheckOpts(argc,argv);
GenericInitialize(argc,argv,"executor");
ThisAgentInit();
KeepPromises();
#ifdef MINGW
if(NOWINSERVICE)
{
StartServer(argc,argv);
}
else
{
NovaWin_StartExecService();
}
#else /* NOT MINGW */
StartServer(argc,argv);
#endif /* NOT MINGW */
return 0;
}
/*****************************************************************************/
/* Level 1 */
/*****************************************************************************/
void CheckOpts(int argc,char **argv)
{ extern char *optarg;
char arg[CF_BUFSIZE];
int optindex = 0;
int c;
char ld_library_path[CF_BUFSIZE];
while ((c=getopt_long(argc,argv,"d:vnKIf:D:N:VxL:hFV1gMW",OPTIONS,&optindex)) != EOF)
{
switch ((char) c)
{
case 'f':
if (optarg && strlen(optarg) < 5)
{
snprintf(arg,CF_MAXVARSIZE," -f used but argument \"%s\" incorrect",optarg);
FatalError(arg);
}
strncpy(VINPUTFILE,optarg,CF_BUFSIZE-1);
VINPUTFILE[CF_BUFSIZE-1] = '\0';
MINUSF = true;
break;
case 'd':
NewClass("opt_debug");
switch ((optarg==NULL) ? '3' : *optarg)
{
case '1':
D1 = true;
DEBUG = true;
break;
case '2':
D2 = true;
DEBUG = true;
break;
default:
DEBUG = true;
break;
}
break;
case 'K': IGNORELOCK = true;
break;
case 'D': NewClassesFromString(optarg);
break;
case 'N':
NegateClassesFromString(optarg,&VNEGHEAP);
break;
case 'I': INFORM = true;
break;
case 'v':
VERBOSE = true;
NO_FORK = true;
break;
case 'n': DONTDO = true;
IGNORELOCK = true;
NewClass("opt_dry_run");
break;
case 'q': NOSPLAY = true;
break;
case 'L':
snprintf(ld_library_path,CF_BUFSIZE-1,"LD_LIBRARY_PATH=%s",optarg);
if (putenv(strdup(ld_library_path)) != 0)
{
}
break;
case 'W':
NOWINSERVICE = true;
break;
case 'F':
ONCE = true;
NO_FORK = true;
break;
case 'V': PrintVersionBanner("cf-execd");
exit(0);
case 'h': Syntax("cf-execd - cfengine's execution agent",OPTIONS,HINTS,ID);
exit(0);
case 'M': ManPage("cf-execd - cfengine's execution agent",OPTIONS,HINTS,ID);
exit(0);
case 'x': SelfDiagnostic();
exit(0);
default: Syntax("cf-execd - cfengine's execution agent",OPTIONS,HINTS,ID);
exit(1);
}
}
if (argv[optind] != NULL)
{
CfOut(cf_error,"","Unexpected argument with no preceding option: %s\n",argv[optind]);
}
}
/*****************************************************************************/
void ThisAgentInit()
{
umask(077);
LOGGING = true;
MAILTO[0] = '\0';
MAILFROM[0] = '\0';
VMAILSERVER[0] = '\0';
EXECCOMMAND[0] = '\0';
if (SCHEDULE == NULL)
{
AppendItem(&SCHEDULE,"Min00",NULL);
AppendItem(&SCHEDULE,"Min05",NULL);
AppendItem(&SCHEDULE,"Min10",NULL);
AppendItem(&SCHEDULE,"Min15",NULL);
AppendItem(&SCHEDULE,"Min20",NULL);
AppendItem(&SCHEDULE,"Min25",NULL);
AppendItem(&SCHEDULE,"Min30",NULL);
AppendItem(&SCHEDULE,"Min35",NULL);
AppendItem(&SCHEDULE,"Min40",NULL);
AppendItem(&SCHEDULE,"Min45",NULL);
AppendItem(&SCHEDULE,"Min50",NULL);
AppendItem(&SCHEDULE,"Min55",NULL);
}
}
/*****************************************************************************/
void KeepPromises()
{ struct Constraint *cp;
char rettype,splay[CF_BUFSIZE];
void *retval;
for (cp = ControlBodyConstraints(cf_executor); cp != NULL; cp=cp->next)
{
if (IsExcluded(cp->classes))
{
continue;
}
if (GetVariable("control_executor",cp->lval,&retval,&rettype) == cf_notype)
{
CfOut(cf_error,"","Unknown lval %s in exec control body",cp->lval);
continue;
}
if (strcmp(cp->lval,CFEX_CONTROLBODY[cfex_mailfrom].lval) == 0)
{
strcpy(MAILFROM,retval);
Debug("mailfrom = %s\n",MAILFROM);
}
if (strcmp(cp->lval,CFEX_CONTROLBODY[cfex_mailto].lval) == 0)
{
strcpy(MAILTO,retval);
Debug("mailto = %s\n",MAILTO);
}
if (strcmp(cp->lval,CFEX_CONTROLBODY[cfex_smtpserver].lval) == 0)
{
strcpy(VMAILSERVER,retval);
Debug("smtpserver = %s\n",VMAILSERVER);
}
if (strcmp(cp->lval,CFEX_CONTROLBODY[cfex_execcommand].lval) == 0)
{
strcpy(EXECCOMMAND,retval);
Debug("exec_command = %s\n",EXECCOMMAND);
}
if (strcmp(cp->lval,CFEX_CONTROLBODY[cfex_executorfacility].lval) == 0)
{
SetFacility(retval);
continue;
}
if (strcmp(cp->lval,CFEX_CONTROLBODY[cfex_mailmaxlines].lval) == 0)
{
MAXLINES = Str2Int(retval);
Debug("maxlines = %d\n",MAXLINES);
}
if (strcmp(cp->lval,CFEX_CONTROLBODY[cfex_splaytime].lval) == 0)
{
int hash,time = Str2Int(retval);
snprintf(splay,CF_BUFSIZE,"%s+%s+%d",VFQNAME,VIPADDRESS,getuid());
hash = GetHash(splay);
SPLAYTIME = (int)(time*60*hash/CF_HASHTABLESIZE);
}
if (strcmp(cp->lval,CFEX_CONTROLBODY[cfex_schedule].lval) == 0)
{
struct Rlist *rp;
Debug("schedule ...\n");
DeleteItemList(SCHEDULE);
SCHEDULE = NULL;
for (rp = (struct Rlist *) retval; rp != NULL; rp = rp->next)
{
if (!IsItemIn(SCHEDULE,rp->item))
{
AppendItem(&SCHEDULE,rp->item,NULL);
}
}
}
}
}
/*****************************************************************************/
void StartServer(int argc,char **argv)
{ int time_to_run = false;
time_t now = time(NULL);
struct Promise *pp = NewPromise("exec_cfengine","the executor agent");
struct Attributes dummyattr;
struct CfLock thislock;
Banner("Starting executor");
memset(&dummyattr,0,sizeof(dummyattr));
dummyattr.restart_class = "nonce";
dummyattr.transaction.ifelapsed = CF_EXEC_IFELAPSED;
dummyattr.transaction.expireafter = CF_EXEC_EXPIREAFTER;
if (!ONCE)
{
thislock = AcquireLock(pp->promiser,VUQNAME,CFSTARTTIME,dummyattr,pp,false);
if (thislock.lock == NULL)
{
DeletePromise(pp);
return;
}
}
Apoptosis();
#ifdef MINGW
if (!NO_FORK)
{
CfOut(cf_verbose, "", "Windows does not support starting processes in the background - starting in foreground");
}
#else /* NOT MINGW */
if ((!NO_FORK) && (fork() != 0))
{
CfOut(cf_inform,"","cf-execd starting %.24s\n",cf_ctime(&now));
exit(0);
}
if (!NO_FORK)
{
ActAsDaemon(0);
}
#endif /* NOT MINGW */
WritePID("cf-execd.pid");
signal(SIGINT,HandleSignals);
signal(SIGTERM,HandleSignals);
signal(SIGHUP,SIG_IGN);
signal(SIGPIPE,SIG_IGN);
signal(SIGUSR1,HandleSignals);
signal(SIGUSR2,HandleSignals);
umask(077);
if (ONCE)
{
CfOut(cf_verbose,"","Sleeping for splaytime %d seconds\n\n",SPLAYTIME);
sleep(SPLAYTIME);
LocalExec((void *)0);
}
else
{
#ifdef HAVE_PTHREAD_H
pthread_t tid;
#endif
#if defined NT && !(defined HAVE_LIBPTHREAD || defined BUILDTIN_GCC_THREAD)
int i;
char **nargv;
/*
* Append --once option to our arguments for spawned monitor process.
*/
nargv = malloc(sizeof(char *) * (argc+2));
for (i = 0; i < argc; i++)
{
nargv[i] = argv[i];
}
nargv[i++] = strdup("-FK");
nargv[i++] = NULL;
#endif
while (true)
{
time_to_run = ScheduleRun();
if (time_to_run)
{
CfOut(cf_verbose,"","Sleeping for splaytime %d seconds\n\n",SPLAYTIME);
sleep(SPLAYTIME);
#if defined NT && !(defined HAVE_LIBPTHREAD || defined BUILDTIN_GCC_THREAD)
/*
* Spawn a separate process - spawn will work if the cfexecd binary
* has changed (where cygwin's fork() would fail).
*/
Debug("Spawning %s\n", nargv[0]);
pid = _spawnvp((int)_P_NOWAIT,(char *)(nargv[0]),(char **)nargv);
if (pid < 1)
{
CfOut(cf_error,"_spawnvp","Can't spawn run");
}
#endif
#if (defined HAVE_LIBPTHREAD || defined BUILDTIN_GCC_THREAD)
pthread_attr_init(&PTHREADDEFAULTS);
pthread_attr_setdetachstate(&PTHREADDEFAULTS,PTHREAD_CREATE_DETACHED);
#ifdef HAVE_PTHREAD_ATTR_SETSTACKSIZE
pthread_attr_setstacksize(&PTHREADDEFAULTS,(size_t)2048*1024);
#endif
if (pthread_create(&tid,&PTHREADDEFAULTS,LocalExec,(void *)1) != 0)
{
CfOut(cf_inform,"pthread_create","Can't create thread!");
LocalExec((void *)1);
}
ThreadLock(cft_system);
pthread_attr_destroy(&PTHREADDEFAULTS);
ThreadUnlock(cft_system);
#else
LocalExec((void *)1);
#endif
}
}
}
if (!ONCE)
{
YieldCurrentLock(thislock);
}
}
/*****************************************************************************/
/* Level */
/*****************************************************************************/
void Apoptosis()
{ struct Promise pp = {0};
struct Rlist *signals = NULL, *owners = NULL;
char mypid[32];
static char promiserBuf[CF_SMALLBUF];
if (ONCE || VSYSTEMHARDCLASS == cfnt)
{
/* Otherwise we'll just kill off long jobs */
return;
}
CfOut(cf_verbose,""," !! Programmed pruning of the scheduler cluster");
#ifdef MINGW
snprintf(promiserBuf, sizeof(promiserBuf), "cf-execd"); // using '\' causes regexp problems
#else
snprintf(promiserBuf, sizeof(promiserBuf), "%s/bin/cf-execd", CFWORKDIR);
#endif
pp.promiser = promiserBuf;
pp.promisee = "cfengine";
pp.classes = "any";
pp.petype = CF_SCALAR;
pp.lineno = 0;
pp.audit = NULL;
pp.conlist = NULL;
pp.bundletype = "agent";
pp.bundle = "exec_apoptosis";
pp.ref = "Programmed death";
pp.agentsubtype = "processes";
pp.done = false;
pp.next = NULL;
pp.cache = NULL;
pp.inode_cache = NULL;
pp.this_server = NULL;
pp.donep = &(pp.done);
pp.conn = NULL;
GetCurrentUserName(mypid,31);
PrependRlist(&signals,"term",CF_SCALAR);
PrependRlist(&owners,mypid,CF_SCALAR);
AppendConstraint(&(pp.conlist),"signals",signals,CF_LIST,"any",false);
AppendConstraint(&(pp.conlist),"process_select",strdup("true"),CF_SCALAR,"any",false);
AppendConstraint(&(pp.conlist),"process_owner",owners,CF_LIST,"any",false);
AppendConstraint(&(pp.conlist),"ifelapsed",strdup("0"),CF_SCALAR,"any",false);
AppendConstraint(&(pp.conlist),"process_count",strdup("true"),CF_SCALAR,"any",false);
AppendConstraint(&(pp.conlist),"match_range",strdup("0,2"),CF_SCALAR,"any",false);
AppendConstraint(&(pp.conlist),"process_result",strdup("process_owner.process_count"),CF_SCALAR,"any",false);
CfOut(cf_verbose,""," -> Looking for cf-execd processes owned by %s",mypid);
if (LoadProcessTable(&PROCESSTABLE))
{
VerifyProcessesPromise(&pp);
}
DeleteItemList(PROCESSTABLE);
if (pp.conlist)
{
DeleteConstraintList(pp.conlist);
}
CfOut(cf_verbose,""," !! Pruning complete");
}
/*****************************************************************************/
int ScheduleRun()
{
struct Item *ip;
CfOut(cf_verbose,"","Sleeping...\n");
sleep(CFPULSETIME); /* 1 Minute resolution is enough */
// recheck license (in case of license updates or expiry)
if (EnterpriseExpiry())
{
CfOut(cf_error,"","Cfengine - autonomous configuration engine. This enterprise license is invalid.\n");
exit(1);
}
ThreadLock(cft_system);
DeleteAlphaList(&VHEAP);
InitAlphaList(&VHEAP);
DeleteAlphaList(&VADDCLASSES);
InitAlphaList(&VADDCLASSES);
DeleteItemList(IPADDRESSES);
IPADDRESSES = NULL;
DeleteScope("this");
DeleteScope("mon");
DeleteScope("sys");
NewScope("this");
NewScope("mon");
NewScope("sys");
CfGetInterfaceInfo(cf_executor);
Get3Environment();
BuiltinClasses();
OSClasses();
SetReferenceTime(true);
ThreadUnlock(cft_system);
for (ip = SCHEDULE; ip != NULL; ip = ip->next)
{
CfOut(cf_verbose,"","Checking schedule %s...\n",ip->name);
if (IsDefinedClass(ip->name))
{
CfOut(cf_verbose,"","Waking up the agent at %s ~ %s \n",cf_ctime(&CFSTARTTIME),ip->name);
return true;
}
}
return false;
}
/*************************************************************************/
void *LocalExec(void *scheduled_run)
{ FILE *pp;
char line[CF_BUFSIZE],lineEscaped[sizeof(line)*2],filename[CF_BUFSIZE],*sp;
char cmd[CF_BUFSIZE],esc_command[CF_BUFSIZE];
int print,count = 0;
void *threadName;
time_t starttime = time(NULL);
FILE *fp;
#ifdef HAVE_PTHREAD_SIGMASK
sigset_t sigmask;
sigemptyset(&sigmask);
pthread_sigmask(SIG_BLOCK,&sigmask,NULL);
#endif
#ifdef HAVE_PTHREAD
threadName = ThreadUniqueName(pthread_self());
#else
threadName = NULL;
#endif
CfOut(cf_verbose,"","------------------------------------------------------------------\n\n");
CfOut(cf_verbose,""," LocalExec(%sscheduled) at %s\n", scheduled_run ? "" : "not ", cf_ctime(&starttime));
CfOut(cf_verbose,"","------------------------------------------------------------------\n");
/* Need to make sure we have LD_LIBRARY_PATH here or children will die */
if (strlen(EXECCOMMAND) > 0)
{
strncpy(cmd,EXECCOMMAND,CF_BUFSIZE-1);
if (!strstr(EXECCOMMAND,"-Dfrom_cfexecd"))
{
strcat(EXECCOMMAND," -Dfrom_cfexecd");
}
}
else
{
struct stat sb;
int twin_exists = false;
// twin is bin-twin\cf-agent.exe on windows, bin/cf-twin on Unix
if (VSYSTEMHARDCLASS == mingw || VSYSTEMHARDCLASS == cfnt)
{
snprintf(cmd,CF_BUFSIZE-1,"%s/bin-twin/cf-agent.exe",CFWORKDIR);
MapName(cmd);
if (stat(cmd,&sb) == 0)
{
twin_exists = true;
}
if (twin_exists && IsExecutable(cmd))
{
snprintf(cmd,CF_BUFSIZE-1,"\"%s/bin-twin/cf-agent.exe\" -f failsafe.cf && \"%s/bin/cf-agent.exe%s\" -Dfrom_cfexecd%s",
CFWORKDIR,
CFWORKDIR,
NOSPLAY ? " -q" : "",
scheduled_run ? ":scheduled_run" : "");
}
else
{
snprintf(cmd,CF_BUFSIZE-1,"\"%s/bin/cf-agent.exe\" -f failsafe.cf && \"%s/bin/cf-agent.exe%s\" -Dfrom_cfexecd%s",
CFWORKDIR,
CFWORKDIR,
NOSPLAY ? " -q" : "",
scheduled_run ? ":scheduled_run" : "");
}
}
else
{
snprintf(cmd,CF_BUFSIZE-1,"%s/bin/cf-twin",CFWORKDIR);
if (stat(cmd,&sb) == 0)
{
twin_exists = true;
}
if (twin_exists && IsExecutable(cmd))
{
snprintf(cmd,CF_BUFSIZE-1,"\"%s/bin/cf-twin\" -f failsafe.cf && \"%s/bin/cf-agent%s\" -Dfrom_cfexecd%s",
CFWORKDIR,
CFWORKDIR,
NOSPLAY ? " -q" : "",
scheduled_run ? ":scheduled_run" : "");
}
else
{
snprintf(cmd,CF_BUFSIZE-1,"\"%s/bin/cf-agent\" -f failsafe.cf && \"%s/bin/cf-agent%s\" -Dfrom_cfexecd%s",
CFWORKDIR,
CFWORKDIR,
NOSPLAY ? " -q" : "",
scheduled_run ? ":scheduled_run" : "");
}
}
}
strncpy(esc_command,MapName(cmd),CF_BUFSIZE-1);
snprintf(line,CF_BUFSIZE-1,"_%d_%s",starttime,CanonifyName(cf_ctime(&starttime)));
snprintf(filename,CF_BUFSIZE-1,"%s/outputs/cf_%s_%s_%x",CFWORKDIR,CanonifyName(VFQNAME),line,threadName);
MapName(filename);
/* What if no more processes? Could sacrifice and exec() - but we need a sentinel */
if ((fp = fopen(filename,"w")) == NULL)
{
CfOut(cf_error,"fopen","!! Couldn't open \"%s\" - aborting exec\n",filename);
return NULL;
}
CfOut(cf_verbose,""," -> Command => %s\n",cmd);
if ((pp = cf_popen_sh(esc_command,"r")) == NULL)
{
CfOut(cf_error,"cf_popen","!! Couldn't open pipe to command \"%s\"\n",cmd);
fclose(fp);
return NULL;
}
CfOut(cf_verbose,""," -> Command is executing...%s\n",esc_command);
while (!feof(pp) && CfReadLine(line,CF_BUFSIZE,pp))
{
if (ferror(pp))
{
fflush(pp);
break;
}
print = false;
for (sp = line; *sp != '\0'; sp++)
{
if (!isspace((int)*sp))
{
print = true;
break;
}
}
if (print)
{
// we must escape print format chars (%) from output
ReplaceStr(line,lineEscaped,sizeof(lineEscaped),"%","%%");
fprintf(fp,"%s\n",lineEscaped);
count++;
/* If we can't send mail, log to syslog */
if (strlen(MAILTO) == 0)
{
strncat(lineEscaped,"\n",sizeof(lineEscaped)-1-strlen(lineEscaped));
if ((strchr(lineEscaped,'\n')) == NULL)
{
lineEscaped[sizeof(lineEscaped)-2] = '\n';
}
CfOut(cf_inform,"",lineEscaped);
}
line[0] = '\0';
lineEscaped[0] = '\0';
}
}
cf_pclose(pp);
Debug("Closing fp\n");
fclose(fp);
if (ONCE)
{
Cf3CloseLog();
}
CfOut(cf_verbose,""," -> Command is complete\n",cmd);
if (count)
{
CfOut(cf_verbose,""," -> Mailing result\n",cmd);
MailResult(filename,MAILTO);
}
else
{
CfOut(cf_verbose,""," -> No output\n",cmd);
unlink(filename);
}
return NULL;
}
/******************************************************************************/
/* Level 4 */
/******************************************************************************/
int FileChecksum(char *filename,unsigned char digest[EVP_MAX_MD_SIZE+1],char type)
{ FILE *file;
EVP_MD_CTX context;
int len;
unsigned int md_len;
unsigned char buffer[1024];
const EVP_MD *md = NULL;
Debug2("FileChecksum(%c,%s)\n",type,filename);
if ((file = fopen(filename,"rb")) == NULL)
{
printf ("%s can't be opened\n", filename);
}
else
{
switch (type)
{
case 's': md = EVP_get_digestbyname("sha");
break;
case 'm': md = EVP_get_digestbyname("md5");
break;
default: FatalError("Software failure in ChecksumFile");
}
if (!md)
{
return 0;
}
EVP_DigestInit(&context,md);
while ((len = fread(buffer,1,1024,file)))
{
EVP_DigestUpdate(&context,buffer,len);
}
EVP_DigestFinal(&context,digest,&md_len);
fclose (file);
return(md_len);
}
return 0;
}
/*******************************************************************/
int CompareResult(char *filename,char *prev_file)
{ int i;
unsigned char digest1[EVP_MAX_MD_SIZE+1];
unsigned char digest2[EVP_MAX_MD_SIZE+1];
int md_len1, md_len2;
FILE *fp;
int rtn = 0;
CfOut(cf_verbose,"","Comparing files %s with %s\n", prev_file, filename);
if ((fp=fopen(prev_file,"r")) != NULL)
{
fclose(fp);
md_len1 = FileChecksum(prev_file, digest1, 'm');
md_len2 = FileChecksum(filename, digest2, 'm');
if (md_len1 != md_len2)
{
rtn = 1;
}
else
{
for (i = 0; i < md_len1; i++)
{
if (digest1[i] != digest2[i])
{
rtn = 1;
break;
}
}
}
}
else
{
/* no previous file */
rtn = 1;
}
if (!ThreadLock(cft_count))
{
CfOut(cf_error, "", "!! Severe lock error when mailing in exec");
return 1;
}
/* replace old file with new*/
unlink(prev_file);
if(!LinkOrCopy(filename,prev_file,true))
{
CfOut(cf_inform,"","Could not symlink or copy %s to %s",filename,prev_file);
rtn = 1;
}
ThreadUnlock(cft_count);
return(rtn);
}
/***********************************************************************/
void MailResult(char *file,char *to)
{ int sd, sent, count = 0, anomaly = false;
char prev_file[CF_BUFSIZE],vbuff[CF_BUFSIZE];
struct hostent *hp;
struct sockaddr_in raddr;
struct servent *server;
struct stat statbuf;
time_t now = time(NULL);
FILE *fp;
CfOut(cf_verbose,"","Mail result...\n");
if (cfstat(file,&statbuf) == -1)
{
return;
}
snprintf(prev_file,CF_BUFSIZE-1,"%s/outputs/previous",CFWORKDIR);
MapName(prev_file);
if (statbuf.st_size == 0)
{
unlink(file);
Debug("Nothing to report in %s\n",file);
return;
}
if (CompareResult(file,prev_file) == 0)
{
CfOut(cf_verbose,"","Previous output is the same as current so do not mail it\n");
return;
}
if ((strlen(VMAILSERVER) == 0) || (strlen(to) == 0))
{
/* Syslog should have done this */
CfOut(cf_verbose, "", "Empty mail server or address - skipping");
return;
}
if (MAXLINES == 0)
{
Debug("Not mailing: EmailMaxLines was zero\n");
return;
}
Debug("Mailing results of (%s) to (%s)\n",file,to);
/* Check first for anomalies - for subject header */
if ((fp = fopen(file,"r")) == NULL)
{
CfOut(cf_inform,"fopen","!! Couldn't open file %s",file);
return;
}
while (!feof(fp))
{
vbuff[0] = '\0';
fgets(vbuff,CF_BUFSIZE,fp);
if (strstr(vbuff,"entropy"))
{
anomaly = true;
break;
}
}
fclose(fp);
if ((fp = fopen(file,"r")) == NULL)
{
CfOut(cf_inform,"fopen","Couldn't open file %s",file);
return;
}
Debug("Looking up hostname %s\n\n",VMAILSERVER);
if ((hp = gethostbyname(VMAILSERVER)) == NULL)
{
printf("Unknown host: %s\n", VMAILSERVER);
printf("Make sure that fully qualified names can be looked up at your site.\n");
fclose(fp);
return;
}
if ((server = getservbyname("smtp","tcp")) == NULL)
{
CfOut(cf_inform,"getservbyname","Unable to lookup smtp service");
fclose(fp);
return;
}
memset(&raddr,0,sizeof(raddr));
raddr.sin_port = (unsigned int) server->s_port;
raddr.sin_addr.s_addr = ((struct in_addr *)(hp->h_addr))->s_addr;
raddr.sin_family = AF_INET;
Debug("Connecting...\n");
if ((sd = socket(AF_INET,SOCK_STREAM,0)) == -1)
{
CfOut(cf_inform,"socket","Couldn't open a socket");
fclose(fp);
return;
}
if (connect(sd,(void *) &raddr,sizeof(raddr)) == -1)
{
CfOut(cf_inform,"connect","Couldn't connect to host %s\n",VMAILSERVER);
fclose(fp);
cf_closesocket(sd);
return;
}
/* read greeting */
if (!Dialogue(sd,NULL))
{
goto mail_err;
}
sprintf(vbuff,"HELO %s\r\n",VFQNAME);
Debug("%s",vbuff);
if (!Dialogue(sd,vbuff))
{
goto mail_err;
}
if (strlen(MAILFROM) == 0)
{
sprintf(vbuff,"MAIL FROM: \r\n",VFQNAME);
Debug("%s",vbuff);
}
else
{
sprintf(vbuff,"MAIL FROM: <%s>\r\n",MAILFROM);
Debug("%s",vbuff);
}
if (!Dialogue(sd,vbuff))
{
goto mail_err;
}
sprintf(vbuff,"RCPT TO: <%s>\r\n",to);
Debug("%s",vbuff);
if (!Dialogue(sd,vbuff))
{
goto mail_err;
}
if (!Dialogue(sd,"DATA\r\n"))
{
goto mail_err;
}
if (anomaly)
{
sprintf(vbuff,"Subject: %s **!! [%s/%s]\r\n",MailSubject(),VFQNAME,VIPADDRESS);
Debug("%s",vbuff);
}
else
{
sprintf(vbuff,"Subject: %s [%s/%s]\r\n",MailSubject(),VFQNAME,VIPADDRESS);
Debug("%s",vbuff);
}
sent = send(sd,vbuff,strlen(vbuff),0);
#if defined LINUX || defined NETBSD || defined FREEBSD || defined OPENBSD
strftime(vbuff,CF_BUFSIZE,"Date: %a, %d %b %Y %H:%M:%S %z\r\n",localtime(&now));
sent=send(sd,vbuff,strlen(vbuff),0);
#endif
if (strlen(MAILFROM) == 0)
{
sprintf(vbuff,"From: cfengine@%s\r\n",VFQNAME);
Debug("%s",vbuff);
}
else
{
sprintf(vbuff,"From: %s\r\n",MAILFROM);
Debug("%s",vbuff);
}
sent = send(sd,vbuff,strlen(vbuff),0);
sprintf(vbuff,"To: %s\r\n\r\n",to);
Debug("%s",vbuff);
sent = send(sd,vbuff,strlen(vbuff),0);
while(!feof(fp))
{
vbuff[0] = '\0';
fgets(vbuff,CF_BUFSIZE,fp);
Debug("%s",vbuff);
if (strlen(vbuff) > 0)
{
vbuff[strlen(vbuff)-1] = '\r';
strcat(vbuff, "\n");
count++;
sent = send(sd,vbuff,strlen(vbuff),0);
}
if ((MAXLINES != INF_LINES) && (count > MAXLINES))
{
sprintf(vbuff,"\r\n[Mail truncated by cfengine. File is at %s on %s]\r\n",file,VFQNAME);
sent = send(sd,vbuff,strlen(vbuff),0);
break;
}
}
if (!Dialogue(sd,".\r\n"))
{
Debug("mail_err\n");
goto mail_err;
}
Dialogue(sd,"QUIT\r\n");
Debug("Done sending mail\n");
fclose(fp);
cf_closesocket(sd);
return;
mail_err:
fclose(fp);
cf_closesocket(sd);
CfOut(cf_log,"","Cannot mail to %s.", to);
}
/******************************************************************/
/* Level 5 */
/******************************************************************/
int Dialogue(int sd,char *s)
{ int sent;
char ch,f = '\0';
int charpos,rfclinetype = ' ';
if ((s != NULL) && (*s != '\0'))
{
sent = send(sd,s,strlen(s),0);
Debug("SENT(%d)->%s",sent,s);
}
else
{
Debug("Nothing to send .. waiting for opening\n");
}
charpos = 0;
while (recv(sd,&ch,1,0))
{
charpos++;
if (f == '\0')
{
f = ch;
}
if (charpos == 4) /* Multiline RFC in form 222-Message with hyphen at pos 4 */
{
rfclinetype = ch;
}
Debug("%c",ch);
if (ch == '\n' || ch == '\0')
{
charpos = 0;
if (rfclinetype == ' ')
{
break;
}
}
}
return ((f == '2') || (f == '3')); /* return code 200 or 300 from smtp*/
}
/* EOF */
cfengine-3.2.4/src/signals.c 0000644 0001750 0001750 00000005173 11715232734 012625 0000000 0000000 /*
Copyright (C) Cfengine AS
This file is part of Cfengine 3 - written and maintained by Cfengine 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 Commerical Open Source License
(COSL) may apply to this file if you as a licensee so wish it. See
included file COSL.txt.
*/
/*****************************************************************************/
/* */
/* File: signals.c */
/* */
/*****************************************************************************/
#include "cf3.defs.h"
#include "cf3.extern.h"
void HandleSignals(int signum)
{
if (signum != SIGCHLD)
{
CfOut(cf_error,"","Received signal %d (%s) while doing [%s]",signum,SIGNALS[signum],CFLOCK);
CfOut(cf_error,"","Logical start time %s ",cf_ctime(&CFSTARTTIME));
CfOut(cf_error,"","This sub-task started really at %s\n",cf_ctime(&CFINITSTARTTIME));
fflush(stdout);
if (signum == SIGTERM || signum == SIGINT || signum == SIGHUP || signum == SIGSEGV || signum == SIGKILL|| signum == SIGPIPE)
{
SelfTerminatePrelude();
exit(0);
}
else if (signum == SIGUSR1)
{
DEBUG= true;
D2= true;
}
else if (signum == SIGUSR2)
{
DEBUG= false;
D2= false;
}
else /* zombie cleanup - how hard does it have to be? */
{
}
/* Reset the signal handler */
signal(signum,HandleSignals);
}
}
/*****************************************************************************/
void SelfTerminatePrelude()
{
struct CfLock best_guess;
CfOut(cf_verbose,"","Trying to remove lock - try %s",CFLOCK);
best_guess.lock = strdup(CFLOCK);
best_guess.last = strdup(CFLAST);
best_guess.log = strdup(CFLOG);
YieldCurrentLock(best_guess);
unlink(PIDFILE);
EndAudit();
GenericDeInitialize();
}
cfengine-3.2.4/src/compiler.h 0000644 0001750 0001750 00000002354 11715232734 013002 0000000 0000000 /*
Copyright (C) Cfengine AS
This file is part of Cfengine 3 - written and maintained by Cfengine 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 Commerical Open Source License
(COSL) may apply to this file if you as a licensee so wish it. See
included file COSL.txt.
*/
#ifndef CFENGINE_COMPILER_H
#define CFENGINE_COMPILER_H
/* Compiler-specific options/defines */
#if defined(__GNUC__) && (__GNUC__ * 100 >= 3)
# define FUNC_ATTR_NORETURN __attribute__((noreturn))
#else /* not gcc >= 3.0 */
# define FUNC_ATTR_NORETURN
#endif
#endif
cfengine-3.2.4/src/instrumentation.c 0000644 0001750 0001750 00000033747 11715232734 014440 0000000 0000000 /*
Copyright (C) Cfengine AS
This file is part of Cfengine 3 - written and maintained by Cfengine 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 Commerical Open Source License
(COSL) may apply to this file if you as a licensee so wish it. See
included file COSL.txt.
*/
/*****************************************************************************/
/* */
/* File: instrumentation.c */
/* */
/*****************************************************************************/
#include "cf3.defs.h"
#include "cf3.extern.h"
#include
static void NotePerformance(char *eventname,time_t t,double value);
static void UpdateLastSawHost(char *rkey,char *ipaddress);
static void PurgeMultipleIPReferences(CF_DB *dbp,char *rkey,char *ipaddress);
/* Alter this code at your peril. Berkeley DB is very sensitive to errors. */
/***************************************************************/
struct timespec BeginMeasure()
{ struct timespec start;
if (clock_gettime(CLOCK_REALTIME, &start) == -1)
{
CfOut(cf_verbose,"clock_gettime","Clock gettime failure");
}
return start;
}
/***************************************************************/
void EndMeasurePromise(struct timespec start,struct Promise *pp)
{ char id[CF_BUFSIZE], *mid = NULL;
mid = GetConstraint("measurement_class",pp,CF_SCALAR);
if (mid)
{
snprintf(id,CF_BUFSIZE,"%s:%s:%.100s",(char *)mid,pp->agentsubtype,pp->promiser);
Chop(id);
EndMeasure(id,start);
}
}
/***************************************************************/
void EndMeasure(char *eventname,struct timespec start)
{ struct timespec stop;
int measured_ok = true;
double dt;
if (clock_gettime(CLOCK_REALTIME, &stop) == -1)
{
CfOut(cf_verbose,"clock_gettime","Clock gettime failure");
measured_ok = false;
}
dt = (double)(stop.tv_sec - start.tv_sec)+(double)(stop.tv_nsec-start.tv_nsec)/(double)CF_BILLION;
if (measured_ok)
{
NotePerformance(eventname,start.tv_sec,dt);
}
}
/***************************************************************/
static void NotePerformance(char *eventname,time_t t,double value)
{ CF_DB *dbp;
char name[CF_BUFSIZE];
struct Event e,newe;
double lastseen,delta2;
int lsea = CF_WEEK;
time_t now = time(NULL);
Debug("PerformanceEvent(%s,%.1f s)\n",eventname,value);
snprintf(name,CF_BUFSIZE-1,"%s/%s",CFWORKDIR,CF_PERFORMANCE);
if (!OpenDB(name,&dbp))
{
return;
}
if (ReadDB(dbp,eventname,&e,sizeof(e)))
{
lastseen = now - e.t;
newe.t = t;
newe.Q.q = value;
newe.Q.expect = GAverage(value,e.Q.expect,0.3);
delta2 = (value - e.Q.expect)*(value - e.Q.expect);
newe.Q.var = GAverage(delta2,e.Q.var,0.3);
/* Have to kickstart variance computation, assume 1% to start */
if (newe.Q.var <= 0.0009)
{
newe.Q.var = newe.Q.expect / 100.0;
}
}
else
{
lastseen = 0.0;
newe.t = t;
newe.Q.q = value;
newe.Q.expect = value;
newe.Q.var = 0.001;
}
if (lastseen > (double)lsea)
{
Debug("Performance record %s expired\n",eventname);
DeleteDB(dbp,eventname);
}
else
{
CfOut(cf_verbose,"","Performance(%s): time=%.4lf secs, av=%.4lf +/- %.4lf\n",eventname,value,newe.Q.expect,sqrt(newe.Q.var));
WriteDB(dbp,eventname,&newe,sizeof(newe));
}
CloseDB(dbp);
}
/***************************************************************/
void NoteClassUsage(struct AlphaList baselist)
{ CF_DB *dbp;
CF_DBC *dbcp;
void *stored;
char *key,name[CF_BUFSIZE];
int i,j,ksize,vsize;
struct Event e,entry,newe;
double lsea = CF_WEEK * 52; /* expire after a year */
time_t now = time(NULL);
struct Item *ip,*list = NULL;
double lastseen,delta2;
double vtrue = 1.0; /* end with a rough probability */
/* Only do this for the default policy, too much "downgrading" otherwise */
if (MINUSF)
{
return;
}
Debug("RecordClassUsage\n");
for (i = 0; i < CF_ALPHABETSIZE; i++)
{
for (ip = baselist.list[i]; ip != NULL; ip=ip->next)
{
if (IGNORECLASS(ip->name))
{
Debug("Ignoring class %s (not packing)", ip->name);
continue;
}
for (j = 0; j < 4; j++)
{
if (strcmp(ip->name,SHIFT_TEXT[j]) == 0)
{
continue;
}
}
for (j = 0; j < 7; j++)
{
if (strcmp(ip->name,DAY_TEXT[j]) == 0)
{
continue;
}
}
for (j = 0; j < 12; j++)
{
if (strcmp(ip->name,MONTH_TEXT[j]) == 0)
{
continue;
}
}
IdempPrependItem(&list,ip->name,NULL);
}
}
snprintf(name,CF_BUFSIZE-1,"%s/%s",CFWORKDIR,CF_CLASSUSAGE);
MapName(name);
if (!OpenDB(name,&dbp))
{
return;
}
/* First record the classes that are in use */
for (ip = list; ip != NULL; ip=ip->next)
{
if (ReadDB(dbp,ip->name,&e,sizeof(e)))
{
lastseen = now - e.t;
newe.t = now;
newe.Q.q = vtrue;
newe.Q.expect = GAverage(vtrue,e.Q.expect,0.7);
delta2 = (vtrue - e.Q.expect)*(vtrue - e.Q.expect);
newe.Q.var = GAverage(delta2,e.Q.var,0.7);
}
else
{
lastseen = 0.0;
newe.t = now;
newe.Q.q = 0.5*vtrue;
newe.Q.expect = 0.5*vtrue; /* With no data it's 50/50 what we can say */
newe.Q.var = 0.000;
}
if (lastseen > lsea)
{
Debug("Class usage record %s expired\n",ip->name);
DeleteDB(dbp,ip->name);
}
else
{
Debug("Upgrading %s %f\n",ip->name,newe.Q.expect);
WriteDB(dbp,ip->name,&newe,sizeof(newe));
}
}
/* Then update with zero the ones we know about that are not active */
/* Acquire a cursor for the database. */
if (!NewDBCursor(dbp,&dbcp))
{
CfOut(cf_inform,""," !! Unable to scan class db");
CloseDB(dbp);
DeleteItemList(list);
return;
}
memset(&entry, 0, sizeof(entry));
OpenDBTransaction(dbp);
while(NextDB(dbp,dbcp,&key,&ksize,&stored,&vsize))
{
double measure,av,var;
time_t then;
char eventname[CF_BUFSIZE];
memset(eventname,0,CF_BUFSIZE);
strncpy(eventname,(char *)key,ksize);
if (stored != NULL)
{
memcpy(&entry,stored,sizeof(entry));
then = entry.t;
measure = entry.Q.q;
av = entry.Q.expect;
var = entry.Q.var;
lastseen = now - then;
if (lastseen > lsea)
{
Debug("Class usage record %s expired\n",eventname);
DeleteDB(dbp,eventname);
}
else if (!IsItemIn(list,eventname))
{
newe.t = then;
newe.Q.q = 0;
newe.Q.expect = GAverage(0.0,av,0.5);
delta2 = av*av;
newe.Q.var = GAverage(delta2,var,0.5);
Debug("Downgrading class %s from %lf to %lf\n",eventname,entry.Q.expect,newe.Q.expect);
WriteDB(dbp,eventname,&newe,sizeof(newe));
}
}
}
CommitDBTransaction(dbp);
DeleteDBCursor(dbp,dbcp);
CloseDB(dbp);
DeleteItemList(list);
}
/***************************************************************/
/* Last saw handling */
/***************************************************************/
void LastSaw(char *username,char *ipaddress,unsigned char digest[EVP_MAX_MD_SIZE+1],enum roles role)
{ char databuf[CF_BUFSIZE];
time_t now = time(NULL);
int known = false;
char *mapip;
if (strlen(ipaddress) == 0)
{
CfOut(cf_inform,"","LastSeen registry for empty IP with role %d",role);
return;
}
ThreadLock(cft_output);
switch (role)
{
case cf_accept:
snprintf(databuf,CF_BUFSIZE-1,"-%s",HashPrint(CF_DEFAULT_DIGEST,digest));
break;
case cf_connect:
snprintf(databuf,CF_BUFSIZE-1,"+%s",HashPrint(CF_DEFAULT_DIGEST,digest));
break;
}
ThreadUnlock(cft_output);
mapip = MapAddress(ipaddress);
UpdateLastSawHost(databuf,mapip);
}
/*****************************************************************************/
static void UpdateLastSawHost(char *rkey,char *ipaddress)
{ CF_DB *dbpent = NULL,*dbp = NULL;
struct CfKeyHostSeen q,newq;
double lastseen,delta2;
void *stored;
char name[CF_BUFSIZE],*key;
time_t now = time(NULL);
int intermittency = false;
char timebuf[26];
if (BooleanControl("control_agent",CFA_CONTROLBODY[cfa_intermittency].lval))
{
CfOut(cf_inform,""," -> Recording intermittency");
intermittency = true;
}
snprintf(name,CF_BUFSIZE-1,"%s/%s",CFWORKDIR,CF_LASTDB_FILE);
MapName(name);
if (!OpenDB(name,&dbp))
{
CfOut(cf_inform,""," !! Unable to open last seen db");
return;
}
if (intermittency)
{
/* Open special file for peer entropy record - INRIA-like intermittency */
snprintf(name,CF_BUFSIZE-1,"%s/lastseen/%s.%s",CFWORKDIR,CF_LASTDB_FILE,rkey);
MapName(name);
if (!OpenDB(name,&dbpent))
{
intermittency = false;
}
}
if (ReadDB(dbp,rkey,&q,sizeof(q)))
{
lastseen = (double)now - q.Q.q;
if (q.Q.q <= 0)
{
lastseen = 300;
q.Q.expect = 0;
q.Q.var = 0;
}
newq.Q.q = (double)now;
newq.Q.expect = GAverage(lastseen,q.Q.expect,0.4);
delta2 = (lastseen - q.Q.expect)*(lastseen - q.Q.expect);
newq.Q.var = GAverage(delta2,q.Q.var,0.4);
strncpy(newq.address,ipaddress,CF_ADDRSIZE-1);
}
else
{
lastseen = 0.0;
newq.Q.q = (double)now;
newq.Q.expect = 0.0;
newq.Q.var = 0.0;
strncpy(newq.address,ipaddress,CF_ADDRSIZE-1);
}
if (strcmp(rkey+1,PUBKEY_DIGEST) == 0)
{
struct Item *ip;
int match = false;
for (ip = IPADDRESSES; ip != NULL; ip=ip->next)
{
if (strcmp(ipaddress,ip->name) == 0)
{
match = true;
}
}
if (!match)
{
CfOut(cf_verbose,""," ! Not updating last seen, as this appears to be a host with a duplicate key");
CloseDB(dbp);
if (intermittency && dbpent)
{
CloseDB(dbpent);
}
return;
}
}
CfOut(cf_verbose,""," -> Last saw %s (alias %s) at %s\n",rkey,ipaddress,cf_strtimestamp_local(now,timebuf));
PurgeMultipleIPReferences(dbp,rkey,ipaddress);
WriteDB(dbp,rkey,&newq,sizeof(newq));
if (intermittency)
{
WriteDB(dbpent,GenTimeKey(now),&newq,sizeof(newq));
}
if (intermittency && dbpent)
{
CloseDB(dbpent);
}
CloseDB(dbp);
}
/*****************************************************************************/
bool RemoveHostFromLastSeen(const char *hostname, char *hostkey)
{
char ip[CF_BUFSIZE];
char digest[CF_BUFSIZE]={0};
if(!hostkey)
{
strcpy(ip, Hostname2IPString(hostname));
IPString2KeyDigest(ip, digest);
}
else
{
snprintf(digest,sizeof(digest),"%s",hostkey);
}
CF_DB *dbp;
char name[CF_BUFSIZE], key[CF_BUFSIZE];
snprintf(name,CF_BUFSIZE-1,"%s/%s",CFWORKDIR,CF_LASTDB_FILE);
MapName(name);
if (!OpenDB(name, &dbp))
{
CfOut(cf_error, "", " !! Unable to open last seen DB");
return false;
}
snprintf(key, CF_BUFSIZE, "-%s", digest);
DeleteComplexKeyDB(dbp, key, strlen(key) + 1);
snprintf(key, CF_BUFSIZE, "+%s", digest);
DeleteComplexKeyDB(dbp, key, strlen(key) + 1);
CloseDB(dbp);
return true;
}
/*****************************************************************************/
static void PurgeMultipleIPReferences(CF_DB *dbp,char *rkey,char *ipaddress)
{ CF_DBC *dbcp;
struct CfKeyHostSeen q,newq;
double lastseen,delta2,lsea = LASTSEENEXPIREAFTER;
void *stored;
char name[CF_BUFSIZE],*key;
time_t now = time(NULL);
int qsize,ksize,update_address,keys_match;
// This is an expensive call, but it is the price we pay for consistency
// Make sure we only call it if we have to
if (!NewDBCursor(dbp,&dbcp))
{
CfOut(cf_inform,""," !! Unable to scan the last seen db");
return;
}
while(NextDB(dbp,dbcp,&key,&ksize,&stored,&qsize))
{
keys_match = false;
if (strcmp(key+1,rkey+1) == 0)
{
keys_match = true;
}
memcpy(&q,stored,sizeof(q));
lastseen = (double)now - q.Q.q;
if (lastseen > lsea)
{
CfOut(cf_verbose,""," -> Last-seen record for %s expired after %.1lf > %.1lf hours\n",key,lastseen/3600,lsea/3600);
DeleteDB(dbp,key);
continue;
}
// Avoid duplicate address/key pairs
if (keys_match && strcmp(q.address,ipaddress) != 0)
{
CfOut(cf_verbose,""," ! Synchronizing %s's address as this host %s seems to have moved from location %s to %s",key,rkey,q.address,ipaddress);
strcpy(q.address,ipaddress);
update_address = true;
}
else if (!keys_match && strcmp(q.address,ipaddress) == 0)
{
CfOut(cf_verbose,""," ! Updating %s's address (%s) as this host %s seems to have gone off line",key,ipaddress,rkey);
strcpy(q.address,CF_UNKNOWN_IP);
update_address = true;
}
else
{
update_address = false;
}
if (update_address)
{
WriteDB(dbp,key,&q,sizeof(q));
}
}
DeleteDBCursor(dbp,dbcp);
}
/*****************************************************************************/
/* Toolkit */
/*****************************************************************************/
double GAverage(double anew,double aold,double p)
/* return convex mixture - p is the trust/confidence in the new value */
{
return (p*anew + (1.0-p)*aold);
}
cfengine-3.2.4/src/verify_services.c 0000644 0001750 0001750 00000007771 11715232734 014402 0000000 0000000 /*
Copyright (C) Cfengine AS
This file is part of Cfengine 3 - written and maintained by Cfengine 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 Commerical Open Source License
(COSL) may apply to this file if you as a licensee so wish it. See
included file COSL.txt.
*/
/*****************************************************************************/
/* */
/* File: verify_services.c */
/* */
/*****************************************************************************/
#include "cf3.defs.h"
#include "cf3.extern.h"
static int ServicesSanityChecks(struct Attributes a,struct Promise *pp);
static void SetServiceDefaults(struct Attributes *a);
/*****************************************************************************/
void VerifyServicesPromise(struct Promise *pp)
{ struct Attributes a = {{0}};
a = GetServicesAttributes(pp);
SetServiceDefaults(&a);
if (ServicesSanityChecks(a,pp))
{
VerifyServices(a,pp);
}
}
/*****************************************************************************/
static int ServicesSanityChecks(struct Attributes a,struct Promise *pp)
{ struct Rlist *dep;
switch(a.service.service_policy)
{
case cfsrv_start:
break;
case cfsrv_stop:
case cfsrv_disable:
if(strcmp(a.service.service_autostart_policy, "none") != 0)
{
CfOut(cf_error,"","!! Autostart policy of service promiser \"%s\" needs to be \"none\" when service policy is not \"start\", but is \"%s\"",
pp->promiser, a.service.service_autostart_policy);
PromiseRef(cf_error,pp);
return false;
}
break;
default:
CfOut(cf_error,"","!! Invalid service policy for service \"%s\"", pp->promiser);
PromiseRef(cf_error,pp);
return false;
}
for(dep = a.service.service_depend; dep != NULL; dep = dep->next)
{
if(strcmp(pp->promiser, dep->item) == 0)
{
CfOut(cf_error,"","!! Service promiser \"%s\" has itself as dependency", pp->promiser);
PromiseRef(cf_error,pp);
return false;
}
}
if(a.service.service_type == NULL)
{
CfOut(cf_error,"","!! Service type for service \"%s\" is not known", pp->promiser);
PromiseRef(cf_error,pp);
return false;
}
#ifdef MINGW
if(strcmp(a.service.service_type, "windows") != 0)
{
CfOut(cf_error,"","!! Service type for promiser \"%s\" must be \"windows\" on this system, but is \"%s\"", pp->promiser, a.service.service_type);
PromiseRef(cf_error,pp);
return false;
}
#endif /* MINGW */
return true;
}
/*****************************************************************************/
static void SetServiceDefaults(struct Attributes *a)
{
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 MINGW
if(a->service.service_type == NULL)
{
a->service.service_type = "windows";
}
#endif /* MINGW */
}
cfengine-3.2.4/src/communication.c 0000644 0001750 0001750 00000020455 11715232734 014032 0000000 0000000 /*
Copyright (C) Cfengine AS
This file is part of Cfengine 3 - written and maintained by Cfengine 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 Commerical Open Source License
(COSL) may apply to this file if you as a licensee so wish it. See
included file COSL.txt.
*/
/*******************************************************************/
/* */
/* IP layers */
/* */
/*******************************************************************/
#include "cf3.defs.h"
#include "cf3.extern.h"
static char *IPString2UQHostname(char *ipaddress);
/*********************************************************************/
struct cfagent_connection *NewAgentConn()
{ struct cfagent_connection *ap;
if ((ap = (struct cfagent_connection *)malloc(sizeof(struct cfagent_connection))) == NULL)
{
return NULL;
}
Debug("New server connection...\n");
ap->sd = (int)CF_NOT_CONNECTED;
ap->family = AF_INET;
ap->trust = false;
ap->localip[0] = '\0';
ap->remoteip[0] = '\0';
ap->session_key = NULL;
ap->encryption_type = 'c';
ap->error = false;
return ap;
};
/*********************************************************************/
void DeleteAgentConn(struct cfagent_connection *ap)
{
if (ap->session_key != NULL)
{
free(ap->session_key);
}
free(ap);
ap = NULL;
}
/**********************************************************************/
void DePort(char *address)
{ char *sp,*chop,*fc = NULL,*fd = NULL,*ld = NULL;
int ccount = 0, dcount = 0;
/* Start looking for ethernet/ipv6 addresses */
for (sp = address; *sp != '\0'; sp++)
{
if (*sp == ':')
{
if (!fc)
{
fc = sp;
}
ccount++;
}
if (*sp == '.')
{
if (!fd)
{
fd = sp;
}
ld = sp;
dcount++;
}
}
if (!fd)
{
/* This does not look like an IP address+port, maybe ethernet */
return;
}
if (dcount == 4)
{
chop = ld;
}
else if (dcount > 1 && fc != NULL)
{
chop = fc;
}
else if (ccount > 1 && fd != NULL)
{
chop = fd;
}
else
{
/* Don't recognize address */
return;
}
if (chop < address+strlen(address))
{
*chop = '\0';
}
return;
}
/*******************************************************************/
int IsIPV6Address(char *name)
{ char *sp;
int count,max = 0;
Debug("IsIPV6Address(%s)\n",name);
if (name == NULL)
{
return false;
}
count = 0;
for (sp = name; *sp != '\0'; sp++)
{
if (isalnum((int)*sp))
{
count++;
}
else if ((*sp != ':') && (*sp != '.'))
{
return false;
}
if (*sp == 'r')
{
return false;
}
if (count > max)
{
max = count;
}
else
{
count = 0;
}
}
if (max <= 2)
{
Debug("Looks more like a MAC address");
return false;
}
if (strstr(name,":") == NULL)
{
return false;
}
if (StrStr(name,"scope"))
{
return false;
}
return true;
}
/*******************************************************************/
int IsIPV4Address(char *name)
{ char *sp;
int count = 0;
Debug("IsIPV4Address(%s)\n",name);
if (name == NULL)
{
return false;
}
for (sp = name; *sp != '\0'; sp++)
{
if (!isdigit((int)*sp) && (*sp != '.'))
{
return false;
}
if (*sp == '.')
{
count++;
}
}
if (count != 3)
{
return false;
}
return true;
}
/*****************************************************************************/
const char *Hostname2IPString(const char *hostname)
{ static char ipbuffer[CF_SMALLBUF];
int err;
#if defined(HAVE_GETADDRINFO)
struct addrinfo query, *response, *ap;
memset(&query,0,sizeof(struct addrinfo));
query.ai_family = AF_UNSPEC;
query.ai_socktype = SOCK_STREAM;
memset(ipbuffer,0,CF_SMALLBUF-1);
if ((err = getaddrinfo(hostname,NULL,&query,&response)) != 0)
{
CfOut(cf_inform,"","Unable to lookup hostname (%s) or cfengine service: %s",hostname,gai_strerror(err));
return hostname;
}
for (ap = response; ap != NULL; ap = ap->ai_next)
{
strncpy(ipbuffer,sockaddr_ntop(ap->ai_addr),64);
Debug("Found address (%s) for host %s\n",ipbuffer,hostname);
if (strlen(ipbuffer) == 0)
{
snprintf(ipbuffer,CF_SMALLBUF-1,"Empty IP result for %s",hostname);
}
freeaddrinfo(response);
return ipbuffer;
}
#else
struct hostent *hp;
struct sockaddr_in cin;
memset(&cin,0,sizeof(cin));
memset(ipbuffer,0,CF_SMALLBUF-1);
if ((hp = gethostbyname(hostname)) != NULL)
{
cin.sin_addr.s_addr = ((struct in_addr *)(hp->h_addr))->s_addr;
strncpy(ipbuffer,inet_ntoa(cin.sin_addr),CF_SMALLBUF-1);
CfOut(cf_verbose,"","Found address (%s) for host %s\n",ipbuffer,hostname);
return ipbuffer;
}
#endif
snprintf(ipbuffer,CF_SMALLBUF-1,"Unknown IP %s",hostname);
return ipbuffer;
}
/*****************************************************************************/
char *IPString2Hostname(char *ipaddress)
{ static char hostbuffer[MAXHOSTNAMELEN];
int err;
#if defined(HAVE_GETADDRINFO)
struct addrinfo query, *response, *ap;
memset(&query,0,sizeof(query));
memset(&response,0,sizeof(response));
query.ai_flags = AI_CANONNAME;
memset(hostbuffer,0,MAXHOSTNAMELEN);
if ((err = getaddrinfo(ipaddress,NULL,&query,&response)) != 0)
{
CfOut(cf_inform,"","Unable to lookup IP address (%s): %s",ipaddress,gai_strerror(err));
snprintf(hostbuffer,MAXHOSTNAMELEN,ipaddress);
return hostbuffer;
}
for (ap = response; ap != NULL; ap = ap->ai_next)
{
if ((err = getnameinfo(ap->ai_addr,ap->ai_addrlen,hostbuffer,MAXHOSTNAMELEN,0,0,0)) != 0)
{
snprintf(hostbuffer,MAXHOSTNAMELEN,ipaddress);
freeaddrinfo(response);
return hostbuffer;
}
Debug("Found address (%s) for host %s\n",hostbuffer,ipaddress);
freeaddrinfo(response);
return hostbuffer;
}
snprintf(hostbuffer,MAXHOSTNAMELEN-1,ipaddress);
#else
struct hostent *hp;
struct sockaddr_in myaddr;
struct in_addr iaddr;
memset(hostbuffer,0,MAXHOSTNAMELEN);
if ((iaddr.s_addr = inet_addr(ipaddress)) != -1)
{
hp = gethostbyaddr((void *)&iaddr,sizeof(struct sockaddr_in),AF_INET);
if ((hp == NULL) || (hp->h_name == NULL))
{
strcpy(hostbuffer,ipaddress);
return hostbuffer;
}
strncpy(hostbuffer,hp->h_name,MAXHOSTNAMELEN-1);
}
else
{
strcpy(hostbuffer,"(non registered IP)");
}
#endif
return hostbuffer;
}
/*****************************************************************************/
static char *IPString2UQHostname(char *ipaddress)
/* Return an unqualified hostname */
{ static char hostbuffer[MAXHOSTNAMELEN];
char *sp;
strcpy(hostbuffer,IPString2Hostname(ipaddress));
for (sp = hostbuffer; *sp != '\0'; sp++)
{
if (*sp == '.')
{
*sp = '\0';
break;
}
}
return hostbuffer;
}
/*****************************************************************************/
int GetMyHostInfo(char nameBuf[MAXHOSTNAMELEN], char ipBuf[MAXIP4CHARLEN])
{ char *ip;
struct hostent *hostinfo;
if (gethostname(nameBuf, MAXHOSTNAMELEN) == 0)
{
if ((hostinfo = gethostbyname(nameBuf)) != NULL)
{
ip = inet_ntoa(*(struct in_addr *)*hostinfo->h_addr_list);
strncpy(ipBuf, ip, MAXIP4CHARLEN - 1);
ipBuf[MAXIP4CHARLEN - 1] = '\0';
return true;
}
else
{
CfOut(cf_error, "gethostbyname", "!! Could not get host entry for local host");
}
}
else
{
CfOut(cf_error, "gethostname", "!! Could not get host name");
}
return false;
}
cfengine-3.2.4/src/install.c 0000644 0001750 0001750 00000020463 11715232734 012632 0000000 0000000 /*
Copyright (C) Cfengine AS
This file is part of Cfengine 3 - written and maintained by Cfengine 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 Commerical Open Source License
(COSL) may apply to this file if you as a licensee so wish it. See
included file COSL.txt.
*/
/*****************************************************************************/
/* */
/* File: install.c */
/* */
/*****************************************************************************/
#include "cf3.defs.h"
#include "cf3.extern.h"
static void DeleteSubTypes(struct SubType *tp);
/*******************************************************************/
int RelevantBundle(char *agent,char *blocktype)
{ struct Item *ip;
if (strcmp(agent,CF_AGENTTYPES[cf_common]) == 0 || strcmp(CF_COMMONC,P.blocktype) == 0)
{
return true;
}
/* Here are some additional bundle types handled by cfAgent */
ip = SplitString("edit_line,edit_xml",',');
if (strcmp(agent,CF_AGENTTYPES[cf_agent]) == 0)
{
if (IsItemIn(ip,blocktype))
{
DeleteItemList(ip);
return true;
}
}
DeleteItemList(ip);
return false;
}
/*******************************************************************/
struct Bundle *AppendBundle(struct Bundle **start,char *name, char *type, struct Rlist *args)
{ struct Bundle *bp,*lp;
if (INSTALL_SKIP)
{
return NULL;
}
Debug("Appending new bundle %s %s (",type,name);
if (DEBUG)
{
ShowRlist(stdout,args);
}
Debug(")\n");
CheckBundle(name,type);
if ((bp = (struct Bundle *)malloc(sizeof(struct Bundle))) == NULL)
{
CfOut(cf_error,"malloc","Unable to alloc Bundle");
FatalError("");
}
if (*start == NULL)
{
*start = bp;
}
else
{
for (lp = *start; lp->next != NULL; lp=lp->next)
{
}
lp->next = bp;
}
bp->name = strdup(name);
bp->next = NULL;
bp->type = strdup(type);
bp->args = args;
bp->subtypes = NULL;
return bp;
}
/*******************************************************************/
struct Body *AppendBody(struct Body **start,char *name, char *type, struct Rlist *args)
{ struct Body *bp,*lp;
struct Rlist *rp;
Debug("Appending new promise body %s %s(",type,name);
CheckBody(name,type);
for (rp = args; rp!= NULL; rp=rp->next)
{
Debug("%s,",(char *)rp->item);
}
Debug(")\n");
if ((bp = (struct Body *)malloc(sizeof(struct Body))) == NULL)
{
CfOut(cf_error,"malloc","Unable to allocate Body");
FatalError("");
}
if (*start == NULL)
{
*start = bp;
}
else
{
for (lp = *start; lp->next != NULL; lp=lp->next)
{
}
lp->next = bp;
}
bp->name = strdup(name);
bp->next = NULL;
bp->type = strdup(type);
bp->args = args;
bp->conlist = NULL;
return bp;
}
/*******************************************************************/
struct SubType *AppendSubType(struct Bundle *bundle,char *typename)
{ struct SubType *tp,*lp;
char *sp;
if (INSTALL_SKIP)
{
return NULL;
}
Debug("Appending new type section %s\n",typename);
if (bundle == NULL)
{
yyerror("Software error. Attempt to add a type without a bundle\n");
FatalError("Stopped");
}
for (lp = bundle->subtypes; lp != NULL; lp=lp->next)
{
if (strcmp(lp->name,typename) == 0)
{
return lp;
}
}
if ((tp = (struct SubType *)malloc(sizeof(struct SubType))) == NULL)
{
CfOut(cf_error,"malloc","Unable to allocate SubType");
FatalError("");
}
if ((sp = strdup(typename)) == NULL)
{
CfOut(cf_error,"malloc","Unable to allocate SubType");
FatalError("");
}
if (bundle->subtypes == NULL)
{
bundle->subtypes = tp;
}
else
{
for (lp = bundle->subtypes; lp->next != NULL; lp=lp->next)
{
}
lp->next = tp;
}
tp->promiselist = NULL;
tp->name = sp;
tp->next = NULL;
return tp;
}
/*******************************************************************/
struct Promise *AppendPromise(struct SubType *type,char *promiser, void *promisee,char petype,char *classes,char *bundle,char *bundletype)
{ struct Promise *pp,*lp;
char *sp = NULL,*spe = NULL;
char output[CF_BUFSIZE];
if (INSTALL_SKIP)
{
return NULL;
}
if (type == NULL)
{
yyerror("Software error. Attempt to add a promise without a type\n");
FatalError("Stopped");
}
/* Check here for broken promises - or later with more info? */
Debug("Appending Promise from bundle %s %s if context %s\n",bundle,promiser,classes);
if ((pp = (struct Promise *)malloc(sizeof(struct Promise))) == NULL)
{
CfOut(cf_error,"malloc","Unable to allocate Promise");
FatalError("");
}
if ((sp = strdup(promiser)) == NULL)
{
CfOut(cf_error,"malloc","Unable to allocate Promise");
FatalError("");
}
if (strlen(classes) > 0)
{
if ((spe = strdup(classes)) == NULL)
{
CfOut(cf_error,"malloc","Unable to allocate Promise");
FatalError("");
}
}
else
{
if ((spe = strdup("any")) == NULL)
{
CfOut(cf_error,"malloc","Unable to allocate Promise");
FatalError("");
}
}
if (strcmp(type->name,"classes") == 0 || strcmp(type->name,"vars") == 0)
{
if (isdigit(*promiser) && Str2Int(promiser) != CF_NOINT)
{
yyerror("Variable or class identifier is purely numerical, which is not allowed");
}
}
if (strcmp(type->name,"vars") == 0)
{
if (!CheckParseVariableName(promiser))
{
snprintf(output,CF_BUFSIZE,"Use of a reserved or illegal variable name \"%s\" ",promiser);
ReportError(output);
}
}
if (type->promiselist == NULL)
{
type->promiselist = pp;
}
else
{
for (lp = type->promiselist; lp->next != NULL; lp=lp->next)
{
}
lp->next = pp;
}
pp->audit = AUDITPTR;
pp->lineno = P.line_no;
pp->bundle = strdup(bundle);
pp->promiser = sp;
pp->promisee = promisee; /* this is a list allocated separately */
pp->petype = petype; /* rtype of promisee - list or scalar recipient? */
pp->classes = spe;
pp->conlist = NULL;
pp->done = false;
pp->donep = &(pp->done);
pp->this_server = NULL;
pp->cache = NULL;
pp->conn = NULL;
pp->inode_cache = NULL;
pp->bundletype = strdup(bundletype); /* cache agent,common,server etc*/
pp->agentsubtype = type->name; /* Cache the typename */
pp->ref = NULL; /* cache a reference if given*/
pp->ref_alloc = 'n';
pp->next = NULL;
return pp;
}
/*******************************************************************/
/* Cleanup */
/*******************************************************************/
void DeleteBundles(struct Bundle *bp)
{
if (bp == NULL)
{
return;
}
if (bp->next != NULL)
{
DeleteBundles(bp->next);
}
if (bp->name != NULL)
{
free(bp->name);
}
if (bp->type != NULL)
{
free(bp->type);
}
DeleteRlist(bp->args);
DeleteSubTypes(bp->subtypes);
free(bp);
}
/*******************************************************************/
static void DeleteSubTypes(struct SubType *tp)
{
if (tp == NULL)
{
return;
}
if (tp->next != NULL)
{
DeleteSubTypes(tp->next);
}
DeletePromises(tp->promiselist);
if (tp->name != NULL)
{
free(tp->name);
}
free(tp);
}
/*******************************************************************/
void DeleteBodies(struct Body *bp)
{
if (bp == NULL)
{
return;
}
if (bp->next != NULL)
{
DeleteBodies(bp->next);
}
if (bp->name != NULL)
{
free(bp->name);
}
if (bp->type != NULL)
{
free(bp->type);
}
DeleteRlist(bp->args);
DeleteConstraintList(bp->conlist);
free(bp);
}
cfengine-3.2.4/src/server_transform.c 0000644 0001750 0001750 00000057375 11715232734 014601 0000000 0000000 /*
Copyright (C) Cfengine AS
This file is part of Cfengine 3 - written and maintained by Cfengine 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 Commerical Open Source License
(COSL) may apply to this file if you as a licensee so wish it. See
included file COSL.txt.
*/
/*****************************************************************************/
/* */
/* File: server_transform.c */
/* */
/*****************************************************************************/
#include "cf3.defs.h"
#include "cf3.extern.h"
#include "cf3.server.h"
static void KeepContextBundles(void);
static void KeepServerPromise(struct Promise *pp);
static void InstallServerAuthPath(char *path,struct Auth **list,struct Auth **listtop);
static void KeepServerRolePromise(struct Promise *pp);
extern struct BodySyntax CFS_CONTROLBODY[];
extern struct BodySyntax CF_REMROLE_BODIES[];
/*******************************************************************/
/* GLOBAL VARIABLES */
/*******************************************************************/
extern int CLOCK_DRIFT;
extern int CFD_MAXPROCESSES;
extern int ACTIVE_THREADS;
extern int NO_FORK;
extern int MULTITHREAD;
extern int CHECK_RFC931;
extern int CFD_INTERVAL;
extern int DENYBADCLOCKS;
extern int MULTIPLECONNS;
extern int TRIES;
extern int MAXTRIES;
extern int LOGCONNS;
extern int LOGENCRYPT;
extern struct Item *CONNECTIONLIST;
extern struct Auth *ROLES;
extern struct Auth *ROLESTOP;
/*******************************************************************/
void KeepFileAccessPromise(struct Promise *pp);
void KeepLiteralAccessPromise(struct Promise *pp, char *type);
void KeepQueryAccessPromise(struct Promise *pp,char *type);
/*******************************************************************/
/* Level */
/*******************************************************************/
void KeepPromises()
{
KeepContextBundles();
KeepControlPromises();
KeepPromiseBundles();
}
/*******************************************************************/
void Summarize()
{ struct Auth *ptr;
struct Item *ip,*ipr;
CfOut(cf_verbose,"","Summarize control promises\n");
CfOut(cf_verbose, "", "Granted access to paths :\n");
for (ptr = VADMIT; ptr != NULL; ptr=ptr->next)
{
CfOut(cf_verbose, "", "Path: %s (encrypt=%d)\n",ptr->path,ptr->encrypt);
for (ip = ptr->accesslist; ip != NULL; ip=ip->next)
{
CfOut(cf_verbose, "", " Admit: %s root=",ip->name);
for (ipr = ptr->maproot; ipr !=NULL; ipr=ipr->next)
{
CfOut(cf_verbose, "", "%s,",ipr->name);
}
}
}
CfOut(cf_verbose, "", "Denied access to paths :\n");
for (ptr = VDENY; ptr != NULL; ptr=ptr->next)
{
CfOut(cf_verbose, "", "Path: %s\n",ptr->path);
for (ip = ptr->accesslist; ip != NULL; ip=ip->next)
{
CfOut(cf_verbose, "", " Deny: %s\n",ip->name);
}
}
CfOut(cf_verbose,""," -> Host IPs allowed connection access :\n");
for (ip = NONATTACKERLIST; ip != NULL; ip=ip->next)
{
CfOut(cf_verbose,""," .... IP: %s\n",ip->name);
}
CfOut(cf_verbose,"","Host IPs denied connection access :\n");
for (ip = ATTACKERLIST; ip != NULL; ip=ip->next)
{
CfOut(cf_verbose,""," .... IP: %s\n",ip->name);
}
CfOut(cf_verbose,"","Host IPs allowed multiple connection access :\n");
for (ip = MULTICONNLIST; ip != NULL; ip=ip->next)
{
CfOut(cf_verbose,""," .... IP: %s\n",ip->name);
}
CfOut(cf_verbose,"","Host IPs from whom we shall accept public keys on trust :\n");
for (ip = TRUSTKEYLIST; ip != NULL; ip=ip->next)
{
CfOut(cf_verbose,""," .... IP: %s\n",ip->name);
}
CfOut(cf_verbose,"","Users from whom we accept connections :\n");
for (ip = ALLOWUSERLIST; ip != NULL; ip=ip->next)
{
CfOut(cf_verbose,""," .... USERS: %s\n",ip->name);
}
CfOut(cf_verbose,"","Host IPs from NAT which we don't verify :\n");
for (ip = SKIPVERIFY; ip != NULL; ip=ip->next)
{
CfOut(cf_verbose,""," .... IP: %s\n",ip->name);
}
CfOut(cf_verbose,"","Dynamical Host IPs (e.g. DHCP) whose bindings could vary over time :\n");
for (ip = DHCPLIST; ip != NULL; ip=ip->next)
{
CfOut(cf_verbose,""," .... IP: %s\n",ip->name);
}
}
/*******************************************************************/
/* Level */
/*******************************************************************/
void KeepControlPromises()
{ struct Constraint *cp;
char rettype;
void *retval;
CFD_MAXPROCESSES = 30;
MAXTRIES = 5;
CFD_INTERVAL = 0;
CHECKSUMUPDATES = true;
DENYBADCLOCKS = true;
CFRUNCOMMAND[0] = '\0';
CHECK_RFC931 = false;
/* Keep promised agent behaviour - control bodies */
Banner("Server control promises..");
HashControls();
/* Now expand */
for (cp = ControlBodyConstraints(cf_server); cp != NULL; cp=cp->next)
{
if (IsExcluded(cp->classes))
{
continue;
}
if (GetVariable("control_server",cp->lval,&retval,&rettype) == cf_notype)
{
CfOut(cf_error,"","Unknown lval %s in server control body",cp->lval);
continue;
}
if (strcmp(cp->lval,CFS_CONTROLBODY[cfs_serverfacility].lval) == 0)
{
SetFacility(retval);
continue;
}
if (strcmp(cp->lval,CFS_CONTROLBODY[cfs_denybadclocks].lval) == 0)
{
DENYBADCLOCKS = GetBoolean(retval);
CfOut(cf_verbose,"","SET denybadclocks = %d\n",DENYBADCLOCKS);
continue;
}
if (strcmp(cp->lval,CFS_CONTROLBODY[cfs_logencryptedtransfers].lval) == 0)
{
LOGENCRYPT = GetBoolean(retval);
CfOut(cf_verbose,"","SET LOGENCRYPT = %d\n",LOGENCRYPT);
continue;
}
if (strcmp(cp->lval,CFS_CONTROLBODY[cfs_logallconnections].lval) == 0)
{
LOGCONNS = GetBoolean(retval);
CfOut(cf_verbose,"","SET LOGCONNS = %d\n",LOGCONNS);
continue;
}
if (strcmp(cp->lval,CFS_CONTROLBODY[cfs_maxconnections].lval) == 0)
{
CFD_MAXPROCESSES = (int)Str2Int(retval);
MAXTRIES = CFD_MAXPROCESSES / 3;
CfOut(cf_verbose,"","SET maxconnections = %d\n",CFD_MAXPROCESSES);
continue;
}
if (strcmp(cp->lval,CFS_CONTROLBODY[cfs_cfruncommand].lval) == 0)
{
strncpy(CFRUNCOMMAND,retval,CF_BUFSIZE-1);
CfOut(cf_verbose,"","SET cfruncommand = %s\n",CFRUNCOMMAND);
continue;
}
if (strcmp(cp->lval,CFS_CONTROLBODY[cfs_allowconnects].lval) == 0)
{
struct Rlist *rp;
CfOut(cf_verbose,"","SET Allowing connections from ...\n");
for (rp = (struct Rlist *) retval; rp != NULL; rp = rp->next)
{
if (!IsItemIn(NONATTACKERLIST,rp->item))
{
AppendItem(&NONATTACKERLIST,rp->item,cp->classes);
}
}
continue;
}
if (strcmp(cp->lval,CFS_CONTROLBODY[cfs_denyconnects].lval) == 0)
{
struct Rlist *rp;
CfOut(cf_verbose,"","SET Denying connections from ...\n");
for (rp = (struct Rlist *) retval; rp != NULL; rp = rp->next)
{
if (!IsItemIn(ATTACKERLIST,rp->item))
{
AppendItem(&ATTACKERLIST,rp->item,cp->classes);
}
}
continue;
}
if (strcmp(cp->lval,CFS_CONTROLBODY[cfs_skipverify].lval) == 0)
{
struct Rlist *rp;
CfOut(cf_verbose,"","SET Skip verify connections from ...\n");
for (rp = (struct Rlist *) retval; rp != NULL; rp = rp->next)
{
if (!IsItemIn(SKIPVERIFY,rp->item))
{
AppendItem(&SKIPVERIFY,rp->item,cp->classes);
}
}
continue;
}
if (strcmp(cp->lval,CFS_CONTROLBODY[cfs_dynamicaddresses].lval) == 0)
{
struct Rlist *rp;
CfOut(cf_verbose,"","SET Dynamic addresses from ...\n");
for (rp = (struct Rlist *)retval; rp != NULL; rp = rp->next)
{
if (!IsItemIn(DHCPLIST,rp->item))
{
AppendItem(&DHCPLIST,rp->item,cp->classes);
}
}
continue;
}
if (strcmp(cp->lval,CFS_CONTROLBODY[cfs_allowallconnects].lval) == 0)
{
struct Rlist *rp;
CfOut(cf_verbose,"","SET Allowing multiple connections from ...\n");
for (rp = (struct Rlist *)retval; rp != NULL; rp = rp->next)
{
if (!IsItemIn(MULTICONNLIST,rp->item))
{
AppendItem(&MULTICONNLIST,rp->item,cp->classes);
}
}
continue;
}
if (strcmp(cp->lval,CFS_CONTROLBODY[cfs_allowusers].lval) == 0)
{
struct Rlist *rp;
CfOut(cf_verbose,"","SET Allowing users ...\n");
for (rp = (struct Rlist *)retval; rp != NULL; rp = rp->next)
{
if (!IsItemIn(ALLOWUSERLIST,rp->item))
{
AppendItem(&ALLOWUSERLIST,rp->item,cp->classes);
}
}
continue;
}
if (strcmp(cp->lval,CFS_CONTROLBODY[cfs_trustkeysfrom].lval) == 0)
{
struct Rlist *rp;
CfOut(cf_verbose,"","SET Trust keys from ...\n");
for (rp = (struct Rlist *)retval; rp != NULL; rp = rp->next)
{
if (!IsItemIn(TRUSTKEYLIST,rp->item))
{
AppendItem(&TRUSTKEYLIST,rp->item,cp->classes);
}
}
continue;
}
if (strcmp(cp->lval,CFS_CONTROLBODY[cfs_portnumber].lval) == 0)
{
SHORT_CFENGINEPORT = (short)Str2Int(retval);
strncpy(STR_CFENGINEPORT,retval,15);
CfOut(cf_verbose,"","SET default portnumber = %u = %s = %s\n",(int)SHORT_CFENGINEPORT,STR_CFENGINEPORT,retval);
SHORT_CFENGINEPORT = htons((short)Str2Int(retval));
continue;
}
if (strcmp(cp->lval,CFS_CONTROLBODY[cfs_keyttl].lval) == 0)
{
KEYTTL = (short)Str2Int(retval);
CfOut(cf_verbose,"","SET key TTL = %d\n",KEYTTL);
continue;
}
if (strcmp(cp->lval,CFS_CONTROLBODY[cfs_bindtointerface].lval) == 0)
{
strncpy(BINDINTERFACE,retval,CF_BUFSIZE-1);
CfOut(cf_verbose,"","SET bindtointerface = %s\n",BINDINTERFACE);
continue;
}
}
if (GetVariable("control_common",CFG_CONTROLBODY[cfg_syslog_host].lval,&retval,&rettype) != cf_notype)
{
SYSLOGPORT = (unsigned short)Str2Int(retval);
}
if (GetVariable("control_common",CFG_CONTROLBODY[cfg_syslog_port].lval,&retval,&rettype) != cf_notype)
{
strncpy(SYSLOGHOST,Hostname2IPString(retval),CF_MAXVARSIZE-1);
}
if (GetVariable("control_common",CFG_CONTROLBODY[cfg_fips_mode].lval,&retval,&rettype) != cf_notype)
{
FIPS_MODE = GetBoolean(retval);
CfOut(cf_verbose,"","SET FIPS_MODE = %d\n",FIPS_MODE);
}
}
/*********************************************************************/
static void KeepContextBundles()
{ struct Bundle *bp;
struct SubType *sp;
struct Promise *pp;
char *scope;
/* Dial up the generic promise expansion with a callback */
for (bp = BUNDLES; bp != NULL; bp = bp->next) /* get schedule */
{
scope = bp->name;
SetNewScope(bp->name);
if ((strcmp(bp->type,CF_AGENTTYPES[cf_server]) == 0) || (strcmp(bp->type,CF_AGENTTYPES[cf_common]) == 0))
{
DeletePrivateClassContext(); // Each time we change bundle
BannerBundle(bp,NULL);
scope = bp->name;
for (sp = bp->subtypes; sp != NULL; sp = sp->next) /* get schedule */
{
if (strcmp(sp->name,"vars") != 0 && strcmp(sp->name,"classes") != 0)
{
continue;
}
BannerSubType(scope,sp->name,0);
SetScope(scope);
AugmentScope(scope,NULL,NULL);
for (pp = sp->promiselist; pp != NULL; pp=pp->next)
{
ExpandPromise(cf_server,scope,pp,KeepServerPromise);
}
}
}
}
}
/*********************************************************************/
void KeepPromiseBundles()
{ struct Bundle *bp;
struct SubType *sp;
struct Promise *pp;
char *scope;
/* Dial up the generic promise expansion with a callback */
for (bp = BUNDLES; bp != NULL; bp = bp->next) /* get schedule */
{
scope = bp->name;
SetNewScope(bp->name);
if ((strcmp(bp->type,CF_AGENTTYPES[cf_server]) == 0) || (strcmp(bp->type,CF_AGENTTYPES[cf_common]) == 0))
{
DeletePrivateClassContext(); // Each time we change bundle
BannerBundle(bp,NULL);
scope = bp->name;
for (sp = bp->subtypes; sp != NULL; sp = sp->next) /* get schedule */
{
if (strcmp(sp->name,"access") != 0 && strcmp(sp->name,"roles") != 0)
{
continue;
}
BannerSubType(scope,sp->name,0);
SetScope(scope);
AugmentScope(scope,NULL,NULL);
for (pp = sp->promiselist; pp != NULL; pp=pp->next)
{
ExpandPromise(cf_server,scope,pp,KeepServerPromise);
}
}
}
}
}
/*********************************************************************/
/* Level */
/*********************************************************************/
static void KeepServerPromise(struct Promise *pp)
{ char *sp = NULL;
if (!IsDefinedClass(pp->classes))
{
CfOut(cf_verbose,"","Skipping whole promise, as context is %s\n",pp->classes);
return;
}
if (VarClassExcluded(pp,&sp))
{
CfOut(cf_verbose,"","\n");
CfOut(cf_verbose,"",". . . . . . . . . . . . . . . . . . . . . . . . . . . . \n");
CfOut(cf_verbose,"","Skipping whole next promise (%s), as var-context %s is not relevant\n",pp->promiser,sp);
CfOut(cf_verbose,"",". . . . . . . . . . . . . . . . . . . . . . . . . . . . \n");
return;
}
if (strcmp(pp->agentsubtype,"classes") == 0)
{
KeepClassContextPromise(pp);
return;
}
sp = (char *)GetConstraint("resource_type",pp,CF_SCALAR);
if (strcmp(pp->agentsubtype,"access") == 0 && sp && strcmp(sp,"literal") == 0)
{
KeepLiteralAccessPromise(pp,"literal");
return;
}
if (strcmp(pp->agentsubtype,"access") == 0 && sp && strcmp(sp,"query") == 0)
{
KeepQueryAccessPromise(pp,"query");
return;
}
if (strcmp(pp->agentsubtype,"access") == 0 && sp && strcmp(sp,"context") == 0)
{
KeepLiteralAccessPromise(pp,"context");
return;
}
/* Default behaviour is file access */
if (strcmp(pp->agentsubtype,"access") == 0)
{
KeepFileAccessPromise(pp);
return;
}
if (strcmp(pp->agentsubtype,"roles") == 0)
{
KeepServerRolePromise(pp);
return;
}
}
/*********************************************************************/
void KeepFileAccessPromise(struct Promise *pp)
{ struct Constraint *cp;
struct Rlist *rp;
struct Auth *ap,*dp;
char *val;
if (strlen(pp->promiser) != 1)
{
DeleteSlash(pp->promiser);
}
if (!GetAuthPath(pp->promiser,VADMIT))
{
InstallServerAuthPath(pp->promiser,&VADMIT,&VADMITTOP);
}
if (!GetAuthPath(pp->promiser,VDENY))
{
InstallServerAuthPath(pp->promiser,&VDENY,&VDENYTOP);
}
ap = GetAuthPath(pp->promiser,VADMIT);
dp = GetAuthPath(pp->promiser,VDENY);
for (cp = pp->conlist; cp != NULL; cp = cp->next)
{
if (!IsDefinedClass(cp->classes))
{
continue;
}
switch (cp->type)
{
case CF_SCALAR:
val = (char *)cp->rval;
if (strcmp(cp->lval,CF_REMACCESS_BODIES[cfs_encrypted].lval) == 0)
{
ap->encrypt = true;
}
break;
case CF_LIST:
for (rp = (struct Rlist *)cp->rval; rp != NULL; rp=rp->next)
{
if (strcmp(cp->lval,CF_REMACCESS_BODIES[cfs_admit].lval) == 0)
{
PrependItem(&(ap->accesslist),rp->item,NULL);
continue;
}
if (strcmp(cp->lval,CF_REMACCESS_BODIES[cfs_deny].lval) == 0)
{
PrependItem(&(dp->accesslist),rp->item,NULL);
continue;
}
if (strcmp(cp->lval,CF_REMACCESS_BODIES[cfs_maproot].lval) == 0)
{
PrependItem(&(ap->maproot),rp->item,NULL);
continue;
}
}
break;
case CF_FNCALL:
/* Shouldn't happen */
break;
}
}
}
/*********************************************************************/
void KeepLiteralAccessPromise(struct Promise *pp,char *type)
{ struct Constraint *cp;
struct Rlist *rp;
struct Auth *ap,*dp;
char *handle = GetConstraint("handle",pp,CF_SCALAR);
char *val;
if (handle == NULL)
{
CfOut(cf_error,"","Access to literal server data requires you to define a promise handle for reference");
return;
}
if (!GetAuthPath(handle,VARADMIT))
{
InstallServerAuthPath(handle,&VARADMIT,&VARADMITTOP);
}
RegisterLiteralServerData(handle,pp);
if (!GetAuthPath(handle,VARDENY))
{
InstallServerAuthPath(handle,&VARDENY,&VARDENYTOP);
}
ap = GetAuthPath(handle,VARADMIT);
dp = GetAuthPath(handle,VARDENY);
if (strcmp(type,"literal") == 0)
{
ap->literal = true;
}
if (strcmp(type,"context") == 0)
{
ap->classpattern = true;
}
for (cp = pp->conlist; cp != NULL; cp = cp->next)
{
if (!IsDefinedClass(cp->classes))
{
continue;
}
switch (cp->type)
{
case CF_SCALAR:
val = (char *)cp->rval;
if (strcmp(cp->lval,CF_REMACCESS_BODIES[cfs_encrypted].lval) == 0)
{
ap->encrypt = true;
}
break;
case CF_LIST:
for (rp = (struct Rlist *)cp->rval; rp != NULL; rp=rp->next)
{
if (strcmp(cp->lval,CF_REMACCESS_BODIES[cfs_admit].lval) == 0)
{
PrependItem(&(ap->accesslist),rp->item,NULL);
continue;
}
if (strcmp(cp->lval,CF_REMACCESS_BODIES[cfs_deny].lval) == 0)
{
PrependItem(&(dp->accesslist),rp->item,NULL);
continue;
}
if (strcmp(cp->lval,CF_REMACCESS_BODIES[cfs_maproot].lval) == 0)
{
PrependItem(&(ap->maproot),rp->item,NULL);
continue;
}
}
break;
case CF_FNCALL:
/* Shouldn't happen */
break;
}
}
}
/*********************************************************************/
void KeepQueryAccessPromise(struct Promise *pp,char *type)
{ struct Constraint *cp;
struct Rlist *rp;
struct Auth *ap,*dp;
char *val;
if (!GetAuthPath(pp->promiser,VARADMIT))
{
InstallServerAuthPath(pp->promiser,&VARADMIT,&VARADMITTOP);
}
RegisterLiteralServerData(pp->promiser,pp);
if (!GetAuthPath(pp->promiser,VARDENY))
{
InstallServerAuthPath(pp->promiser,&VARDENY,&VARDENYTOP);
}
ap = GetAuthPath(pp->promiser,VARADMIT);
dp = GetAuthPath(pp->promiser,VARDENY);
if (strcmp(type,"query") == 0)
{
ap->literal = true;
}
for (cp = pp->conlist; cp != NULL; cp = cp->next)
{
if (!IsDefinedClass(cp->classes))
{
continue;
}
switch (cp->type)
{
case CF_SCALAR:
val = (char *)cp->rval;
if (strcmp(cp->lval,CF_REMACCESS_BODIES[cfs_encrypted].lval) == 0)
{
ap->encrypt = true;
}
break;
case CF_LIST:
for (rp = (struct Rlist *)cp->rval; rp != NULL; rp=rp->next)
{
if (strcmp(cp->lval,CF_REMACCESS_BODIES[cfs_admit].lval) == 0)
{
PrependItem(&(ap->accesslist),rp->item,NULL);
continue;
}
if (strcmp(cp->lval,CF_REMACCESS_BODIES[cfs_deny].lval) == 0)
{
PrependItem(&(dp->accesslist),rp->item,NULL);
continue;
}
if (strcmp(cp->lval,CF_REMACCESS_BODIES[cfs_maproot].lval) == 0)
{
PrependItem(&(ap->maproot),rp->item,NULL);
continue;
}
}
break;
case CF_FNCALL:
/* Shouldn't happen */
break;
}
}
}
/*********************************************************************/
static void KeepServerRolePromise(struct Promise *pp)
{ struct Constraint *cp;
struct Rlist *rp;
struct Auth *ap;
if (!GetAuthPath(pp->promiser,ROLES))
{
InstallServerAuthPath(pp->promiser,&ROLES,&ROLESTOP);
}
ap = GetAuthPath(pp->promiser,ROLES);
for (cp = pp->conlist; cp != NULL; cp = cp->next)
{
if (!IsDefinedClass(cp->classes))
{
continue;
}
switch (cp->type)
{
case CF_LIST:
for (rp = (struct Rlist *)cp->rval; rp != NULL; rp=rp->next)
{
if (strcmp(cp->lval,CF_REMROLE_BODIES[cfs_authorize].lval) == 0)
{
PrependItem(&(ap->accesslist),rp->item,NULL);
continue;
}
}
break;
case CF_FNCALL:
/* Shouldn't happen */
break;
default:
if (strcmp(cp->lval,"comment") == 0 || strcmp(cp->lval,"handle") == 0)
{
}
else
{
CfOut(cf_error,"","RHS of authorize promise for %s should be a list\n",pp->promiser);
}
break;
}
}
}
/***********************************************************************/
/* Level */
/***********************************************************************/
static void InstallServerAuthPath(char *path,struct Auth **list,struct Auth **listtop)
{ struct Auth *ptr;
#ifdef MINGW
int i;
for(i = 0; path[i] != '\0'; i++)
{
path[i] = ToLower(path[i]);
}
#endif /* MINGW */
if ((ptr = (struct Auth *)malloc(sizeof(struct Auth))) == NULL)
{
FatalError("Memory Allocation failed for InstallAuthPath() #1");
}
if ((ptr->path = strdup(path)) == NULL)
{
FatalError("Memory Allocation failed for InstallAuthPath() #3");
}
if (*listtop == NULL) /* First element in the list */
{
*list = ptr;
}
else
{
(*listtop)->next = ptr;
}
ptr->accesslist = NULL;
ptr->maproot = NULL;
ptr->literal = false;
ptr->encrypt = false;
ptr->next = NULL;
*listtop = ptr;
}
/***********************************************************************/
/* Level */
/***********************************************************************/
struct Auth *GetAuthPath(char *path,struct Auth *list)
{ struct Auth *ap;
#ifdef MINGW
int i;
for(i = 0; path[i] != '\0'; i++)
{
path[i] = ToLower(path[i]);
}
#endif /* MINGW */
if (strlen(path) != 1)
{
DeleteSlash(path);
}
for (ap = list; ap != NULL; ap=ap->next)
{
if (strcmp(ap->path,path) == 0)
{
return ap;
}
}
return NULL;
}
/***********************************************************************/
cfengine-3.2.4/src/logging.c 0000644 0001750 0001750 00000034175 11715232734 012617 0000000 0000000 /*
Copyright (C) Cfengine AS
This file is part of Cfengine 3 - written and maintained by Cfengine 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 Commerical Open Source License
(COSL) may apply to this file if you as a licensee so wish it. See
included file COSL.txt.
*/
/*****************************************************************************/
/* */
/* File: logging.c */
/* */
/*****************************************************************************/
#include "cf3.defs.h"
#include "cf3.extern.h"
static void ExtractOperationLock(char *op);
static void AddAllClasses(struct Rlist *list,int persist,enum statepolicy policy);
static void DeleteAllClasses(struct Rlist *list);
/*****************************************************************************/
void BeginAudit()
{ struct Promise dummyp = {0};
struct Attributes dummyattr = {{0}};
if (THIS_AGENT_TYPE != cf_agent)
{
return;
}
memset(&dummyp,0,sizeof(dummyp));
memset(&dummyattr,0,sizeof(dummyattr));
ClassAuditLog(&dummyp,dummyattr,"Cfagent starting",CF_NOP,"");
}
/*****************************************************************************/
void EndAudit()
{ double total;
char *sp,rettype,string[CF_BUFSIZE];
void *retval;
struct Promise dummyp = {0};
struct Attributes dummyattr = {{0}};
if (THIS_AGENT_TYPE != cf_agent)
{
return;
}
memset(&dummyp,0,sizeof(dummyp));
memset(&dummyattr,0,sizeof(dummyattr));
if (BooleanControl("control_agent",CFA_CONTROLBODY[cfa_track_value].lval))
{
FILE *fout;
char name[CF_MAXVARSIZE],datestr[CF_MAXVARSIZE];
time_t now = time(NULL);
CfOut(cf_inform,""," -> Recording promise valuations");
snprintf(name,CF_MAXVARSIZE,"%s/state/%s",CFWORKDIR,CF_VALUE_LOG);
snprintf(datestr,CF_MAXVARSIZE,"%s",cf_ctime(&now));
if ((fout = fopen(name,"a")) == NULL)
{
CfOut(cf_inform,""," !! Unable to write to the value log %s\n",name);
return;
}
Chop(datestr);
fprintf(fout,"%s,%.4lf,%.4lf,%.4lf\n",datestr,VAL_KEPT,VAL_REPAIRED,VAL_NOTKEPT);
TrackValue(datestr,VAL_KEPT,VAL_REPAIRED,VAL_NOTKEPT);
fclose(fout);
}
total = (double)(PR_KEPT+PR_NOTKEPT+PR_REPAIRED)/100.0;
if (GetVariable("control_common","version",&retval,&rettype) != cf_notype)
{
sp = (char *)retval;
}
else
{
sp = "(not specified)";
}
if (total == 0)
{
*string = '\0';
CfOut(cf_verbose,"","Outcome of version %s: No checks were scheduled\n",sp);
return;
}
else
{
snprintf(string,CF_BUFSIZE,"Outcome of version %s (%s-%d): Promises observed to be kept %.0f%%, Promises repaired %.0f%%, Promises not repaired %.0f\%%",
sp,
THIS_AGENT,
CFA_BACKGROUND,
(double)PR_KEPT/total,
(double)PR_REPAIRED/total,
(double)PR_NOTKEPT/total);
CfOut(cf_verbose,"","%s",string);
PromiseLog(string);
}
if (strlen(string) > 0)
{
ClassAuditLog(&dummyp,dummyattr,string,CF_REPORT,"");
}
ClassAuditLog(&dummyp,dummyattr,"Cfagent closing",CF_NOP,"");
}
/*****************************************************************************/
void ClassAuditLog(struct Promise *pp,struct Attributes attr,char *str,char status,char *reason)
{ time_t now = time(NULL);
char date[CF_BUFSIZE],lock[CF_BUFSIZE],key[CF_BUFSIZE],operator[CF_BUFSIZE];
struct AuditLog newaudit;
struct Audit *ap = pp->audit;
struct timespec t;
double keyval;
int lineno = pp->lineno;
char name[CF_BUFSIZE];
const char *noStatusTypes[] = { "vars", "classes", NULL };
const char *noLogTypes[] = { "insert_lines", "delete_lines", "replace_patterns", "field_edits", NULL };
bool log = true;
Debug("ClassAuditLog(%s)\n",str);
// never count vars or classes as repaired (creates messy reports)
if (pp && (pp->agentsubtype == NULL || IsStrIn(pp->agentsubtype,noStatusTypes)))
{
return;
}
if (pp && IsStrIn(pp->agentsubtype,noLogTypes))
{
log = false;
}
switch(status)
{
case CF_CHG:
if (!EDIT_MODEL)
{
PR_REPAIRED++;
VAL_REPAIRED += attr.transaction.value_repaired;
}
AddAllClasses(attr.classes.change,attr.classes.persist,attr.classes.timer);
DeleteAllClasses(attr.classes.del_change);
if (log)
{
NotePromiseCompliance(pp,0.5,cfn_repaired,reason);
SummarizeTransaction(attr,pp,attr.transaction.log_repaired);
}
break;
case CF_WARN:
PR_NOTKEPT++;
VAL_NOTKEPT += attr.transaction.value_notkept;
if (log)
{
NotePromiseCompliance(pp,1.0,cfn_notkept,reason);
}
break;
case CF_TIMEX:
PR_NOTKEPT++;
VAL_NOTKEPT += attr.transaction.value_notkept;
AddAllClasses(attr.classes.timeout,attr.classes.persist,attr.classes.timer);
DeleteAllClasses(attr.classes.del_notkept);
if(log)
{
NotePromiseCompliance(pp,0.0,cfn_notkept,reason);
SummarizeTransaction(attr,pp,attr.transaction.log_failed);
}
break;
case CF_FAIL:
PR_NOTKEPT++;
VAL_NOTKEPT += attr.transaction.value_notkept;
AddAllClasses(attr.classes.failure,attr.classes.persist,attr.classes.timer);
DeleteAllClasses(attr.classes.del_notkept);
if(log)
{
NotePromiseCompliance(pp,0.0,cfn_notkept,reason);
SummarizeTransaction(attr,pp,attr.transaction.log_failed);
}
break;
case CF_DENIED:
PR_NOTKEPT++;
VAL_NOTKEPT += attr.transaction.value_notkept;
AddAllClasses(attr.classes.denied,attr.classes.persist,attr.classes.timer);
DeleteAllClasses(attr.classes.del_notkept);
if(log)
{
NotePromiseCompliance(pp,0.0,cfn_notkept,reason);
SummarizeTransaction(attr,pp,attr.transaction.log_failed);
}
break;
case CF_INTERPT:
PR_NOTKEPT++;
VAL_NOTKEPT += attr.transaction.value_notkept;
AddAllClasses(attr.classes.interrupt,attr.classes.persist,attr.classes.timer);
DeleteAllClasses(attr.classes.del_notkept);
if(log)
{
NotePromiseCompliance(pp,0.0,cfn_notkept,reason);
SummarizeTransaction(attr,pp,attr.transaction.log_failed);
}
break;
case CF_UNKNOWN:
case CF_NOP:
AddAllClasses(attr.classes.kept,attr.classes.persist,attr.classes.timer);
DeleteAllClasses(attr.classes.del_kept);
if(log)
{
NotePromiseCompliance(pp,1.0,cfn_nop,reason);
SummarizeTransaction(attr,pp,attr.transaction.log_kept);
}
PR_KEPT++;
VAL_KEPT += attr.transaction.value_kept;
break;
}
if (!(attr.transaction.audit || AUDIT))
{
return;
}
snprintf(name,CF_BUFSIZE-1,"%s/%s",CFWORKDIR,CF_AUDITDB_FILE);
MapName(name);
if (!OpenDB(name,&AUDITDBP))
{
return;
}
if (AUDITDBP == NULL || THIS_AGENT_TYPE != cf_agent)
{
return;
}
snprintf(date,CF_BUFSIZE,"%s",cf_ctime(&now));
Chop(date);
ExtractOperationLock(lock);
snprintf(operator,CF_BUFSIZE-1,"[%s] op %s",date,lock);
strncpy(newaudit.operator,operator,CF_AUDIT_COMMENT-1);
if (clock_gettime(CLOCK_REALTIME,&t) == -1)
{
CfOut(cf_verbose,"clock_gettime","Clock gettime failure during audit transaction");
return;
}
// Auditing key needs microsecond precision to separate entries
keyval = (double)(t.tv_sec)+(double)(t.tv_nsec)/(double)CF_BILLION;
snprintf(key,CF_BUFSIZE-1,"%lf",keyval);
if (DEBUG)
{
AuditStatusMessage(stdout,status);
}
if (ap != NULL)
{
strncpy(newaudit.comment,str,CF_AUDIT_COMMENT-1);
strncpy(newaudit.filename,ap->filename,CF_AUDIT_COMMENT-1);
if (ap->version == NULL || strlen(ap->version) == 0)
{
Debug("Promised in %s bundle %s (unamed version last edited at %s) at/before line %d\n",ap->filename,pp->bundle,ap->date,lineno);
newaudit.version[0] = '\0';
}
else
{
Debug("Promised in %s bundle %s (version %s last edited at %s) at/before line %d\n",ap->filename,pp->bundle,ap->version,ap->date,lineno);
strncpy(newaudit.version,ap->version,CF_AUDIT_VERSION-1);
}
strncpy(newaudit.date,ap->date,CF_AUDIT_DATE);
newaudit.lineno = lineno;
}
else
{
strcpy(newaudit.date,date);
strncpy(newaudit.comment,str,CF_AUDIT_COMMENT-1);
strcpy(newaudit.filename,"schedule");
strcpy(newaudit.version,"");
newaudit.lineno = 0;
}
newaudit.status = status;
if (AUDITDBP && (attr.transaction.audit || AUDIT))
{
WriteDB(AUDITDBP,key,&newaudit,sizeof(newaudit));
}
CloseDB(AUDITDBP);
}
/*****************************************************************************/
static void AddAllClasses(struct Rlist *list,int persist,enum statepolicy policy)
{ struct Rlist *rp;
int slot;
char *string;
if (list == NULL)
{
return;
}
for (rp = list; rp != NULL; rp=rp->next)
{
char *classname = strdup(rp->item);
CanonifyNameInPlace(classname);
if (IsHardClass(classname))
{
CfOut(cf_error,""," !! You cannot use reserved hard class \"%s\" as post-condition class",classname);
}
if (persist > 0)
{
CfOut(cf_verbose,""," ?> defining persistent promise result class %s\n", classname);
NewPersistentContext(CanonifyName(rp->item),persist,policy);
}
else
{
CfOut(cf_verbose,""," ?> defining promise result class %s\n", classname);
}
IdempPrependAlphaList(&VHEAP, classname);
}
}
/*****************************************************************************/
static void DeleteAllClasses(struct Rlist *list)
{ struct Rlist *rp;
char *string;
int slot;
if (list == NULL)
{
return;
}
for (rp = list; rp != NULL; rp=rp->next)
{
if (!CheckParseClass("class cancellation",(char *)rp->item,CF_IDRANGE))
{
return;
}
if (IsHardClass((char *)rp->item))
{
CfOut(cf_error,""," !! You cannot cancel a reserved hard class \"%s\" in post-condition classes", rp->item);
}
string = (char *)(rp->item);
slot = (int)*string;
CfOut(cf_verbose,""," -> Cancelling class %s\n",string);
DeletePersistentContext(string);
DeleteItemLiteral(&(VHEAP.list[slot]),CanonifyName(string));
DeleteItemLiteral(&(VADDCLASSES.list[slot]),CanonifyName(string));
AppendItem(&VDELCLASSES,CanonifyName(string),NULL);
}
}
/************************************************************************/
static void ExtractOperationLock(char *op)
{ char *sp, lastch = 'x';
int i = 0, dots = 0;
int offset = strlen("lock...")+strlen(VUQNAME);
/* Use the global copy of the lock from the main serial thread */
for (sp = CFLOCK+offset; *sp != '\0'; sp++)
{
switch (*sp)
{
case '_':
if (lastch == '_')
{
break;
}
else
{
op[i] = '/';
}
break;
case '.':
dots++;
op[i] = *sp;
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
dots = 9;
break;
default:
op[i] = *sp;
break;
}
lastch = *sp;
i++;
if (dots > 1)
{
break;
}
}
op[i] = '\0';
}
/************************************************************************/
void PromiseLog(char *s)
{ char filename[CF_BUFSIZE];
time_t now = time(NULL);
FILE *fout;
if (s == NULL || strlen(s) == 0)
{
return;
}
snprintf(filename,CF_BUFSIZE,"%s/%s",CFWORKDIR,CF_PROMISE_LOG);
MapName(filename);
if ((fout = fopen(filename,"a")) == NULL)
{
CfOut(cf_error,"fopen","Could not open %s",filename);
return;
}
fprintf(fout,"%ld,%ld: %s\n",CFSTARTTIME,now,s);
fclose(fout);
}
/************************************************************************/
void FatalError(char *s, ...)
{ struct CfLock best_guess;
if (s)
{
va_list ap;
char buf[CF_BUFSIZE] = "";
va_start(ap, s);
vsnprintf(buf, CF_BUFSIZE - 1, s, ap);
va_end(ap);
CfOut(cf_error,"","Fatal cfengine error: %s", buf);
}
if (strlen(CFLOCK) > 0)
{
best_guess.lock = strdup(CFLOCK);
best_guess.last = strdup(CFLAST);
best_guess.log = strdup(CFLOG);
YieldCurrentLock(best_guess);
}
unlink(PIDFILE);
EndAudit();
GenericDeInitialize();
exit(1);
}
/*****************************************************************************/
void AuditStatusMessage(FILE *fp,char status)
{
switch (status) /* Reminder */
{
case CF_CHG:
fprintf(fp,"made a system correction");
break;
case CF_WARN:
fprintf(fp,"promise not kept, no action taken");
break;
case CF_TIMEX:
fprintf(fp,"timed out");
break;
case CF_FAIL:
fprintf(fp,"failed to make a correction");
break;
case CF_DENIED:
fprintf(fp,"was denied access to an essential resource");
break;
case CF_INTERPT:
fprintf(fp,"was interrupted\n");
break;
case CF_NOP:
fprintf(fp,"was applied but performed no required actions");
break;
case CF_UNKNOWN:
fprintf(fp,"was applied but status unknown");
break;
case CF_REPORT:
fprintf(fp,"report");
break;
}
}
cfengine-3.2.4/src/server.c 0000644 0001750 0001750 00000312702 11715232734 012472 0000000 0000000 /*
Copyright (C) Cfengine AS
This file is part of Cfengine 3 - written and maintained by Cfengine 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 Commerical Open Source License
(COSL) may apply to this file if you as a licensee so wish it. See
included file COSL.txt.
*/
/*****************************************************************************/
/* */
/* File: server.c */
/* */
/*****************************************************************************/
#include "cf3.defs.h"
#include "cf3.extern.h"
#include "cf3.server.h"
int main (int argc,char *argv[]);
void StartServer (int argc, char **argv);
int OpenReceiverChannel (void);
void PurgeOldConnections (struct Item **list,time_t now);
void SpawnConnection (int sd_reply, char *ipaddr);
void CheckFileChanges (int argc, char **argv, int sd);
void *HandleConnection (struct cfd_connection *conn);
int BusyWithConnection (struct cfd_connection *conn);
int MatchClasses (struct cfd_connection *conn);
void DoExec (struct cfd_connection *conn, char *sendbuffer, char *args);
int GetCommand (char *str);
int VerifyConnection (struct cfd_connection *conn, char *buf);
void RefuseAccess (struct cfd_connection *conn, char *sendbuffer, int size, char *errormsg);
int AccessControl(const char *oldFilename,struct cfd_connection *conn,int encrypt,struct Auth *admit, struct Auth *deny);
int LiteralAccessControl(char *filename,struct cfd_connection *conn,int encrypt,struct Auth *admit, struct Auth *deny);
struct Item *ContextAccessControl(char *in,struct cfd_connection *conn,int encrypt,struct Auth *vadmit, struct Auth *vdeny);
void ReplyServerContext(struct cfd_connection *conn,char *sendbuffer,char *recvbuffer,int encrypted,struct Item *classes);
int CheckStoreKey (struct cfd_connection *conn, RSA *key);
int StatFile (struct cfd_connection *conn, char *sendbuffer, char *filename);
void CfGetFile (struct cfd_get_arg *args);
void CfEncryptGetFile(struct cfd_get_arg *args);
void CompareLocalHash(struct cfd_connection *conn, char *sendbuffer, char *recvbuffer);
void GetServerLiteral(struct cfd_connection *conn,char *sendbuffer,char *recvbuffer,int encrypted);
int GetServerQuery(struct cfd_connection *conn,char *sendbuffer,char *recvbuffer);
int CfOpenDirectory (struct cfd_connection *conn, char *sendbuffer, char *oldDirname);
int CfSecOpenDirectory (struct cfd_connection *conn, char *sendbuffer, char *dirname);
void Terminate (int sd);
void DeleteAuthList (struct Auth *ap);
int AllowedUser (char *user);
int AuthorizeRoles(struct cfd_connection *conn,char *args);
int TransferRights(char *filename,int sd,struct cfd_get_arg *args,char *sendbuffer, struct stat *sb);
void AbortTransfer(int sd,char *sendbuffer,char *filename);
void FailedTransfer(int sd,char *sendbuffer,char *filename);
void ReplyNothing (struct cfd_connection *conn);
struct cfd_connection *NewConn (int sd);
void DeleteConn (struct cfd_connection *conn);
time_t SecondsTillAuto (void);
void SetAuto (int seconds);
int cfscanf (char *in, int len1, int len2, char *out1, char *out2, char *out3);
int AuthenticationDialogue (struct cfd_connection *conn,char *buffer, int buffersize);
int IsKnownHost (RSA *oldkey,RSA *newkey,char *addr,char *user);
void AddToKeyDB (RSA *key,char *addr);
int SafeOpen (char *filename);
void SafeClose (int fd);
int OptionFound(char *args, char *pos, char *word);
in_addr_t GetInetAddr (char *host);
extern struct BodySyntax CFS_CONTROLBODY[];
char CFRUNCOMMAND[CF_BUFSIZE];
time_t CFDSTARTTIME;
/*******************************************************************/
/* Command line options */
/*******************************************************************/
const char *ID = "The server daemon provides two services: it acts as a\n"
"file server for remote file copying and it allows an\n"
"authorized cf-runagent to start start a cf-agent process\n"
"and set certain additional classes with role-based access\n"
"control.\n";
const struct option OPTIONS[15] =
{
{ "help",no_argument,0,'h' },
{ "debug",optional_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'},
{ NULL,0,0,'\0' }
};
const char *HINTS[15] =
{
"Print the help message",
"Set debugging level 0,1,2,3",
"Output verbose information about the behaviour of the agent",
"Output the version of the software",
"Specify an alternative input file than the default",
"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",
NULL
};
/*******************************************************************/
/* GLOBAL VARIABLES */
/*******************************************************************/
int CLOCK_DRIFT = 3600; /* 1hr */
int CFD_MAXPROCESSES = 0;
int ACTIVE_THREADS = 0;
int NO_FORK = false;
int MULTITHREAD = false;
int CHECK_RFC931 = false;
int CFD_INTERVAL = 0;
int DENYBADCLOCKS = true;
int MULTIPLECONNS = false;
int TRIES = 0;
int MAXTRIES = 5;
int LOGCONNS = false;
int LOGENCRYPT = false;
struct Item *CONNECTIONLIST = NULL;
struct Auth *ROLES = NULL;
struct Auth *ROLESTOP = NULL;
struct Auth *VADMIT = NULL;
struct Auth *VADMITTOP = NULL;
struct Auth *VDENY = NULL;
struct Auth *VDENYTOP = NULL;
struct Auth *VARADMIT = NULL;
struct Auth *VARADMITTOP = NULL;
struct Auth *VARDENY = NULL;
struct Auth *VARDENYTOP = NULL;
/*****************************************************************************/
int main(int argc,char *argv[])
{
CheckOpts(argc,argv);
GenericInitialize(argc,argv,"server");
ThisAgentInit();
KeepPromises();
Summarize();
StartServer(argc,argv);
return 0;
}
/*******************************************************************/
void CheckOpts(int argc,char **argv)
{ extern char *optarg;
char ld_library_path[CF_BUFSIZE];
char arg[CF_BUFSIZE];
int optindex = 0;
int c;
while ((c=getopt_long(argc,argv,"d:vIKf:D:N:VSxLFM",OPTIONS,&optindex)) != EOF)
{
switch ((char) c)
{
case 'f':
if (optarg && strlen(optarg) < 5)
{
snprintf(arg,CF_MAXVARSIZE," -f used but argument \"%s\" incorrect",optarg);
FatalError(arg);
}
strncpy(VINPUTFILE,optarg,CF_BUFSIZE-1);
VINPUTFILE[CF_BUFSIZE-1] = '\0';
MINUSF = true;
break;
case 'd':
switch ((optarg==NULL) ? '3' : *optarg)
{
case '1':
D1 = true;
DEBUG = true;
break;
case '2':
D2 = true;
DEBUG = true;
break;
default:
DEBUG = true;
break;
}
NO_FORK = true;
break;
case 'K': IGNORELOCK = true;
break;
case 'D': NewClassesFromString(optarg);
break;
case 'N': NegateClassesFromString(optarg,&VNEGHEAP);
break;
case 'I':
INFORM = true;
break;
case 'v':
VERBOSE = true;
NO_FORK = true;
break;
case 'F': NO_FORK = true;
break;
case 'L': CfOut(cf_verbose,"","Setting LD_LIBRARY_PATH=%s\n",optarg);
snprintf(ld_library_path,CF_BUFSIZE-1,"LD_LIBRARY_PATH=%s",optarg);
putenv(ld_library_path);
break;
case 'V': PrintVersionBanner("cf-serverd");
exit(0);
case 'h': Syntax("cf-serverd - cfengine's server agent",OPTIONS,HINTS,ID);
exit(0);
case 'M': ManPage("cf-serverd - cfengine's server agent",OPTIONS,HINTS,ID);
exit(0);
case 'x': SelfDiagnostic();
exit(0);
default: Syntax("cf-serverd - cfengine's server agent",OPTIONS,HINTS,ID);
exit(1);
}
}
if (argv[optind] != NULL)
{
CfOut(cf_error,"","Unexpected argument with no preceding option: %s\n",argv[optind]);
FatalError("Aborted");
}
Debug("Set debugging\n");
}
/*******************************************************************/
void ThisAgentInit()
{
NewScope("remote_access");
umask(077);
CFDSTARTTIME = time(NULL);
KEYTTL = 24;
}
/*******************************************************************/
void StartServer(int argc,char **argv)
{ char ipaddr[CF_MAXVARSIZE],intime[64];
int sd,sd_reply;
fd_set rset;
time_t now;
struct timeval timeout;
int ret_val;
struct Promise *pp = NewPromise("server_cfengine","the server daemon");
struct Attributes dummyattr = {{0}};
struct CfLock thislock;
#if defined(HAVE_GETADDRINFO)
int addrlen=sizeof(struct sockaddr_in6);
struct sockaddr_in6 cin;
#else
int addrlen=sizeof(struct sockaddr_in);
struct sockaddr_in cin;
#endif
memset(&dummyattr,0,sizeof(dummyattr));
if ((sd = OpenReceiverChannel()) == -1)
{
CfOut(cf_error,"","Unable to start server");
exit(1);
}
signal(SIGINT,HandleSignals);
signal(SIGTERM,HandleSignals);
signal(SIGHUP,SIG_IGN);
signal(SIGPIPE,SIG_IGN);
signal(SIGCHLD,SIG_IGN);
signal(SIGUSR1,HandleSignals);
signal(SIGUSR2,HandleSignals);
if (listen(sd,queuesize) == -1)
{
CfOut(cf_error,"listen","listen failed");
exit(1);
}
dummyattr.transaction.ifelapsed = 0;
dummyattr.transaction.expireafter = 1;
thislock = AcquireLock(pp->promiser,VUQNAME,CFSTARTTIME,dummyattr,pp,false);
if (thislock.lock == NULL)
{
return;
}
CfOut(cf_verbose,"","Listening for connections ...\n");
#ifdef MINGW
if(!NO_FORK)
{
CfOut(cf_verbose, "", "Windows does not support starting processes in the background - starting in foreground");
}
#else /* NOT MINGW */
if ((!NO_FORK) && (fork() != 0))
{
CfOut(cf_inform,"","cf-serverd starting %.24s\n",cf_ctime(&CFDSTARTTIME));
GenericDeInitialize();
exit(0);
}
if (!NO_FORK)
{
ActAsDaemon(sd);
}
#endif /* NOT MINGW */
WritePID("cf-serverd.pid");
/* Andrew Stribblehill -- close sd on exec */
#ifndef MINGW
fcntl(sd, F_SETFD, FD_CLOEXEC);
#endif
while (true)
{
if (ThreadLock(cft_server_children))
{
if (ACTIVE_THREADS == 0)
{
CheckFileChanges(argc,argv,sd);
}
ThreadUnlock(cft_server_children);
}
FD_ZERO(&rset);
FD_SET(sd,&rset);
timeout.tv_sec = 10; /* Set a 10 second timeout for select */
timeout.tv_usec = 0;
Debug(" -> Waiting at incoming select...\n");
ret_val = select((sd+1),&rset,NULL,NULL,&timeout);
if (ret_val == -1) /* Error received from call to select */
{
if (errno == EINTR)
{
continue;
}
else
{
CfOut(cf_error,"select","select failed");
exit(1);
}
}
else if (!ret_val) /* No data waiting, we must have timed out! */
{
continue;
}
CfOut(cf_verbose,""," -> Accepting a connection\n");
if ((sd_reply = accept(sd,(struct sockaddr *)&cin,&addrlen)) != -1)
{
memset(ipaddr,0,CF_MAXVARSIZE);
ThreadLock(cft_getaddr);
snprintf(ipaddr,CF_MAXVARSIZE-1,"%s",sockaddr_ntop((struct sockaddr *)&cin));
ThreadUnlock(cft_getaddr);
Debug("Obtained IP address of %s on socket %d from accept\n",ipaddr,sd_reply);
if (NONATTACKERLIST && !IsMatchItemIn(NONATTACKERLIST,MapAddress(ipaddr)))
{
CfOut(cf_error,"","Not allowing connection from non-authorized IP %s\n",ipaddr);
cf_closesocket(sd_reply);
continue;
}
if (IsMatchItemIn(ATTACKERLIST,MapAddress(ipaddr)))
{
CfOut(cf_error,"","Denying connection from non-authorized IP %s\n",ipaddr);
cf_closesocket(sd_reply);
continue;
}
if ((now = time((time_t *)NULL)) == -1)
{
now = 0;
}
PurgeOldConnections(&CONNECTIONLIST,now);
if (!IsMatchItemIn(MULTICONNLIST,MapAddress(ipaddr)))
{
if (IsItemIn(CONNECTIONLIST,MapAddress(ipaddr)))
{
CfOut(cf_error,"","Denying repeated connection from \"%s\"\n",ipaddr);
cf_closesocket(sd_reply);
continue;
}
}
if (LOGCONNS)
{
CfOut(cf_log,"","Accepting connection from \"%s\"\n",ipaddr);
}
else
{
CfOut(cf_inform,"","Accepting connection from \"%s\"\n",ipaddr);
}
snprintf(intime,63,"%d",(int)now);
if (!ThreadLock(cft_count))
{
return;
}
PrependItem(&CONNECTIONLIST,MapAddress(ipaddr),intime);
if (!ThreadUnlock(cft_count))
{
return;
}
SpawnConnection(sd_reply,ipaddr);
}
}
YieldCurrentLock(thislock); /* We never get here - this is done by a signal handler */
}
/*******************************************************************************/
in_addr_t GetInetAddr(char *host)
{ struct in_addr addr;
struct hostent *hp;
char output[CF_BUFSIZE];
addr.s_addr = inet_addr(host);
if ((addr.s_addr == INADDR_NONE) || (addr.s_addr == 0))
{
if ((hp = gethostbyname(host)) == 0)
{
snprintf(output,CF_BUFSIZE,"\nhost not found: %s\n",host);
FatalError(output);
}
if (hp->h_addrtype != AF_INET)
{
snprintf(output,CF_BUFSIZE,"unexpected address family: %d\n",hp->h_addrtype);
FatalError(output);
}
if (hp->h_length != sizeof(addr))
{
snprintf(output,CF_BUFSIZE,"unexpected address length %d\n",hp->h_length);
FatalError(output);
}
memcpy((char *) &addr, hp->h_addr, hp->h_length);
}
return (addr.s_addr);
}
/*********************************************************************/
/* Level 2 */
/*********************************************************************/
int OpenReceiverChannel()
{ int sd;
int yes=1;
char *ptr = NULL;
struct linger cflinger;
#if defined(HAVE_GETADDRINFO)
struct addrinfo query,*response,*ap;
#else
struct sockaddr_in sin;
#endif
cflinger.l_onoff = 1;
cflinger.l_linger = 60;
#if defined(HAVE_GETADDRINFO)
memset(&query,0,sizeof(struct addrinfo));
query.ai_flags = AI_PASSIVE;
query.ai_family = AF_UNSPEC;
query.ai_socktype = SOCK_STREAM;
/*
* HvB : Bas van der Vlies
*/
if (BINDINTERFACE[0] != '\0' )
{
ptr = BINDINTERFACE;
}
if (getaddrinfo(ptr,STR_CFENGINEPORT,&query,&response) != 0)
{
CfOut(cf_error,"getaddrinfo","DNS/service lookup failure");
return -1;
}
sd = -1;
for (ap = response ; ap != NULL; ap=ap->ai_next)
{
if ((sd = socket(ap->ai_family,ap->ai_socktype,ap->ai_protocol)) == -1)
{
continue;
}
if (setsockopt(sd, SOL_SOCKET,SO_REUSEADDR,(char *)&yes,sizeof (int)) == -1)
{
CfOut(cf_error,"setsockopt","Socket options were not accepted");
exit(1);
}
if (setsockopt(sd, SOL_SOCKET, SO_LINGER,(char *)&cflinger,sizeof (struct linger)) == -1)
{
CfOut(cf_error,"setsockopt","Socket options were not accepted");
exit(1);
}
if (bind(sd,ap->ai_addr,ap->ai_addrlen) == 0)
{
if (DEBUG)
{
ThreadLock(cft_getaddr);
printf("Bound to address %s on %s=%d\n",sockaddr_ntop(ap->ai_addr),CLASSTEXT[VSYSTEMHARDCLASS],VSYSTEMHARDCLASS);
ThreadUnlock(cft_getaddr);
}
if (VSYSTEMHARDCLASS == mingw || VSYSTEMHARDCLASS == openbsd || VSYSTEMHARDCLASS == freebsd || VSYSTEMHARDCLASS == netbsd || VSYSTEMHARDCLASS == dragonfly)
{
continue; /* *bsd doesn't map ipv6 addresses */
}
else
{
break;
}
}
CfOut(cf_error,"bind","Could not bind server address");
cf_closesocket(sd);
sd = -1;
}
if (sd < 0)
{
CfOut(cf_error,"","Couldn't open bind an open socket\n");
exit(1);
}
if (response != NULL)
{
freeaddrinfo(response);
}
#else
memset(&sin,0,sizeof(sin));
if (BINDINTERFACE[0] != '\0' )
{
sin.sin_addr.s_addr = GetInetAddr(BINDINTERFACE);
}
else
{
sin.sin_addr.s_addr = INADDR_ANY;
}
sin.sin_port = (unsigned short)SHORT_CFENGINEPORT;
sin.sin_family = AF_INET;
if ((sd = socket(AF_INET,SOCK_STREAM,0)) == -1)
{
CfOut(cf_error,"socket","Couldn't open socket");
exit (1);
}
if (setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, (char *) &yes, sizeof (int)) == -1)
{
CfOut(cf_error,"sockopt","Couldn't set socket options");
exit (1);
}
if (setsockopt(sd, SOL_SOCKET, SO_LINGER, (char *) &cflinger, sizeof (struct linger)) == -1)
{
CfOut(cf_error,"sockopt","Couldn't set socket options");
exit (1);
}
if (bind(sd,(struct sockaddr *)&sin,sizeof(sin)) == -1)
{
CfOut(cf_error,"bind","Couldn't bind to socket");
exit(1);
}
#endif
return sd;
}
/*********************************************************************/
/* Level 3 */
/*********************************************************************/
void PurgeOldConnections(struct 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. */
{ struct Item *ip;
int then = 0;
if (list == NULL)
{
return;
}
Debug("Purging Old Connections...\n");
if (!ThreadLock(cft_count))
{
return;
}
for (ip = *list; ip != NULL; ip=ip->next)
{
sscanf(ip->classes,"%d",&then);
if (now > then + 7200)
{
DeleteItem(list,ip);
CfOut(cf_verbose,"","Purging IP address %s from connection list\n",ip->name);
}
}
if (!ThreadUnlock(cft_count))
{
return;
}
Debug("Done purging\n");
}
/*********************************************************************/
void SpawnConnection(int sd_reply,char *ipaddr)
{ struct cfd_connection *conn;
#ifdef HAVE_PTHREAD_H
pthread_t tid;
#endif
conn = NewConn(sd_reply);
strncpy(conn->ipaddr,ipaddr,CF_MAX_IP_LEN-1);
CfOut(cf_verbose,"","New connection...(from %s:sd %d)\n",conn->ipaddr,sd_reply);
#if defined HAVE_LIBPTHREAD || defined BUILTIN_GCC_THREAD
CfOut(cf_verbose,"","Spawning new thread...\n");
pthread_attr_init(&PTHREADDEFAULTS);
pthread_attr_setdetachstate(&PTHREADDEFAULTS,PTHREAD_CREATE_DETACHED);
#ifdef HAVE_PTHREAD_ATTR_SETSTACKSIZE
pthread_attr_setstacksize(&PTHREADDEFAULTS,(size_t)1024*1024);
#endif
if (pthread_create(&tid,&PTHREADDEFAULTS,(void *)HandleConnection,(void *)conn) != 0)
{
CfOut(cf_error,"create","pthread_create failed");
HandleConnection(conn);
}
pthread_attr_destroy(&PTHREADDEFAULTS);
#else
/* Can't fork here without getting a zombie unless we do some complex waiting? */
CfOut(cf_verbose,"","Single threaded...\n");
HandleConnection(conn);
#endif
}
/**************************************************************/
void CheckFileChanges(int argc,char **argv,int sd)
{ struct stat newstat;
char filename[CF_BUFSIZE];
int ok;
memset(&newstat,0,sizeof(struct stat));
memset(filename,0,CF_BUFSIZE);
if (!IsFileOutsideDefaultRepository(VINPUTFILE)) /* Don't prepend to absolute names */
{
snprintf(filename,CF_BUFSIZE,"%s/inputs/",CFWORKDIR);
}
strncat(filename,VINPUTFILE,CF_BUFSIZE-1-strlen(filename));
MapName(filename);
Debug("Checking file updates on %s (%x/%x)\n",filename, newstat.st_mtime, CFDSTARTTIME);
if (NewPromiseProposals())
{
CfOut(cf_verbose,""," -> New promises detected...\n");
ok = CheckPromises(cf_server);
if (ok)
{
CfOut(cf_inform,"","Rereading config files %s..\n",filename);
/* Free & reload -- lock this to avoid access errors during reload */
DeleteAlphaList(&VHEAP);
InitAlphaList(&VHEAP);
DeleteAlphaList(&VADDCLASSES);
InitAlphaList(&VADDCLASSES);
DeleteItemList(VNEGHEAP);
DeleteItemList(TRUSTKEYLIST);
DeleteItemList(SKIPVERIFY);
DeleteItemList(DHCPLIST);
DeleteItemList(ATTACKERLIST);
DeleteItemList(NONATTACKERLIST);
DeleteItemList(MULTICONNLIST);
DeleteAuthList(VADMIT);
DeleteAuthList(VDENY);
//DeleteRlist(VINPUTLIST); This is just a pointer, cannot free it
VSYSTEMHARDCLASS = unused1;
DeleteAllScope();
strcpy(VDOMAIN,"undefined.domain");
POLICY_SERVER[0] = '\0';
VADMIT = VADMITTOP = NULL;
VDENY = VDENYTOP = NULL;
VNEGHEAP = NULL;
TRUSTKEYLIST = NULL;
SKIPVERIFY = NULL;
DHCPLIST = NULL;
ATTACKERLIST = NULL;
NONATTACKERLIST = NULL;
MULTICONNLIST = NULL;
VINPUTLIST = NULL;
DeleteBundles(BUNDLES);
DeleteBodies(BODIES);
BUNDLES = NULL;
BODIES = NULL;
ERRORCOUNT = 0;
NewScope("sys");
SetPolicyServer(POLICY_SERVER);
NewScalar("sys","policy_hub",POLICY_SERVER,cf_str);
if (EnterpriseExpiry())
{
CfOut(cf_error,"","Cfengine - autonomous configuration engine. This enterprise license is invalid.\n");
}
NewScope("const");
NewScope("this");
NewScope("control_server");
NewScope("control_common");
NewScope("mon");
NewScope("remote_access");
GetNameInfo3();
CfGetInterfaceInfo(cf_server);
Get3Environment();
BuiltinClasses();
OSClasses();
NewClass(THIS_AGENT);
SetReferenceTime(true);
ReadPromises(cf_server,CF_SERVERC);
KeepPromises();
Summarize();
}
else
{
CfOut(cf_inform,""," !! File changes contain errors -- ignoring");
PROMISETIME = time(NULL);
}
}
else
{
Debug(" -> No new promises found\n");
}
}
/*********************************************************************/
/* Level 4 */
/*********************************************************************/
void *HandleConnection(struct cfd_connection *conn)
{ char output[CF_BUFSIZE];
#if defined HAVE_PTHREAD_H && (defined HAVE_LIBPTHREAD || defined BUILDTIN_GCC_THREAD)
#ifdef HAVE_PTHREAD_SIGMASK
sigset_t sigmask;
sigemptyset(&sigmask);
pthread_sigmask(SIG_BLOCK,&sigmask,NULL);
#endif
#endif
if (conn == NULL)
{
Debug("Null connection\n");
return NULL;
}
if (!ThreadLock(cft_server_children))
{
DeleteConn(conn);
return NULL;
}
ACTIVE_THREADS++;
if (ACTIVE_THREADS >= CFD_MAXPROCESSES)
{
ACTIVE_THREADS--;
if (TRIES++ > MAXTRIES) /* When to say we're hung / apoptosis threshold */
{
CfOut(cf_error,"","Server seems to be paralyzed. DOS attack? Committing apoptosis...");
HandleSignals(SIGTERM);
}
if (!ThreadUnlock(cft_server_children))
{
}
CfOut(cf_error,"","Too many threads (>=%d) -- increase server maxconnections?",CFD_MAXPROCESSES);
snprintf(output,CF_BUFSIZE,"BAD: Server is currently too busy -- increase maxconnections or splaytime?");
SendTransaction(conn->sd_reply,output,0,CF_DONE);
DeleteConn(conn);
return NULL;
}
else
{
ThreadUnlock(cft_server_children);
}
TRIES = 0; /* As long as there is activity, we're not stuck */
while (BusyWithConnection(conn))
{
}
Debug("Terminating thread...\n");
if (!ThreadLock(cft_server_children))
{
DeleteConn(conn);
return NULL;
}
ACTIVE_THREADS--;
if (!ThreadUnlock(cft_server_children))
{
}
DeleteConn(conn);
return NULL;
}
/*********************************************************************/
int BusyWithConnection(struct cfd_connection *conn)
/* This is the protocol section. Here we must */
/* check that the incoming data are sensible */
/* and extract the information from the message */
{ time_t tloc, trem = 0;
char recvbuffer[CF_BUFSIZE+CF_BUFEXT], sendbuffer[CF_BUFSIZE],check[CF_BUFSIZE];
char filename[CF_BUFSIZE],buffer[CF_BUFSIZE],args[CF_BUFSIZE],out[CF_BUFSIZE];
long time_no_see = 0;
unsigned int len=0;
int drift, plainlen, received, encrypted = 0;
struct cfd_get_arg get_args;
struct Item *classes;
memset(recvbuffer,0,CF_BUFSIZE+CF_BUFEXT);
memset(&get_args,0,sizeof(get_args));
if ((received = ReceiveTransaction(conn->sd_reply,recvbuffer,NULL)) == -1)
{
return false;
}
if (strlen(recvbuffer) == 0)
{
Debug("cf-serverd terminating NULL transmission!\n");
return false;
}
Debug("Received: [%s] on socket %d\n",recvbuffer,conn->sd_reply);
switch (GetCommand(recvbuffer))
{
case cfd_exec:
memset(args,0,CF_BUFSIZE);
sscanf(recvbuffer,"EXEC %255[^\n]",args);
if (!conn->id_verified)
{
CfOut(cf_inform,"","Server refusal due to incorrect identity\n");
RefuseAccess(conn,sendbuffer,0,recvbuffer);
return false;
}
if (!AllowedUser(conn->username))
{
CfOut(cf_inform,"","Server refusal due to non-allowed user\n");
RefuseAccess(conn,sendbuffer,0,recvbuffer);
return false;
}
if (!conn->rsa_auth)
{
CfOut(cf_inform,"","Server refusal due to no RSA authentication\n");
RefuseAccess(conn,sendbuffer,0,recvbuffer);
return false;
}
if (!AccessControl(GetArg0(CFRUNCOMMAND),conn,false,VADMIT,VDENY))
{
CfOut(cf_inform,"","Server refusal due to denied access to requested object\n");
RefuseAccess(conn,sendbuffer,0,recvbuffer);
return false;
}
if (!MatchClasses(conn))
{
CfOut(cf_inform,"","Server refusal due to failed class/context match\n");
Terminate(conn->sd_reply);
return false;
}
DoExec(conn,sendbuffer,args);
Terminate(conn->sd_reply);
return false;
case cfd_version:
if (! conn->id_verified)
{
CfOut(cf_inform,"","ID not verified\n");
RefuseAccess(conn,sendbuffer,0,recvbuffer);
}
snprintf(conn->output,CF_BUFSIZE,"OK: %s",Version());
SendTransaction(conn->sd_reply,conn->output,0,CF_DONE);
return conn->id_verified;
case cfd_cauth:
conn->id_verified = VerifyConnection(conn,(char *)(recvbuffer+strlen("CAUTH ")));
if (! conn->id_verified)
{
CfOut(cf_inform,"","ID not verified\n");
RefuseAccess(conn,sendbuffer,0,recvbuffer);
}
return conn->id_verified; /* are we finished yet ? */
case cfd_sauth: /* This is where key agreement takes place */
if (! conn->id_verified)
{
CfOut(cf_inform,"","ID not verified\n");
RefuseAccess(conn,sendbuffer,0,recvbuffer);
return false;
}
if (!AuthenticationDialogue(conn,recvbuffer,received))
{
CfOut(cf_inform,"","Auth dialogue error\n");
RefuseAccess(conn,sendbuffer,0,recvbuffer);
return false;
}
return true;
case cfd_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)
{
CfOut(cf_inform,"","GET buffer out of bounds\n");
RefuseAccess(conn,sendbuffer,0,recvbuffer);
return false;
}
if (! conn->id_verified)
{
CfOut(cf_inform,"","ID not verified\n");
RefuseAccess(conn,sendbuffer,0,recvbuffer);
return false;
}
if (!AccessControl(filename,conn,false,VADMIT,VDENY))
{
CfOut(cf_inform,"","Access denied to get object\n");
RefuseAccess(conn,sendbuffer,0,recvbuffer);
return true;
}
memset(sendbuffer,0,CF_BUFSIZE);
if (get_args.buf_size >= CF_BUFSIZE)
{
get_args.buf_size = 2048;
}
get_args.connect = conn;
get_args.encrypt = false;
get_args.replybuff = sendbuffer;
get_args.replyfile = filename;
CfGetFile(&get_args);
return true;
case cfd_sget:
memset(buffer,0,CF_BUFSIZE);
sscanf(recvbuffer,"SGET %u %d",&len,&(get_args.buf_size));
if (received != len+CF_PROTO_OFFSET)
{
CfOut(cf_verbose,"","Protocol error SGET\n");
RefuseAccess(conn,sendbuffer,0,recvbuffer);
return false;
}
plainlen = DecryptString(conn->encryption_type,recvbuffer+CF_PROTO_OFFSET,buffer,conn->session_key,len);
cfscanf(buffer,strlen("GET"),strlen("dummykey"),check,sendbuffer,filename);
if (strcmp(check,"GET") != 0)
{
CfOut(cf_inform,"","SGET/GET problem\n");
RefuseAccess(conn,sendbuffer,0,recvbuffer);
return true;
}
if (get_args.buf_size < 0 || get_args.buf_size > 8192)
{
CfOut(cf_inform,"","SGET bounding error\n");
RefuseAccess(conn,sendbuffer,0,recvbuffer);
return false;
}
if (get_args.buf_size >= CF_BUFSIZE)
{
get_args.buf_size = 2048;
}
Debug("Confirm decryption, and thus validity of caller\n");
Debug("SGET %s with blocksize %d\n",filename,get_args.buf_size);
if (! conn->id_verified)
{
CfOut(cf_inform,"","ID not verified\n");
RefuseAccess(conn,sendbuffer,0,recvbuffer);
return false;
}
if (!AccessControl(filename,conn,true,VADMIT,VDENY))
{
CfOut(cf_inform,"","Access control error\n");
RefuseAccess(conn,sendbuffer,0,recvbuffer);
return false;
}
memset(sendbuffer,0,CF_BUFSIZE);
get_args.connect = conn;
get_args.encrypt = true;
get_args.replybuff = sendbuffer;
get_args.replyfile = filename;
CfEncryptGetFile(&get_args);
return true;
case cfd_sopendir:
memset(buffer,0,CF_BUFSIZE);
sscanf(recvbuffer,"SOPENDIR %u",&len);
if (len >= sizeof(out) || received != len+CF_PROTO_OFFSET)
{
CfOut(cf_verbose,"","Protocol error OPENDIR: %d\n",len);
RefuseAccess(conn,sendbuffer,0,recvbuffer);
return false;
}
if (conn->session_key == NULL)
{
CfOut(cf_inform,"","No session key\n");
RefuseAccess(conn,sendbuffer,0,recvbuffer);
return false;
}
memcpy(out,recvbuffer+CF_PROTO_OFFSET,len);
plainlen = DecryptString(conn->encryption_type,out,recvbuffer,conn->session_key,len);
if (strncmp(recvbuffer,"OPENDIR",7) !=0)
{
CfOut(cf_inform,"","Opendir failed to decrypt\n");
RefuseAccess(conn,sendbuffer,0,recvbuffer);
return true;
}
memset(filename,0,CF_BUFSIZE);
sscanf(recvbuffer,"OPENDIR %[^\n]",filename);
if (! conn->id_verified)
{
CfOut(cf_inform,"","ID not verified\n");
RefuseAccess(conn,sendbuffer,0,recvbuffer);
return false;
}
if (!AccessControl(filename,conn,true,VADMIT,VDENY)) /* opendir don't care about privacy */
{
CfOut(cf_inform,"","Access error\n");
RefuseAccess(conn,sendbuffer,0,recvbuffer);
return false;
}
CfSecOpenDirectory(conn,sendbuffer,filename);
return true;
case cfd_opendir:
memset(filename,0,CF_BUFSIZE);
sscanf(recvbuffer,"OPENDIR %[^\n]",filename);
if (! conn->id_verified)
{
CfOut(cf_inform,"","ID not verified\n");
RefuseAccess(conn,sendbuffer,0,recvbuffer);
return false;
}
if (!AccessControl(filename,conn,true,VADMIT,VDENY)) /* opendir don't care about privacy */
{
CfOut(cf_inform,"","DIR access error\n");
RefuseAccess(conn,sendbuffer,0,recvbuffer);
return false;
}
CfOpenDirectory(conn,sendbuffer,filename);
return true;
case cfd_ssynch:
memset(buffer,0,CF_BUFSIZE);
sscanf(recvbuffer,"SSYNCH %u",&len);
if (len >= sizeof(out) || received != len+CF_PROTO_OFFSET)
{
CfOut(cf_verbose,"","Protocol error SSYNCH: %d\n",len);
RefuseAccess(conn,sendbuffer,0,recvbuffer);
return false;
}
if (conn->session_key == NULL)
{
CfOut(cf_inform,"","Bad session key\n");
RefuseAccess(conn,sendbuffer,0,recvbuffer);
return false;
}
memcpy(out,recvbuffer+CF_PROTO_OFFSET,len);
plainlen = DecryptString(conn->encryption_type,out,recvbuffer,conn->session_key,len);
if (plainlen < 0)
{
DebugBinOut((char *)conn->session_key,32,"Session key");
CfOut(cf_error, "", "!! Bad decrypt (%d)",len);
}
if (strncmp(recvbuffer,"SYNCH",5) != 0)
{
CfOut(cf_inform,"","No synch\n");
RefuseAccess(conn,sendbuffer,0,recvbuffer);
return true;
}
/* roll through, no break */
case cfd_synch:
if (! conn->id_verified)
{
CfOut(cf_inform,"","ID not verified\n");
RefuseAccess(conn,sendbuffer,0,recvbuffer);
return false;
}
memset(filename,0,CF_BUFSIZE);
sscanf(recvbuffer,"SYNCH %ld STAT %[^\n]",&time_no_see,filename);
trem = (time_t) time_no_see;
if (time_no_see == 0 || filename[0] == '\0')
{
break;
}
if ((tloc = time((time_t *)NULL)) == -1)
{
sprintf(conn->output,"Couldn't read system clock\n");
CfOut(cf_inform,"time",conn->output);
SendTransaction(conn->sd_reply,"BAD: clocks out of synch",0,CF_DONE);
return true;
}
drift = (int)(tloc-trem);
if (!AccessControl(filename,conn,true,VADMIT,VDENY))
{
CfOut(cf_inform,"","Access control in sync\n");
RefuseAccess(conn,sendbuffer,0,recvbuffer);
return true;
}
if (DENYBADCLOCKS && (drift*drift > CLOCK_DRIFT*CLOCK_DRIFT))
{
snprintf(conn->output,CF_BUFSIZE-1,"BAD: Clocks are too far unsynchronized %ld/%ld\n",(long)tloc,(long)trem);
SendTransaction(conn->sd_reply,conn->output,0,CF_DONE);
return true;
}
else
{
Debug("Clocks were off by %ld\n",(long)tloc-(long)trem);
StatFile(conn,sendbuffer,filename);
}
return true;
case cfd_smd5:
sscanf(recvbuffer,"SMD5 %u",&len);
if (len >= sizeof(out) || received != len+CF_PROTO_OFFSET)
{
CfOut(cf_inform,"","Decryption error\n");
RefuseAccess(conn,sendbuffer,0,recvbuffer);
return true;
}
memcpy(out,recvbuffer+CF_PROTO_OFFSET,len);
plainlen = DecryptString(conn->encryption_type,out,recvbuffer,conn->session_key,len);
if (strncmp(recvbuffer,"MD5",3) !=0)
{
CfOut(cf_inform,"","MD5 protocol error\n");
RefuseAccess(conn,sendbuffer,0,recvbuffer);
return false;
}
/* roll through, no break */
case cfd_md5:
if (! conn->id_verified)
{
CfOut(cf_inform,"","ID not verified\n");
RefuseAccess(conn,sendbuffer,0,recvbuffer);
return true;
}
CompareLocalHash(conn,sendbuffer,recvbuffer);
return true;
case cfd_svar:
sscanf(recvbuffer,"SVAR %u",&len);
if (len >= sizeof(out) || received != len+CF_PROTO_OFFSET)
{
CfOut(cf_inform,"","Decrypt error SVAR\n");
RefuseAccess(conn,sendbuffer,0,"decrypt error SVAR");
return true;
}
memcpy(out,recvbuffer+CF_PROTO_OFFSET,len);
plainlen = DecryptString(conn->encryption_type,out,recvbuffer,conn->session_key,len);
encrypted = true;
if (strncmp(recvbuffer,"VAR",3) !=0)
{
CfOut(cf_inform,"","VAR protocol defect\n");
RefuseAccess(conn,sendbuffer,0,"decryption failure");
return false;
}
/* roll through, no break */
case cfd_var:
if (! conn->id_verified)
{
CfOut(cf_inform,"","ID not verified\n");
RefuseAccess(conn,sendbuffer,0,recvbuffer);
return true;
}
if (!LiteralAccessControl(recvbuffer,conn,encrypted,VARADMIT,VARDENY))
{
CfOut(cf_inform,"","Literal access failure\n");
RefuseAccess(conn,sendbuffer,0,recvbuffer);
return false;
}
GetServerLiteral(conn,sendbuffer,recvbuffer,encrypted);
return true;
case cfd_scontext:
sscanf(recvbuffer,"SCONTEXT %u",&len);
if (len >= sizeof(out) || received != len+CF_PROTO_OFFSET)
{
CfOut(cf_inform,"","Decrypt error SCONTEXT, len,received = %d,%d\n",len,received);
RefuseAccess(conn,sendbuffer,0,"decrypt error SCONTEXT");
return true;
}
memcpy(out,recvbuffer+CF_PROTO_OFFSET,len);
plainlen = DecryptString(conn->encryption_type,out,recvbuffer,conn->session_key,len);
encrypted = true;
if (strncmp(recvbuffer,"CONTEXT",7) !=0)
{
CfOut(cf_inform,"","CONTEXT protocol defect...\n");
RefuseAccess(conn,sendbuffer,0,"Decryption failed?");
return false;
}
/* roll through, no break */
case cfd_context:
if (! conn->id_verified)
{
CfOut(cf_inform,"","ID not verified\n");
RefuseAccess(conn,sendbuffer,0,"Context probe");
return true;
}
if ((classes = ContextAccessControl(recvbuffer,conn,encrypted,VARADMIT,VARDENY)) == NULL)
{
CfOut(cf_inform,"","Context access failure on %s\n",recvbuffer);
RefuseAccess(conn,sendbuffer,0,recvbuffer);
return false;
}
ReplyServerContext(conn,sendbuffer,recvbuffer,encrypted,classes);
return true;
case cfd_squery:
sscanf(recvbuffer,"SQUERY %u",&len);
if (len >= sizeof(out) || received != len+CF_PROTO_OFFSET)
{
CfOut(cf_inform,"","Decrypt error SQUERY\n");
RefuseAccess(conn,sendbuffer,0,"decrypt error SVAR");
return true;
}
memcpy(out,recvbuffer+CF_PROTO_OFFSET,len);
plainlen = DecryptString(conn->encryption_type,out,recvbuffer,conn->session_key,len);
if (strncmp(recvbuffer,"QUERY",5) !=0)
{
CfOut(cf_inform,"","QUERY protocol defect\n");
RefuseAccess(conn,sendbuffer,0,"decryption failure");
return false;
}
if (! conn->id_verified)
{
CfOut(cf_inform,"","ID not verified\n");
RefuseAccess(conn,sendbuffer,0,recvbuffer);
return true;
}
if (!LiteralAccessControl(recvbuffer,conn,true,VARADMIT,VARDENY))
{
CfOut(cf_inform,"","Query access failure\n");
RefuseAccess(conn,sendbuffer,0,recvbuffer);
return false;
}
if (GetServerQuery(conn,sendbuffer,recvbuffer))
{
return true;
}
}
sprintf (sendbuffer,"BAD: Request denied\n");
SendTransaction(conn->sd_reply,sendbuffer,0,CF_DONE);
CfOut(cf_inform,"","Closing connection, due to request: \"%s\"\n",recvbuffer);
return false;
}
/**************************************************************/
/* Level 4 */
/**************************************************************/
int MatchClasses(struct cfd_connection *conn)
{ char recvbuffer[CF_BUFSIZE];
struct Item *classlist = NULL, *ip;
int count = 0;
Debug("Match classes\n");
while (true && (count < 10)) /* arbitrary check to avoid infinite loop, DoS attack*/
{
count++;
if (ReceiveTransaction(conn->sd_reply,recvbuffer,NULL) == -1)
{
CfOut(cf_verbose, "ReceiveTransaction", "Unable to read data from network");
return false;
}
Debug("Got class buffer %s\n",recvbuffer);
if (strncmp(recvbuffer,CFD_TERMINATOR,strlen(CFD_TERMINATOR)) == 0)
{
if (count == 1)
{
Debug("No classes were sent, assuming no restrictions...\n");
return true;
}
break;
}
classlist = SplitStringAsItemList(recvbuffer,' ');
for (ip = classlist; ip != NULL; ip=ip->next)
{
CfOut(cf_verbose,"","Checking whether class %s can be identified as me...\n",ip->name);
if (IsDefinedClass(ip->name))
{
Debug("Class %s matched, accepting...\n",ip->name);
DeleteItemList(classlist);
return true;
}
if (MatchInAlphaList(VHEAP,ip->name))
{
Debug("Class matched regular expression %s, accepting...\n",ip->name);
DeleteItemList(classlist);
return true;
}
if (strncmp(ip->name,CFD_TERMINATOR,strlen(CFD_TERMINATOR)) == 0)
{
CfOut(cf_verbose,"","No classes matched, rejecting....\n");
ReplyNothing(conn);
DeleteItemList(classlist);
return false;
}
}
}
ReplyNothing(conn);
CfOut(cf_verbose,"","No classes matched, rejecting....\n");
DeleteItemList(classlist);
return false;
}
/******************************************************************/
void DoExec(struct cfd_connection *conn,char *sendbuffer,char *args)
{ char ebuff[CF_EXPANDSIZE], line[CF_BUFSIZE], *sp;
int print = false,i;
FILE *pp;
if ((CFSTARTTIME = time((time_t *)NULL)) == -1)
{
CfOut(cf_error,"time","Couldn't read system clock\n");
}
if (strlen(CFRUNCOMMAND) == 0)
{
CfOut(cf_verbose,"","cf-serverd exec request: no cfruncommand defined\n");
sprintf(sendbuffer,"Exec request: no cfruncommand defined\n");
SendTransaction(conn->sd_reply,sendbuffer,0,CF_DONE);
return;
}
CfOut(cf_verbose,"","Examining command string: %s\n",args);
for (sp = args; *sp != '\0'; sp++) /* Blank out -K -f */
{
if (*sp == ';' || *sp == '&' || *sp == '|')
{
sprintf(sendbuffer,"You are not authorized to activate these classes/roles on host %s\n",VFQNAME);
SendTransaction(conn->sd_reply,sendbuffer,0,CF_DONE);
return;
}
if (OptionFound(args,sp,"-K")||OptionFound(args,sp,"-f"))
{
*sp = ' ';
*(sp+1) = ' ';
}
else if (OptionFound(args,sp,"--no-lock"))
{
for (i = 0; i < strlen("--no-lock"); i++)
{
*(sp+i) = ' ';
}
}
else if (OptionFound(args,sp,"--file"))
{
for (i = 0; i < strlen("--file"); i++)
{
*(sp+i) = ' ';
}
}
else if (OptionFound(args,sp,"--define")||OptionFound(args,sp,"-D"))
{
CfOut(cf_verbose,"","Attempt to activate a predefined role..\n");
if (!AuthorizeRoles(conn,sp))
{
sprintf(sendbuffer,"You are not authorized to activate these classes/roles on host %s\n",VFQNAME);
SendTransaction(conn->sd_reply,sendbuffer,0,CF_DONE);
return;
}
}
}
snprintf(ebuff,CF_BUFSIZE,"%s --inform",CFRUNCOMMAND);
if (strlen(ebuff)+strlen(args)+6 > CF_BUFSIZE)
{
snprintf(sendbuffer,CF_BUFSIZE,"Command line too long with args: %s\n",ebuff);
SendTransaction(conn->sd_reply,sendbuffer,0,CF_DONE);
return;
}
else
{
if ((args != NULL) && (strlen(args) > 0))
{
strcat(ebuff," ");
strncat(ebuff,args,CF_BUFSIZE-strlen(ebuff));
snprintf(sendbuffer,CF_BUFSIZE,"cf-serverd Executing %s\n",ebuff);
SendTransaction(conn->sd_reply,sendbuffer,0,CF_DONE);
}
}
CfOut(cf_inform,"","Executing command %s\n",ebuff);
if ((pp = cf_popen_sh(ebuff,"r")) == NULL)
{
CfOut(cf_error,"pipe","Couldn't open pipe to command %s\n",ebuff);
snprintf(sendbuffer,CF_BUFSIZE,"Unable to run %s\n",ebuff);
SendTransaction(conn->sd_reply,sendbuffer,0,CF_DONE);
return;
}
while (!feof(pp))
{
if (ferror(pp))
{
fflush(pp);
break;
}
CfReadLine(line,CF_BUFSIZE,pp);
if (ferror(pp))
{
fflush(pp);
break;
}
print = false;
for (sp = line; *sp != '\0'; sp++)
{
if (! isspace((int)*sp))
{
print = true;
break;
}
}
if (print)
{
snprintf(sendbuffer,CF_BUFSIZE,"%s\n",line);
if (SendTransaction(conn->sd_reply,sendbuffer,0,CF_DONE) == -1)
{
CfOut(cf_error,"send","Sending failed, aborting");
break;
}
}
}
cf_pclose(pp);
}
/**************************************************************/
int GetCommand (char *str)
{ int i;
char op[CF_BUFSIZE];
sscanf(str,"%4095s",op);
for (i = 0; PROTOCOL[i] != NULL; i++)
{
if (strcmp(op,PROTOCOL[i])==0)
{
return i;
}
}
return -1;
}
/*********************************************************************/
int VerifyConnection(struct cfd_connection *conn,char buf[CF_BUFSIZE])
/* Try reverse DNS lookup
and RFC931 username lookup to check the authenticity. */
{ char ipstring[CF_MAXVARSIZE], fqname[CF_MAXVARSIZE], username[CF_MAXVARSIZE];
char dns_assert[CF_MAXVARSIZE],ip_assert[CF_MAXVARSIZE];
int matched = false;
struct passwd *pw;
#if defined(HAVE_GETADDRINFO)
struct addrinfo query, *response=NULL, *ap;
int err;
#else
struct sockaddr_in raddr;
int i,j,len = sizeof(struct sockaddr_in);
struct hostent *hp = NULL;
struct Item *ip_aliases = NULL, *ip_addresses = NULL;
#endif
Debug("Connecting host identifies itself as %s\n",buf);
memset(ipstring,0,CF_MAXVARSIZE);
memset(fqname,0,CF_MAXVARSIZE);
memset(username,0,CF_MAXVARSIZE);
sscanf(buf,"%255s %255s %255s",ipstring,fqname,username);
Debug("(ipstring=[%s],fqname=[%s],username=[%s],socket=[%s])\n",ipstring,fqname,username,conn->ipaddr);
ThreadLock(cft_system);
strncpy(dns_assert,ToLowerStr(fqname),CF_MAXVARSIZE-1);
strncpy(ip_assert,ipstring,CF_MAXVARSIZE-1);
ThreadUnlock(cft_system);
/* It only makes sense to check DNS by reverse lookup if the key had to be accepted
on trust. Once we have a positive key ID, the IP address is irrelevant fr authentication...
We can save a lot of time by not looking this up ... */
if ((conn->trust == false) || IsMatchItemIn(SKIPVERIFY,MapAddress(conn->ipaddr)))
{
CfOut(cf_verbose,"","Allowing %s to connect without (re)checking ID\n",ip_assert);
CfOut(cf_verbose,"","Non-verified Host ID is %s (Using skipverify)\n",dns_assert);
strncpy(conn->hostname,dns_assert,CF_MAXVARSIZE);
CfOut(cf_verbose,"","Non-verified User ID seems to be %s (Using skipverify)\n",username);
strncpy(conn->username,username,CF_MAXVARSIZE);
#ifdef MINGW /* NT uses security identifier instead of uid */
if (!NovaWin_UserNameToSid(username, (SID *)conn->sid, CF_MAXSIDSIZE, false))
{
memset(conn->sid, 0, CF_MAXSIDSIZE); /* is invalid sid - discarded */
}
#else /* NOT MINGW */
if ((pw=getpwnam(username)) == NULL) /* Keep this inside mutex */
{
conn->uid = -2;
}
else
{
conn->uid = pw->pw_uid;
}
#endif /* NOT MINGW */
return true;
}
if (strcmp(ip_assert,MapAddress(conn->ipaddr)) != 0)
{
CfOut(cf_verbose,"","IP address mismatch between client's assertion (%s) and socket (%s) - untrustworthy connection\n",ip_assert,conn->ipaddr);
return false;
}
if (strlen(dns_assert) == 0)
{
CfOut(cf_verbose,"","DNS asserted name was empty - untrustworthy connection\n");
return false;
}
if (strcmp(dns_assert,"skipident") == 0)
{
CfOut(cf_verbose,"","DNS asserted name was withheld before key exchange - untrustworthy connection\n");
return false;
}
CfOut(cf_verbose,"","Socket caller address appears honest (%s matches %s)\n",ip_assert,MapAddress(conn->ipaddr));
CfOut(cf_verbose,"","Socket originates from %s=%s\n",ip_assert,dns_assert);
Debug("Attempting to verify honesty by looking up hostname (%s)\n",dns_assert);
/* Do a reverse DNS lookup, like tcp wrappers to see if hostname matches IP */
#if defined(HAVE_GETADDRINFO)
Debug("Using v6 compatible lookup...\n");
memset(&query,0,sizeof(struct addrinfo));
query.ai_family = AF_UNSPEC;
query.ai_socktype = SOCK_STREAM;
query.ai_flags = AI_PASSIVE;
if ((err=getaddrinfo(dns_assert,NULL,&query,&response)) != 0)
{
CfOut(cf_error,"","Unable to lookup %s (%s)",dns_assert,gai_strerror(err));
}
for (ap = response; ap != NULL; ap = ap->ai_next)
{
ThreadLock(cft_getaddr);
if (strcmp(MapAddress(conn->ipaddr),sockaddr_ntop(ap->ai_addr)) == 0)
{
Debug("Found match\n");
matched = true;
}
ThreadUnlock(cft_getaddr);
}
if (response != NULL)
{
freeaddrinfo(response);
}
#else
Debug("IPV4 hostnname lookup on %s\n",dns_assert);
ThreadLock(cft_getaddr);
if ((hp = gethostbyname(dns_assert)) == NULL)
{
CfOut(cf_verbose,"","cf-serverd Couldn't look up name %s\n",fqname);
CfOut(cf_log,"gethostbyname","DNS lookup of %s failed",dns_assert);
matched = false;
}
else
{
matched = true;
Debug("Looking for the peername of our socket...\n");
if (getpeername(conn->sd_reply,(struct sockaddr *)&raddr,&len) == -1)
{
CfOut(cf_error,"getpeername","Couldn't get socket address\n");
matched = false;
}
CfOut(cf_verbose,"","Looking through hostnames on socket with IPv4 %s\n",sockaddr_ntop((struct sockaddr *)&raddr));
for (i = 0; hp->h_addr_list[i]; i++)
{
CfOut(cf_verbose,"","Reverse lookup address found: %d\n",i);
if (memcmp(hp->h_addr_list[i],(char *)&(raddr.sin_addr),sizeof(raddr.sin_addr)) == 0)
{
CfOut(cf_verbose,"","Canonical name matched host's assertion - id confirmed as %s\n",dns_assert);
break;
}
}
if (hp->h_addr_list[0] != NULL)
{
CfOut(cf_verbose,"","Checking address number %d for non-canonical names (aliases)\n",i);
for (j = 0; hp->h_aliases[j] != NULL; j++)
{
CfOut(cf_verbose,"","Comparing [%s][%s]\n",hp->h_aliases[j],ip_assert);
if (strcmp(hp->h_aliases[j],ip_assert) == 0)
{
CfOut(cf_verbose,"","Non-canonical name (alias) matched host's assertion - id confirmed as %s\n",dns_assert);
break;
}
}
if ((hp->h_addr_list[i] != NULL) && (hp->h_aliases[j] != NULL))
{
CfOut(cf_log,"","Reverse hostname lookup failed, host claiming to be %s was %s\n",buf,sockaddr_ntop((struct sockaddr *)&raddr));
matched = false;
}
else
{
CfOut(cf_verbose,"","Reverse lookup succeeded\n");
}
}
else
{
CfOut(cf_log,"","No name was registered in DNS for %s - reverse lookup failed\n",dns_assert);
matched = false;
}
}
ThreadUnlock(cft_getaddr);
#ifdef MINGW /* NT uses security identifier instead of uid */
if (!NovaWin_UserNameToSid(username, (SID *)conn->sid, CF_MAXSIDSIZE, false))
{
memset(conn->sid, 0, CF_MAXSIDSIZE); /* is invalid sid - discarded */
}
#else /* NOT MINGW */
if ((pw=getpwnam(username)) == NULL) /* Keep this inside mutex */
{
conn->uid = -2;
}
else
{
conn->uid = pw->pw_uid;
}
#endif /* NOT MINGW */
#endif
if (!matched)
{
CfOut(cf_log,"gethostbyname","Failed on DNS reverse lookup of %s\n",dns_assert);
CfOut(cf_log,"","Client sent: %s",buf);
return false;
}
CfOut(cf_verbose,"","Host ID is %s\n",dns_assert);
strncpy(conn->hostname,dns_assert,CF_MAXVARSIZE-1);
CfOut(cf_verbose,"","User ID seems to be %s\n",username);
strncpy(conn->username,username,CF_MAXVARSIZE-1);
return true;
}
/**************************************************************/
int AllowedUser(char *user)
{
if (IsItemIn(ALLOWUSERLIST,user))
{
CfOut(cf_verbose,"","User %s granted connection privileges\n",user);
return true;
}
CfOut(cf_verbose,"","User %s is not allowed on this server\n",user);
return false;
}
/**************************************************************/
/* 'resolved' argument needs to be at least CF_BUFSIZE long */
static bool ResolveFilename(const char *req_path, char *res_path)
{
char req_dir[CF_BUFSIZE];
char req_filename[CF_BUFSIZE];
/*
* Eliminate symlinks from path, but do not resolve the file itself if it is a
* symlink.
*/
strlcpy(req_dir, req_path, CF_BUFSIZE);
ChopLastNode(req_dir);
strlcpy(req_filename, ReadLastNode(req_path), CF_BUFSIZE);
#if defined HAVE_REALPATH && !defined NT
if (realpath(req_dir,res_path) == NULL)
{
return false;
}
#else
memset(res_path,0,CF_BUFSIZE);
CompressPath(res_path,req_dir);
#endif
AddSlash(res_path);
strlcat(res_path, req_filename, CF_BUFSIZE);
/* Adjust for forward slashes */
MapName(res_path);
/* NT has case-insensitive path names */
#ifdef MINGW
int i;
for (i = 0; i < strlen(res_path); i++)
{
res_path[i] = ToLower(res_path[i]);
}
#endif /* MINGW */
return true;
}
/**************************************************************/
int AccessControl(const char *req_path,struct cfd_connection *conn,int encrypt,struct Auth *vadmit, struct Auth *vdeny)
{ struct Auth *ap;
int access = false;
char transrequest[CF_BUFSIZE];
struct stat statbuf;
char translated_req_path[CF_BUFSIZE];
char transpath[CF_BUFSIZE];
Debug("AccessControl(%s)\n",req_path);
/*
* /var/cfengine -> $workdir translation.
*/
TranslatePath(translated_req_path,req_path);
if (ResolveFilename(translated_req_path, transrequest))
{
CfOut(cf_verbose, "", "Filename %s is resolved to %s", translated_req_path, transrequest);
}
else
{
CfOut(cf_verbose,"lstat","Couldn't resolve filename %s from host %s\n",translated_req_path,conn->hostname);
}
if (lstat(transrequest,&statbuf) == -1)
{
CfOut(cf_verbose,"lstat","Couldn't stat filename %s requested by host %s\n",transrequest,conn->hostname);
return false;
}
Debug("AccessControl, match(%s,%s) encrypt request=%d\n",transrequest,conn->hostname,encrypt);
if (vadmit == NULL)
{
CfOut(cf_verbose,"","cf-serverd access list is empty, no files are visible\n");
return false;
}
conn->maproot = false;
for (ap = vadmit; ap != NULL; ap=ap->next)
{
int res = false;
Debug("Examining rule in access list (%s,%s)?\n",transrequest,ap->path);
strncpy(transpath,ap->path,CF_BUFSIZE-1);
MapName(transpath);
if ((strlen(transrequest) > strlen(transpath)) && strncmp(transpath,transrequest,strlen(transpath)) == 0 && transrequest[strlen(transpath)] == FILE_SEPARATOR)
{
res = true; /* Substring means must be a / to link, else just a substring og filename */
}
/* Exact match means single file to admit */
if (strcmp(transpath,transrequest) == 0)
{
res = true;
}
if (strcmp(transpath,"/") == 0)
{
res = true;
}
if (res)
{
CfOut(cf_verbose,"","Found a matching rule in access list (%s in %s)\n",transrequest,transpath);
if (cfstat(transpath,&statbuf) == -1)
{
CfOut(cf_log,"","Warning cannot stat file object %s in admit/grant, or access list refers to dangling link\n",transpath);
continue;
}
if (!encrypt && (ap->encrypt == true))
{
CfOut(cf_error,"","File %s requires encrypt connection...will not serve\n",transpath);
access = false;
}
else
{
Debug("Checking whether to map root privileges..\n");
if (IsMatchItemIn(ap->maproot,MapAddress(conn->ipaddr)) || IsRegexItemIn(ap->maproot,conn->hostname))
{
conn->maproot = true;
CfOut(cf_verbose,"","Mapping root privileges to access non-root files\n");
}
if (IsMatchItemIn(ap->accesslist,MapAddress(conn->ipaddr)) || IsRegexItemIn(ap->accesslist,conn->hostname))
{
access = true;
Debug("Access privileges - match found\n");
}
}
break;
}
}
if (strncmp(transpath,transrequest,strlen(transpath)) == 0)
{
for (ap = vdeny; ap != NULL; ap=ap->next)
{
if (IsRegexItemIn(ap->accesslist,conn->hostname))
{
access = false;
CfOut(cf_verbose,"","Host %s explicitly denied access to %s\n",conn->hostname,transrequest);
break;
}
}
}
if (access)
{
CfOut(cf_verbose,"","Host %s granted access to %s\n",conn->hostname,req_path);
if (encrypt && LOGENCRYPT)
{
/* Log files that were marked as requiring encryption */
CfOut(cf_log,"","Host %s granted access to %s\n",conn->hostname,req_path);
}
}
else
{
CfOut(cf_verbose,"","Host %s denied access to %s\n",conn->hostname,req_path);
}
if (!conn->rsa_auth)
{
CfOut(cf_verbose,"","Cannot map root access without RSA authentication");
conn->maproot = false; /* only public files accessible */
/* return false; */
}
return access;
}
/**************************************************************/
int LiteralAccessControl(char *in,struct cfd_connection *conn,int encrypt,struct Auth *vadmit, struct Auth *vdeny)
{ struct 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
{
sscanf(in,"QUERY %128s",name);
}
Debug("\n\nLiteralAccessControl(%s)\n",name);
conn->maproot = false;
for (ap = vadmit; ap != NULL; ap=ap->next)
{
int res = false;
CfOut(cf_verbose,"","Examining rule in access list (%s,%s)?\n",name,ap->path);
if (strcmp(ap->path,name) == 0)
{
res = true; /* Exact match means single file to admit */
}
if (res)
{
CfOut(cf_verbose,"","Found a matching rule in access list (%s in %s)\n",name,ap->path);
if (ap->literal == false)
{
CfOut(cf_error,"","Variable/query \"%s\" requires a literal server item...cannot set variable directly by path\n",ap->path);
access = false;
break;
}
if (!encrypt && (ap->encrypt == true))
{
CfOut(cf_error,"","Variable %s requires encrypt connection...will not serve\n",name);
access = false;
break;
}
else
{
Debug("Checking whether to map root privileges..\n");
if (IsMatchItemIn(ap->maproot,MapAddress(conn->ipaddr)) || IsRegexItemIn(ap->maproot,conn->hostname))
{
conn->maproot = true;
CfOut(cf_verbose,"","Mapping root privileges\n");
}
else
{
CfOut(cf_verbose,"","No root privileges granted\n");
}
if (IsMatchItemIn(ap->accesslist,MapAddress(conn->ipaddr)) || IsRegexItemIn(ap->accesslist,conn->hostname))
{
access = true;
Debug("Access privileges - match found\n");
}
}
}
}
for (ap = vdeny; ap != NULL; ap=ap->next)
{
if (strcmp(ap->path,name) == 0)
{
if (IsMatchItemIn(ap->accesslist,MapAddress(conn->ipaddr)) || IsRegexItemIn(ap->accesslist,conn->hostname))
{
access = false;
CfOut(cf_verbose,"","Host %s explicitly denied access to %s\n",conn->hostname,name);
break;
}
}
}
if (access)
{
CfOut(cf_verbose,"","Host %s granted access to literal \"%s\"\n",conn->hostname,name);
if (encrypt && LOGENCRYPT)
{
/* Log files that were marked as requiring encryption */
CfOut(cf_log,"","Host %s granted access to literal \"%s\"\n",conn->hostname,name);
}
}
else
{
CfOut(cf_verbose,"","Host %s denied access to literal \"%s\"\n",conn->hostname,name);
}
if (!conn->rsa_auth)
{
CfOut(cf_verbose,"","Cannot map root access without RSA authentication");
conn->maproot = false; /* only public files accessible */
/* return false; */
}
return access;
}
/**************************************************************/
struct Item *ContextAccessControl(char *in,struct cfd_connection *conn,int encrypt,struct Auth *vadmit, struct Auth *vdeny)
{ struct Auth *ap;
int access = false;
char client_regex[CF_BUFSIZE];
CF_DB *dbp;
CF_DBC *dbcp;
int ksize,vsize;
char *key;
void *value;
time_t now = time(NULL);
struct CfState q;
struct Item *ip,*matches = NULL, *candidates = NULL;
char filename[CF_BUFSIZE];
sscanf(in,"CONTEXT %255[^\n]",client_regex);
Debug("\n\nContextAccessControl(%s)\n",client_regex);
snprintf(filename,CF_BUFSIZE,"%s%cstate%c%s",CFWORKDIR,FILE_SEPARATOR,FILE_SEPARATOR,CF_STATEDB_FILE);
if (!OpenDB(filename,&dbp))
{
return NULL;
}
/* Acquire a cursor for the database. */
if (!NewDBCursor(dbp,&dbcp))
{
CfOut(cf_inform,""," !! Unable to scan persistence cache");
return NULL;
}
while(NextDB(dbp,dbcp,&key,&ksize,&value,&vsize))
{
memcpy((void *)&q,value,sizeof(struct CfState));
if (now > q.expires)
{
CfOut(cf_verbose,""," Persistent class %s expired\n",key);
DeleteDB(dbp,key);
}
else
{
if (FullTextMatch(client_regex,key))
{
CfOut(cf_verbose,""," - Found key %s...\n",key);
AppendItem(&candidates,key,NULL);
}
}
}
DeleteDBCursor(dbp,dbcp);
CloseDB(dbp);
for (ip = candidates; ip != NULL; ip=ip->next)
{
for (ap = vadmit; ap != NULL; ap=ap->next)
{
int res = false;
if (FullTextMatch(ap->path,ip->name) == 0)
{
res = true;
}
if (res)
{
CfOut(cf_verbose,"","Found a matching rule in access list (%s in %s)\n",ip->name,ap->path);
if (ap->classpattern == false)
{
CfOut(cf_error,"","Context %s requires a literal server item...cannot set variable directly by path\n",ap->path);
access = false;
continue;
}
if (!encrypt && (ap->encrypt == true))
{
CfOut(cf_error,"","Context %s requires encrypt connection...will not serve\n",ip->name);
access = false;
break;
}
else
{
Debug("Checking whether to map root privileges..\n");
if (IsMatchItemIn(ap->maproot,MapAddress(conn->ipaddr)) || IsRegexItemIn(ap->maproot,conn->hostname))
{
conn->maproot = true;
CfOut(cf_verbose,"","Mapping root privileges\n");
}
else
{
CfOut(cf_verbose,"","No root privileges granted\n");
}
if (IsMatchItemIn(ap->accesslist,MapAddress(conn->ipaddr)) || IsRegexItemIn(ap->accesslist,conn->hostname))
{
access = true;
Debug("Access privileges - match found\n");
}
}
}
}
for (ap = vdeny; ap != NULL; ap=ap->next)
{
if (strcmp(ap->path,ip->name) == 0)
{
if (IsMatchItemIn(ap->accesslist,MapAddress(conn->ipaddr)) || IsRegexItemIn(ap->accesslist,conn->hostname))
{
access = false;
CfOut(cf_verbose,"","Host %s explicitly denied access to context %s\n",conn->hostname,ip->name);
break;
}
}
}
if (access)
{
CfOut(cf_verbose,"","Host %s granted access to context \"%s\"\n",conn->hostname,ip->name);
AppendItem(&matches,ip->name,NULL);
if (encrypt && LOGENCRYPT)
{
/* Log files that were marked as requiring encryption */
CfOut(cf_log,"","Host %s granted access to context \"%s\"\n",conn->hostname,ip->name);
}
}
else
{
CfOut(cf_verbose,"","Host %s denied access to context \"%s\"\n",conn->hostname,ip->name);
}
}
DeleteItemList(candidates);
return matches;
}
/**************************************************************/
int AuthorizeRoles(struct cfd_connection *conn,char *args)
{ char *sp;
struct Auth *ap;
char userid1[CF_MAXVARSIZE],userid2[CF_MAXVARSIZE];
struct Rlist *rp,*defines = NULL;
int permitted = false;
snprintf(userid1,CF_MAXVARSIZE,"%s@%s",conn->username,conn->hostname);
snprintf(userid2,CF_MAXVARSIZE,"%s@%s",conn->username,conn->ipaddr);
CfOut(cf_verbose,"","Checking authorized roles in %s\n",args);
if (strncmp(args,"--define",strlen("--define")) == 0)
{
sp = args + strlen("--define");
}
else
{
sp = args + strlen("-D");
}
while (*sp == ' ')
{
sp++;
}
defines = SplitRegexAsRList(sp,"[,:;]",99,false);
/* For each user-defined class attempt, check RBAC */
for (rp = defines; rp != NULL; rp = rp->next)
{
CfOut(cf_verbose,""," -> Verifying %s\n",rp->item);
for (ap = ROLES; ap != NULL; ap=ap->next)
{
if (FullTextMatch(ap->path,rp->item))
{
/* We have a pattern covering this class - so are we allowed to activate it? */
if (IsMatchItemIn(ap->accesslist,MapAddress(conn->ipaddr)) ||
IsRegexItemIn(ap->accesslist,conn->hostname) ||
IsRegexItemIn(ap->accesslist,userid1) ||
IsRegexItemIn(ap->accesslist,userid2) ||
IsRegexItemIn(ap->accesslist,conn->username)
)
{
CfOut(cf_verbose,"","Attempt to define role/class %s is permitted\n",rp->item);
permitted = true;
}
else
{
CfOut(cf_verbose,"","Attempt to define role/class %s is denied\n",rp->item);
DeleteRlist(defines);
return false;
}
}
}
}
if (permitted)
{
CfOut(cf_verbose,"","Role activation allowed\n");
}
else
{
CfOut(cf_verbose,"","Role activation disallowed - abort execution\n");
}
DeleteRlist(defines);
return permitted;
}
/**************************************************************/
int AuthenticationDialogue(struct cfd_connection *conn,char *recvbuffer, int recvlen)
{ char in[CF_BUFSIZE],*out, *decrypted_nonce;
BIGNUM *counter_challenge = NULL;
unsigned char digest[EVP_MAX_MD_SIZE+1] = {0};
unsigned int crypt_len, nonce_len = 0,encrypted_len = 0;
char sauth[10], iscrypt ='n',enterprise_field = 'c';
int len_n = 0,len_e = 0,keylen, session_size;
unsigned long err;
RSA *newkey;
int digestLen = 0;
enum cfhashes digestType;
if (PRIVKEY == NULL || PUBKEY == NULL)
{
CfOut(cf_error,"","No public/private key pair exists, create one with cf-key\n");
return false;
}
if(FIPS_MODE)
{
digestType = CF_DEFAULT_DIGEST;
digestLen = CF_DEFAULT_DIGEST_LEN;
}
else
{
digestType = cf_md5;
digestLen = CF_MD5_LEN;
}
/* proposition C1 */
/* Opening string is a challenge from the client (some agent) */
sauth[0] = '\0';
sscanf(recvbuffer,"%s %c %u %u %c",sauth,&iscrypt,&crypt_len,&nonce_len,&enterprise_field);
if (crypt_len == 0 || nonce_len == 0 || strlen(sauth) == 0)
{
CfOut(cf_inform,"","Protocol format error in authentation from IP %s\n",conn->hostname);
return false;
}
if (nonce_len > CF_NONCELEN*2)
{
CfOut(cf_inform,"","Protocol deviant authentication nonce from %s\n",conn->hostname);
return false;
}
if (crypt_len > 2*CF_NONCELEN)
{
CfOut(cf_inform,"","Protocol abuse in unlikely cipher from %s\n",conn->hostname);
return false;
}
/* Check there is no attempt to read past the end of the received input */
if (recvbuffer+CF_RSA_PROTO_OFFSET+nonce_len > recvbuffer+recvlen)
{
CfOut(cf_inform,"","Protocol consistency error in authentication from %s\n",conn->hostname);
return false;
}
if ((strcmp(sauth,"SAUTH") != 0) || (nonce_len == 0) || (crypt_len == 0))
{
CfOut(cf_inform,"","Protocol error in RSA authentication from IP %s\n",conn->hostname);
return false;
}
Debug("Challenge encryption = %c, nonce = %d, buf = %d\n",iscrypt,nonce_len,crypt_len);
ThreadLock(cft_system);
if ((decrypted_nonce = malloc(crypt_len)) == NULL)
{
FatalError("memory failure");
}
if (iscrypt == 'y')
{
if (RSA_private_decrypt(crypt_len,recvbuffer+CF_RSA_PROTO_OFFSET,decrypted_nonce,PRIVKEY,RSA_PKCS1_PADDING) <= 0)
{
err = ERR_get_error();
ThreadUnlock(cft_system);
CfOut(cf_error,"","Private decrypt failed = %s\n",ERR_reason_error_string(err));
free(decrypted_nonce);
return false;
}
}
else
{
if (nonce_len > crypt_len)
{
ThreadUnlock(cft_system);
CfOut(cf_error,"","Illegal challenge\n");
free(decrypted_nonce);
return false;
}
memcpy(decrypted_nonce,recvbuffer+CF_RSA_PROTO_OFFSET,nonce_len);
}
ThreadUnlock(cft_system);
/* Client's ID is now established by key or trusted, reply with digest */
HashString(decrypted_nonce,nonce_len,digest,digestType);
free(decrypted_nonce);
/* Get the public key from the client */
ThreadLock(cft_system);
newkey = RSA_new();
ThreadUnlock(cft_system);
/* proposition C2 */
if ((len_n = ReceiveTransaction(conn->sd_reply,recvbuffer,NULL)) == -1)
{
CfOut(cf_inform,"","Protocol error 1 in RSA authentation from IP %s\n",conn->hostname);
RSA_free(newkey);
return false;
}
if (len_n == 0)
{
CfOut(cf_inform,"","Protocol error 2 in RSA authentation from IP %s\n",conn->hostname);
RSA_free(newkey);
return false;
}
if ((newkey->n = BN_mpi2bn(recvbuffer,len_n,NULL)) == NULL)
{
err = ERR_get_error();
CfOut(cf_error,"","Private decrypt failed = %s\n",ERR_reason_error_string(err));
RSA_free(newkey);
return false;
}
/* proposition C3 */
if ((len_e = ReceiveTransaction(conn->sd_reply,recvbuffer,NULL)) == -1)
{
CfOut(cf_inform,"","Protocol error 3 in RSA authentation from IP %s\n",conn->hostname);
RSA_free(newkey);
return false;
}
if (len_e == 0)
{
CfOut(cf_inform,"","Protocol error 4 in RSA authentation from IP %s\n",conn->hostname);
RSA_free(newkey);
return false;
}
if ((newkey->e = BN_mpi2bn(recvbuffer,len_e,NULL)) == NULL)
{
err = ERR_get_error();
CfOut(cf_error,"","Private decrypt failed = %s\n",ERR_reason_error_string(err));
RSA_free(newkey);
return false;
}
if (DEBUG||D2)
{
RSA_print_fp(stdout,newkey,0);
}
HashPubKey(newkey,conn->digest,CF_DEFAULT_DIGEST);
if (VERBOSE)
{
ThreadLock(cft_output);
CfOut(cf_verbose,""," -> Public key identity of host \"%s\" is \"%s\"",conn->ipaddr,HashPrint(CF_DEFAULT_DIGEST,conn->digest));
ThreadUnlock(cft_output);
}
LastSaw(conn->username,conn->ipaddr,conn->digest,cf_accept);
if (!CheckStoreKey(conn,newkey)) /* conceals proposition S1 */
{
if (!conn->trust)
{
RSA_free(newkey);
return false;
}
}
/* Reply with digest of original challenge */
/* proposition S2 */
SendTransaction(conn->sd_reply,digest,digestLen,CF_DONE);
/* Send counter challenge to be sure this is a live session */
ThreadLock(cft_system);
counter_challenge = BN_new();
BN_rand(counter_challenge,CF_NONCELEN,0,0);
nonce_len = BN_bn2mpi(counter_challenge,in);
// hash the challenge from the client
HashString(in,nonce_len,digest,digestType);
encrypted_len = RSA_size(newkey); /* encryption buffer is always the same size as n */
if ((out = malloc(encrypted_len+1)) == NULL)
{
FatalError("memory failure");
}
if (RSA_public_encrypt(nonce_len,in,out,newkey,RSA_PKCS1_PADDING) <= 0)
{
err = ERR_get_error();
CfOut(cf_error,"","Public encryption failed = %s\n",ERR_reason_error_string(err));
RSA_free(newkey);
free(out);
return false;
}
ThreadUnlock(cft_system);
/* proposition S3 */
SendTransaction(conn->sd_reply,out,encrypted_len,CF_DONE);
/* if the client doesn't have our public key, send it */
if (iscrypt != 'y')
{
/* proposition S4 - conditional */
memset(in,0,CF_BUFSIZE);
len_n = BN_bn2mpi(PUBKEY->n,in);
SendTransaction(conn->sd_reply,in,len_n,CF_DONE);
/* proposition S5 - conditional */
memset(in,0,CF_BUFSIZE);
len_e = BN_bn2mpi(PUBKEY->e,in);
SendTransaction(conn->sd_reply,in,len_e,CF_DONE);
}
/* Receive reply to counter_challenge */
/* proposition C4 */
memset(in,0,CF_BUFSIZE);
if (ReceiveTransaction(conn->sd_reply,in,NULL) == -1)
{
BN_free(counter_challenge);
free(out);
RSA_free(newkey);
return false;
}
if (HashesMatch(digest,in,digestType)) /* replay / piggy in the middle attack ? */
{
if (!conn->trust)
{
CfOut(cf_verbose,""," -> Strong authentication of client %s/%s achieved",conn->hostname,conn->ipaddr);
}
else
{
CfOut(cf_verbose,""," -> Weak authentication of trusted client %s/%s (key accepted on trust).\n",conn->hostname,conn->ipaddr);
}
}
else
{
BN_free(counter_challenge);
free(out);
RSA_free(newkey);
CfOut(cf_inform,"","Challenge response from client %s was incorrect - ID false?",conn->ipaddr);
return false;
}
/* Receive random session key,... */
/* proposition C5 */
memset(in,0,CF_BUFSIZE);
if ((keylen = ReceiveTransaction(conn->sd_reply,in,NULL)) == -1)
{
BN_free(counter_challenge);
free(out);
RSA_free(newkey);
return false;
}
if (keylen > CF_BUFSIZE/2)
{
BN_free(counter_challenge);
free(out);
RSA_free(newkey);
CfOut(cf_inform,"","Session key length received from %s is too long",conn->ipaddr);
return false;
}
ThreadLock(cft_system);
session_size = CfSessionKeySize(enterprise_field);
conn->session_key = malloc(session_size);
conn->encryption_type = enterprise_field;
if (conn->session_key == NULL)
{
BN_free(counter_challenge);
free(out);
RSA_free(newkey);
return false;
}
CfOut(cf_verbose,""," -> Receiving session key from client (size=%d)...", keylen);
Debug("keylen=%d, session_size=%d\n", keylen, session_size);
if (keylen == CF_BLOWFISHSIZE) /* Support the old non-ecnrypted for upgrade */
{
memcpy(conn->session_key,in,session_size);
}
else
{
/* New protocol encrypted */
if (RSA_private_decrypt(keylen,in,out,PRIVKEY,RSA_PKCS1_PADDING) <= 0)
{
ThreadUnlock(cft_system);
err = ERR_get_error();
CfOut(cf_error,"","Private decrypt failed = %s\n",ERR_reason_error_string(err));
return false;
}
memcpy(conn->session_key,out,session_size);
}
ThreadUnlock(cft_system);
//DebugBinOut(conn->session_key,session_size,"Session key received");
BN_free(counter_challenge);
free(out);
RSA_free(newkey);
conn->rsa_auth = true;
return true;
}
/**************************************************************/
int StatFile(struct cfd_connection *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. */
{ struct cfstat cfst;
struct stat statbuf,statlinkbuf;
char linkbuf[CF_BUFSIZE],filename[CF_BUFSIZE];
int islink = false;
Debug("\nStatFile(%s)\n",filename);
TranslatePath(filename,ofilename);
memset(&cfst,0,sizeof(struct cfstat));
if (strlen(ReadLastNode(filename)) > CF_MAXLINKSIZE)
{
snprintf(sendbuffer,CF_BUFSIZE*2,"BAD: Filename suspiciously long [%s]\n",filename);
CfOut(cf_error,"",sendbuffer);
SendTransaction(conn->sd_reply,sendbuffer,0,CF_DONE);
return -1;
}
if (lstat(filename,&statbuf) == -1)
{
snprintf(sendbuffer,CF_BUFSIZE,"BAD: unable to stat file %s",filename);
CfOut(cf_verbose,"lstat",sendbuffer);
SendTransaction(conn->sd_reply,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 MINGW // windows doesn't support symbolic links
if (S_ISLNK(statbuf.st_mode))
{
islink = true;
cfst.cf_type = cf_link; /* pointless - overwritten */
cfst.cf_lmode = statbuf.st_mode & 07777;
cfst.cf_nlink = statbuf.st_nlink;
if (readlink(filename,linkbuf,CF_BUFSIZE-1) == -1)
{
sprintf(sendbuffer,"BAD: unable to read link\n");
CfOut(cf_error,"readlink",sendbuffer);
SendTransaction(conn->sd_reply,sendbuffer,0,CF_DONE);
return -1;
}
Debug("readlink: %s\n",linkbuf);
cfst.cf_readlink = linkbuf;
}
#endif /* NOT MINGW */
if (!islink && (cfstat(filename,&statbuf) == -1))
{
CfOut(cf_verbose,"stat","BAD: unable to stat file %s\n",filename);
SendTransaction(conn->sd_reply,sendbuffer,0,CF_DONE);
return -1;
}
Debug("Getting size of link deref %s\n",linkbuf);
if (islink && (cfstat(filename,&statlinkbuf) != -1)) /* linktype=copy used by agent */
{
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;
}
if (S_ISDIR(statbuf.st_mode))
{
cfst.cf_type = cf_dir;
}
if (S_ISREG(statbuf.st_mode))
{
cfst.cf_type = cf_reg;
}
if (S_ISSOCK(statbuf.st_mode))
{
cfst.cf_type = cf_sock;
}
if (S_ISCHR(statbuf.st_mode))
{
cfst.cf_type = cf_char;
}
if (S_ISBLK(statbuf.st_mode))
{
cfst.cf_type = cf_block;
}
if (S_ISFIFO(statbuf.st_mode))
{
cfst.cf_type = cf_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;
}
#if !defined(IRIX) && !defined(MINGW)
if (statbuf.st_size > statbuf.st_blocks * DEV_BSIZE)
#else
# ifdef HAVE_ST_BLOCKS
if (statbuf.st_size > statbuf.st_blocks * DEV_BSIZE)
# else
if (statbuf.st_size > ST_NBLOCKS(statbuf) * DEV_BSIZE)
# endif
#endif
{
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 */
Debug("OK: type=%d\n mode=%o\n lmode=%o\n uid=%d\n gid=%d\n size=%ld\n atime=%d\n mtime=%d\n",
cfst.cf_type,cfst.cf_mode,cfst.cf_lmode,cfst.cf_uid,cfst.cf_gid,(long)cfst.cf_size,
cfst.cf_atime,cfst.cf_mtime);
snprintf(sendbuffer,CF_BUFSIZE,"OK: %d %d %d %d %d %ld %d %d %d %d %d %d %d",
cfst.cf_type,cfst.cf_mode,cfst.cf_lmode,cfst.cf_uid,cfst.cf_gid,(long)cfst.cf_size,
cfst.cf_atime,cfst.cf_mtime,cfst.cf_ctime,cfst.cf_makeholes,cfst.cf_ino,
cfst.cf_nlink,cfst.cf_dev);
SendTransaction(conn->sd_reply,sendbuffer,0,CF_DONE);
memset(sendbuffer,0,CF_BUFSIZE);
if (cfst.cf_readlink != NULL)
{
strcpy(sendbuffer,"OK:");
strcat(sendbuffer,cfst.cf_readlink);
}
else
{
sprintf(sendbuffer,"OK:");
}
SendTransaction(conn->sd_reply,sendbuffer,0,CF_DONE);
return 0;
}
/***************************************************************/
void CfGetFile(struct cfd_get_arg *args)
{ int sd,fd,n_read,total=0,sendlen=0,count = 0;
char sendbuffer[CF_BUFSIZE+256],filename[CF_BUFSIZE];
struct stat sb;
int blocksize = 2048;
char *key;
sd = (args->connect)->sd_reply;
key = (args->connect)->session_key;
TranslatePath(filename,args->replyfile);
cfstat(filename,&sb);
Debug("CfGetFile(%s on sd=%d), size=%d\n",filename,sd,sb.st_size);
/* Now check to see if we have remote permission */
if (!TransferRights(filename,sd,args,sendbuffer,&sb))
{
RefuseAccess(args->connect,sendbuffer,args->buf_size,"");
snprintf(sendbuffer,CF_BUFSIZE,"%s",CF_FAILEDSTR);
SendSocketStream(sd,sendbuffer,args->buf_size,0);
}
/* File transfer */
if ((fd = SafeOpen(filename)) == -1)
{
CfOut(cf_error,"open","Open error of file [%s]\n",filename);
snprintf(sendbuffer,CF_BUFSIZE,"%s",CF_FAILEDSTR);
SendSocketStream(sd,sendbuffer,args->buf_size,0);
}
else
{
while(true)
{
memset(sendbuffer,0,CF_BUFSIZE);
Debug("Now reading from disk...\n");
if ((n_read = read(fd,sendbuffer,blocksize)) == -1)
{
CfOut(cf_error,"read","read failed in GetFile");
break;
}
if (n_read == 0)
{
break;
}
else
{ int savedlen = sb.st_size;
/* check the file is not changing at source */
if (count++ % 3 == 0) /* Don't do this too often */
{
stat(filename,&sb);
}
if (sb.st_size != savedlen)
{
snprintf(sendbuffer,CF_BUFSIZE,"%s%s: %s",CF_CHANGEDSTR1,CF_CHANGEDSTR2,filename);
if (SendSocketStream(sd,sendbuffer,blocksize,0) == -1)
{
CfOut(cf_verbose,"send","Send failed in GetFile");
}
Debug("Aborting transfer after %d: file is changing rapidly at source.\n",total);
break;
}
if ((savedlen - total)/blocksize > 0)
{
sendlen = blocksize;
}
else if (savedlen != 0)
{
sendlen = (savedlen - total);
}
}
total += n_read;
if (SendSocketStream(sd,sendbuffer,sendlen,0) == -1)
{
CfOut(cf_verbose,"send","Send failed in GetFile");
break;
}
}
close(fd);
}
Debug("Done with GetFile()\n");
}
/***************************************************************/
void CfEncryptGetFile(struct cfd_get_arg *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 sd,fd,n_read,total=0,cipherlen,count = 0,finlen,cnt = 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;
EVP_CIPHER_CTX ctx;
char *key,enctype;
struct stat sb;
int savedlen;
sd = (args->connect)->sd_reply;
key = (args->connect)->session_key;
enctype = (args->connect)->encryption_type;
TranslatePath(filename,args->replyfile);
cfstat(filename,&sb);
Debug("CfEncryptGetFile(%s on sd=%d), size=%d\n",filename,sd,sb.st_size);
/* Now check to see if we have remote permission */
if (!TransferRights(filename,sd,args,sendbuffer,&sb))
{
RefuseAccess(args->connect,sendbuffer,args->buf_size,"");
FailedTransfer(sd,sendbuffer,filename);
}
EVP_CIPHER_CTX_init(&ctx);
if ((fd = SafeOpen(filename)) == -1)
{
CfOut(cf_error,"open","Open error of file [%s]\n",filename);
FailedTransfer(sd,sendbuffer,filename);
}
else
{
while(true)
{
memset(sendbuffer,0,CF_BUFSIZE);
if ((n_read = read(fd,sendbuffer,blocksize)) == -1)
{
CfOut(cf_error,"read","read failed in EncryptGetFile");
break;
}
savedlen = sb.st_size;
if (count++ % 3 == 0) /* Don't do this too often */
{
Debug("Restatting %s - size %d\n",filename,n_read);
stat(filename,&sb);
}
if (sb.st_size != savedlen)
{
AbortTransfer(sd,sendbuffer,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(sd,sendbuffer,filename);
EVP_CIPHER_CTX_cleanup(&ctx);
close(fd);
return;
}
if (!EVP_EncryptFinal_ex(&ctx,out+cipherlen,&finlen))
{
FailedTransfer(sd,sendbuffer,filename);
EVP_CIPHER_CTX_cleanup(&ctx);
close(fd);
return;
}
}
cnt++;
//if (n_read < blocksize) // Last transaction
if (total >= savedlen)
{
if (SendTransaction(sd,out,cipherlen+finlen,CF_DONE) == -1)
{
CfOut(cf_verbose,"send","Send failed in GetFile");
EVP_CIPHER_CTX_cleanup(&ctx);
close(fd);
return;
}
break;
}
else
{
if (SendTransaction(sd,out,cipherlen+finlen,CF_MORE) == -1)
{
CfOut(cf_verbose,"send","Send failed in GetFile");
close(fd);
EVP_CIPHER_CTX_cleanup(&ctx);
return;
}
}
}
}
EVP_CIPHER_CTX_cleanup(&ctx);
close(fd);
}
/**************************************************************/
void CompareLocalHash(struct cfd_connection *conn,char *sendbuffer,char *recvbuffer)
{ unsigned char digest1[EVP_MAX_MD_SIZE+1],digest2[EVP_MAX_MD_SIZE+1];
char filename[CF_BUFSIZE],rfilename[CF_BUFSIZE];
char *sp;
int i;
/* TODO - when safe change this proto string to sha2 */
sscanf(recvbuffer,"MD5 %255[^\n]",rfilename);
sp = recvbuffer + strlen(recvbuffer) + CF_SMALL_OFFSET;
for (i = 0; i < CF_DEFAULT_DIGEST_LEN; i++)
{
digest1[i] = *sp++;
}
memset(sendbuffer,0,CF_BUFSIZE);
TranslatePath(filename,rfilename);
HashFile(filename,digest2,CF_DEFAULT_DIGEST);
if (HashesMatch(digest1,digest2,CF_DEFAULT_DIGEST) || HashesMatch(digest1,digest2,cf_md5))
{
sprintf(sendbuffer,"%s",CFD_FALSE);
Debug("Hashes matched ok\n");
SendTransaction(conn->sd_reply,sendbuffer,0,CF_DONE);
}
else
{
sprintf(sendbuffer,"%s",CFD_TRUE);
Debug("Hashes didn't match\n");
SendTransaction(conn->sd_reply,sendbuffer,0,CF_DONE);
}
}
/**************************************************************/
void GetServerLiteral(struct cfd_connection *conn,char *sendbuffer,char *recvbuffer,int encrypted)
{ char handle[CF_BUFSIZE],out[CF_BUFSIZE];
int cipherlen;
sscanf(recvbuffer,"VAR %255[^\n]",handle);
if (ReturnLiteralData(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(conn->encryption_type,sendbuffer,out,conn->session_key,strlen(sendbuffer)+1);
SendTransaction(conn->sd_reply,out,cipherlen,CF_DONE);
}
else
{
SendTransaction(conn->sd_reply,sendbuffer,0,CF_DONE);
}
}
/********************************************************************/
int GetServerQuery(struct cfd_connection *conn,char *sendbuffer,char *recvbuffer)
{ char query[CF_BUFSIZE];
query[0] = '\0';
sscanf(recvbuffer,"QUERY %255[^\n]",query);
if (strlen(query) == 0)
{
return false;
}
#ifdef HAVE_CONSTELLATION
if (cf_strncmp(query,"relay",5) == 0)
{
return Constellation_ReturnRelayQueryData(conn,query,sendbuffer);
}
#endif
#ifdef HAVE_NOVA
return Nova_ReturnQueryData(conn,query);
#else
return false;
#endif
}
/**************************************************************/
void ReplyServerContext(struct cfd_connection *conn,char *sendbuffer,char *recvbuffer,int encrypted,struct Item *classes)
{ char out[CF_BUFSIZE];
int cipherlen;
struct Item *ip;
memset(sendbuffer,0,CF_BUFSIZE);
for (ip = classes; ip != NULL; ip=ip->next)
{
if (strlen(sendbuffer) + strlen(ip->name) < CF_BUFSIZE-3)
{
strcat(sendbuffer,ip->name);
strcat(sendbuffer,",");
}
else
{
CfOut(cf_error,""," !! Overflow in context grab");
break;
}
}
DeleteItemList(classes);
if (encrypted)
{
cipherlen = EncryptString(conn->encryption_type,sendbuffer,out,conn->session_key,strlen(sendbuffer)+1);
SendTransaction(conn->sd_reply,out,cipherlen,CF_DONE);
}
else
{
SendTransaction(conn->sd_reply,sendbuffer,0,CF_DONE);
}
}
/**************************************************************/
int CfOpenDirectory(struct cfd_connection *conn,char *sendbuffer,char *oldDirname)
{ CFDIR *dirh;
const struct dirent *dirp;
int offset;
char dirname[CF_BUFSIZE];
TranslatePath(dirname, oldDirname);
Debug("CfOpenDirectory(%s)\n",dirname);
if (!IsAbsoluteFileName(dirname))
{
sprintf(sendbuffer,"BAD: request to access a non-absolute filename\n");
SendTransaction(conn->sd_reply,sendbuffer,0,CF_DONE);
return -1;
}
if ((dirh = OpenDirLocal(dirname)) == NULL)
{
Debug("cfengine, couldn't open dir %s\n",dirname);
snprintf(sendbuffer,CF_BUFSIZE,"BAD: cfengine, couldn't open dir %s\n",dirname);
SendTransaction(conn->sd_reply,sendbuffer,0,CF_DONE);
return -1;
}
/* Pack names for transmission */
memset(sendbuffer,0,CF_BUFSIZE);
offset = 0;
for (dirp = ReadDir(dirh); dirp != NULL; dirp = ReadDir(dirh))
{
if (strlen(dirp->d_name)+1+offset >= CF_BUFSIZE - CF_MAXLINKSIZE)
{
SendTransaction(conn->sd_reply,sendbuffer,offset+1,CF_MORE);
offset = 0;
memset(sendbuffer,0,CF_BUFSIZE);
}
strncpy(sendbuffer+offset,dirp->d_name,CF_MAXLINKSIZE);
offset += strlen(dirp->d_name) + 1; /* + zero byte separator */
}
strcpy(sendbuffer+offset,CFD_TERMINATOR);
SendTransaction(conn->sd_reply,sendbuffer,offset+2+strlen(CFD_TERMINATOR),CF_DONE);
Debug("END CfOpenDirectory(%s)\n",dirname);
CloseDir(dirh);
return 0;
}
/**************************************************************/
int CfSecOpenDirectory(struct cfd_connection *conn,char *sendbuffer,char *dirname)
{ CFDIR *dirh;
const struct dirent *dirp;
int offset,cipherlen;
char out[CF_BUFSIZE];
Debug("CfSecOpenDirectory(%s)\n",dirname);
if (!IsAbsoluteFileName(dirname))
{
sprintf(sendbuffer,"BAD: request to access a non-absolute filename\n");
cipherlen = EncryptString(conn->encryption_type,sendbuffer,out,conn->session_key,strlen(sendbuffer)+1);
SendTransaction(conn->sd_reply,out,0,CF_DONE);
return -1;
}
if ((dirh = OpenDirLocal(dirname)) == NULL)
{
CfOut(cf_verbose,"","Couldn't open dir %s\n",dirname);
snprintf(sendbuffer,CF_BUFSIZE,"BAD: cfengine, couldn't open dir %s\n",dirname);
cipherlen = EncryptString(conn->encryption_type,sendbuffer,out,conn->session_key,strlen(sendbuffer)+1);
SendTransaction(conn->sd_reply,out,0,CF_DONE);
return -1;
}
/* Pack names for transmission */
memset(sendbuffer,0,CF_BUFSIZE);
offset = 0;
for (dirp = ReadDir(dirh); dirp != NULL; dirp = ReadDir(dirh))
{
if (strlen(dirp->d_name)+1+offset >= CF_BUFSIZE - CF_MAXLINKSIZE)
{
cipherlen = EncryptString(conn->encryption_type,sendbuffer,out,conn->session_key,offset+1);
SendTransaction(conn->sd_reply,out,cipherlen,CF_MORE);
offset = 0;
memset(sendbuffer,0,CF_BUFSIZE);
memset(out,0,CF_BUFSIZE);
}
strncpy(sendbuffer+offset,dirp->d_name,CF_MAXLINKSIZE);
/* + zero byte separator */
offset += strlen(dirp->d_name) + 1;
}
strcpy(sendbuffer+offset,CFD_TERMINATOR);
cipherlen = EncryptString(conn->encryption_type,sendbuffer,out,conn->session_key,offset+2+strlen(CFD_TERMINATOR));
SendTransaction(conn->sd_reply,out,cipherlen,CF_DONE);
Debug("END CfSecOpenDirectory(%s)\n",dirname);
CloseDir(dirh);
return 0;
}
/***************************************************************/
void Terminate(int sd)
{ char buffer[CF_BUFSIZE];
memset(buffer,0,CF_BUFSIZE);
strcpy(buffer,CFD_TERMINATOR);
if (SendTransaction(sd,buffer,strlen(buffer)+1,CF_DONE) == -1)
{
CfOut(cf_verbose,"send","Unable to reply with terminator");
CfOut(cf_verbose,"","Unable to reply with terminator...\n");
}
}
/***************************************************************/
void DeleteAuthList(struct Auth *ap)
{
if (ap != NULL)
{
DeleteAuthList(ap->next);
ap->next = NULL;
DeleteItemList(ap->accesslist);
DeleteItemList(ap->maproot);
free(ap->path);
free((char *)ap);
}
}
/***************************************************************/
/* Level 5 */
/***************************************************************/
int OptionFound(char *args, char *pos, char *word)
/*
* Returns true if the current position 'pos' in buffer
* 'args' corresponds to the word 'word'. Words are
* separated by spaces.
*/
{ size_t len;
if (pos < args)
{
return false;
}
/* Single options do not have to have spaces between */
if (strlen(word) == 2 && strncmp(pos,word,2) == 0)
{
return true;
}
len = strlen(word);
if (strncmp(pos, word, len) != 0)
{
return false;
}
if (pos == args)
{
return true;
}
else if (*(pos-1) == ' ' && (pos[len] == ' ' || pos[len] == '\0'))
{
return true;
}
else
{
return false;
}
}
/**************************************************************/
void RefuseAccess(struct cfd_connection *conn,char *sendbuffer,int size,char *errmesg)
{ char *hostname, *username, *ipaddr;
static char *def = "?";
if (strlen(conn->hostname) == 0)
{
hostname = def;
}
else
{
hostname = conn->hostname;
}
if (strlen(conn->username) == 0)
{
username = def;
}
else
{
username = conn->username;
}
if (strlen(conn->ipaddr) == 0)
{
ipaddr = def;
}
else
{
ipaddr = conn->ipaddr;
}
snprintf(sendbuffer,CF_BUFSIZE,"%s",CF_FAILEDSTR);
SendTransaction(conn->sd_reply,sendbuffer,size,CF_DONE);
CfOut(cf_inform,"","From (host=%s,user=%s,ip=%s)",hostname,username,ipaddr);
if (strlen(errmesg) > 0)
{
if (LOGCONNS)
{
CfOut(cf_log,"","REFUSAL of request from connecting host: (%s)",errmesg);
}
else
{
CfOut(cf_verbose,"","REFUSAL of request from connecting host: (%s)",errmesg);
}
}
}
/***************************************************************/
int TransferRights(char *filename,int sd,struct cfd_get_arg *args,char *sendbuffer, struct stat *sb)
{
#ifdef MINGW
SECURITY_DESCRIPTOR *secDesc;
SID *ownerSid;
if (GetNamedSecurityInfo(filename, SE_FILE_OBJECT, OWNER_SECURITY_INFORMATION,(PSID*)&ownerSid,NULL,NULL,NULL,&secDesc) == ERROR_SUCCESS)
{
if (IsValidSid((args->connect)->sid) && EqualSid(ownerSid, (args->connect)->sid))
{
Debug("Caller %s is the owner of the file\n",(args->connect)->username);
}
else
{
// If the process doesn't own the file, we can access if we are
// root AND granted root map
LocalFree(secDesc);
if (args->connect->maproot)
{
CfOut(cf_verbose,"","Caller %s not owner of \"%s\", but mapping privilege\n", (args->connect)->username, filename);
return true;
}
else
{
CfOut(cf_verbose, "", "!! Remote user denied right to file \"%s\" (consider maproot?)", filename);
return false;
}
}
LocalFree(secDesc);
}
else
{
CfOut(cf_error,"GetNamedSecurityInfo","!! Could not retreive existing owner of \"%s\"", filename);
return false;
}
#else
uid_t uid = (args->connect)->uid;
if (uid != 0 && !args->connect->maproot) /* should remote root be local root */
{
if (sb->st_uid == uid)
{
Debug("Caller %s is the owner of the file\n",(args->connect)->username);
}
else
{
if (sb->st_mode & S_IROTH)
{
Debug("Caller %s not owner of the file but permission granted\n",(args->connect)->username);
}
else
{
Debug("Caller %s is not the owner of the file\n",(args->connect)->username);
CfOut(cf_verbose, "", "!! Remote user denied right to file \"%s\" (consider maproot?)", filename);
return false;
}
}
}
#endif
return true;
}
/***************************************************************/
void AbortTransfer(int sd,char *sendbuffer,char *filename)
{
CfOut(cf_verbose,"","Aborting transfer of file due to source changes\n");
snprintf(sendbuffer,CF_BUFSIZE,"%s%s: %s",CF_CHANGEDSTR1,CF_CHANGEDSTR2,filename);
if (SendTransaction(sd,sendbuffer,0,CF_DONE) == -1)
{
CfOut(cf_verbose,"send","Send failed in GetFile");
}
}
/***************************************************************/
void FailedTransfer(int sd,char *sendbuffer,char *filename)
{
CfOut(cf_verbose,"","Transfer failure\n");
snprintf(sendbuffer,CF_BUFSIZE,"%s",CF_FAILEDSTR);
if (SendTransaction(sd,sendbuffer,0,CF_DONE) == -1)
{
CfOut(cf_verbose,"send","Send failed in GetFile");
}
}
/***************************************************************/
void ReplyNothing(struct cfd_connection *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->sd_reply,buffer,0,CF_DONE) == -1)
{
CfOut(cf_error,"send","");
}
}
/***************************************************************/
int CheckStoreKey(struct cfd_connection *conn,RSA *key)
{ RSA *savedkey;
char udigest[CF_MAXVARSIZE];
ThreadLock(cft_output);
snprintf(udigest,CF_MAXVARSIZE-1,"%s",HashPrint(CF_DEFAULT_DIGEST,conn->digest));
ThreadUnlock(cft_output);
if ((savedkey = HavePublicKey(conn->username,MapAddress(conn->ipaddr),udigest)))
{
CfOut(cf_verbose,"","A public key was already known from %s/%s - no trust required\n",conn->hostname,conn->ipaddr);
CfOut(cf_verbose,"","Adding IP %s to SkipVerify - no need to check this if we have a key\n",conn->ipaddr);
IdempPrependItem(&SKIPVERIFY,MapAddress(conn->ipaddr),NULL);
if ((BN_cmp(savedkey->e,key->e) == 0) && (BN_cmp(savedkey->n,key->n) == 0))
{
CfOut(cf_verbose,"","The public key identity was confirmed as %s@%s\n",conn->username,conn->hostname);
SendTransaction(conn->sd_reply,"OK: key accepted",0,CF_DONE);
RSA_free(savedkey);
return true;
}
}
/* Finally, if we're still here, we should consider trusting a new key ... */
if ((TRUSTKEYLIST != NULL) && IsMatchItemIn(TRUSTKEYLIST,MapAddress(conn->ipaddr)))
{
CfOut(cf_verbose,"","Host %s/%s was found in the list of hosts to trust\n",conn->hostname,conn->ipaddr);
conn->trust = true;
/* conn->maproot = false; ?? */
SendTransaction(conn->sd_reply,"OK: unknown key was accepted on trust",0,CF_DONE);
SavePublicKey(conn->username,MapAddress(conn->ipaddr),udigest,key);
return true;
}
else
{
CfOut(cf_verbose,"","No previous key found, and unable to accept this one on trust\n");
SendTransaction(conn->sd_reply,"BAD: key could not be accepted on trust",0,CF_DONE);
return false;
}
}
/***************************************************************/
/* Toolkit/Class: conn */
/***************************************************************/
struct cfd_connection *NewConn(int sd) /* construct */
{ struct cfd_connection *conn;
ThreadLock(cft_system);
conn = (struct cfd_connection *) malloc(sizeof(struct cfd_connection));
ThreadUnlock(cft_system);
if (conn == NULL)
{
CfOut(cf_error,"malloc","Unable to allocate conn");
HandleSignals(SIGTERM);
}
conn->sd_reply = sd;
conn->id_verified = false;
conn->rsa_auth = false;
conn->trust = false;
conn->hostname[0] = '\0';
conn->ipaddr[0] = '\0';
conn->username[0] = '\0';
conn->session_key = NULL;
conn->encryption_type = 'c';
Debug("*** New socket [%d]\n",sd);
return conn;
}
/***************************************************************/
void DeleteConn(struct cfd_connection *conn) /* destruct */
{
Debug("***Closing socket %d from %s\n",conn->sd_reply,conn->ipaddr);
cf_closesocket(conn->sd_reply);
if (conn->session_key != NULL)
{
free(conn->session_key);
}
if (conn->ipaddr != NULL)
{
if (!ThreadLock(cft_count))
{
return;
}
DeleteItemMatching(&CONNECTIONLIST,MapAddress(conn->ipaddr));
if (!ThreadUnlock(cft_count))
{
return;
}
}
free((char *)conn);
}
/***************************************************************/
/* ERS */
/***************************************************************/
int SafeOpen(char *filename)
{ int fd;
ThreadLock(cft_system);
fd = open(filename,O_RDONLY);
ThreadUnlock(cft_system);
return fd;
}
/***************************************************************/
void SafeClose(int fd)
{
ThreadLock(cft_system);
close(fd);
ThreadUnlock(cft_system);
}
/***************************************************************/
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);
}
/* EOF */
cfengine-3.2.4/src/env_monitor.c 0000644 0001750 0001750 00000062760 11715232734 013531 0000000 0000000 /*
Copyright (C) Cfengine AS
This file is part of Cfengine 3 - written and maintained by Cfengine 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 Commerical Open Source License
(COSL) may apply to this file if you as a licensee so wish it. See
included file COSL.txt.
*/
/*****************************************************************************/
/* */
/* File: env_monitor.c */
/* */
/*****************************************************************************/
#include "cf3.defs.h"
#include "cf3.extern.h"
#include "monitoring.h"
#include
/*****************************************************************************/
/* Globals */
/*****************************************************************************/
static double HISTOGRAM[CF_OBSERVABLES][7][CF_GRAINS];
/* persistent observations */
static double CF_THIS[CF_OBSERVABLES]; /* New from 2.1.21 replacing above - current observation */
/* Work */
static long ITER; /* Iteration since start */
static double AGE,WAGE; /* Age and weekly age of database */
static struct Averages LOCALAV;
/* Leap Detection vars */
static double LDT_BUF[CF_OBSERVABLES][LDT_BUFSIZE];
static double LDT_SUM[CF_OBSERVABLES];
static double LDT_AVG[CF_OBSERVABLES];
static double CHI_LIMIT[CF_OBSERVABLES];
static double CHI[CF_OBSERVABLES];
static double LDT_MAX[CF_OBSERVABLES];
static int LDT_POS = 0;
static int LDT_FULL = false;
int NO_FORK = false;
/*******************************************************************/
/* Prototypes */
/*******************************************************************/
static void GetDatabaseAge(void);
static void LoadHistogram(void);
static void GetQ(void);
static struct Averages EvalAvQ(char *timekey);
static void ArmClasses(struct Averages newvals,char *timekey);
static void GatherPromisedMeasures(void);
static void LeapDetection(void);
static struct Averages *GetCurrentAverages(char *timekey);
static void UpdateAverages(char *timekey, struct Averages newvals);
static void UpdateDistributions(char *timekey, struct Averages *av);
static double WAverage(double newvals,double oldvals, double age);
static double SetClasses(char *name,double variable,double av_expect,double av_var,double localav_expect,double localav_var,struct Item **classlist,char *timekey);
static void SetVariable(char *name,double now, double average, double stddev, struct Item **list);
static double RejectAnomaly(double new,double av,double var,double av2,double var2);
static void ZeroArrivals (void);
static void KeepMonitorPromise(struct Promise *pp);
/****************************************************************/
void MonInitialize(void)
{
int i,j,k;
char vbuff[CF_BUFSIZE];
for (i = 0; i < ATTR; i++)
{
sprintf(vbuff,"%s/state/cf_incoming.%s",CFWORKDIR,ECGSOCKS[i].name);
MapName(vbuff);
CreateEmptyFile(vbuff);
sprintf(vbuff,"%s/state/cf_outgoing.%s",CFWORKDIR,ECGSOCKS[i].name);
MapName(vbuff);
CreateEmptyFile(vbuff);
}
sprintf(vbuff,"%s/state/cf_users",CFWORKDIR);
MapName(vbuff);
CreateEmptyFile(vbuff);
snprintf(AVDB,CF_MAXVARSIZE,"%s/state/%s",CFWORKDIR,CF_AVDB_FILE);
MapName(AVDB);
MonEntropyClassesInit();
GetDatabaseAge();
for (i = 0; i < CF_OBSERVABLES; i++)
{
LOCALAV.Q[i].expect = 0.0;
LOCALAV.Q[i].var = 0.0;
LOCALAV.Q[i].q = 0.0;
}
for (i = 0; i < 7; i++)
{
for (j = 0; j < CF_OBSERVABLES; j++)
{
for (k = 0; k < CF_GRAINS; k++)
{
HISTOGRAM[i][j][k] = 0;
}
}
}
for (i = 0; i < CF_OBSERVABLES; i++)
{
CHI[i] = 0;
CHI_LIMIT[i] = 0.1;
LDT_AVG[i] = 0;
LDT_SUM[i] = 0;
}
srand((unsigned int)time(NULL));
LoadHistogram();
/* Look for local sensors - this is unfortunately linux-centric */
MonTempInit();
MonOtherInit();
Debug("Finished with initialization.\n");
}
/*********************************************************************/
/* Level 2 */
/*********************************************************************/
static void GetDatabaseAge()
{
CF_DB *dbp;
if (!OpenDB(AVDB,&dbp))
{
return;
}
cf_chmod(AVDB,0644);
if (ReadDB(dbp,"DATABASE_AGE",&AGE,sizeof(double)))
{
WAGE = AGE / CF_WEEK * CF_MEASURE_INTERVAL;
Debug("\n\nPrevious DATABASE_AGE %f\n\n",AGE);
}
else
{
Debug("No previous AGE\n");
AGE = 0.0;
}
CloseDB(dbp);
}
/*********************************************************************/
static void LoadHistogram(void)
{
FILE *fp;
int i,day,position;
double maxval[CF_OBSERVABLES];
char filename[CF_BUFSIZE];
snprintf(filename,CF_BUFSIZE,"%s/state/histograms",CFWORKDIR);
if ((fp = fopen(filename,"r")) == NULL)
{
CfOut(cf_verbose,"fopen","Unable to load histogram data");
return;
}
for (i = 0; i < CF_OBSERVABLES; i++)
{
maxval[i] = 1.0;
}
for (position = 0; position < CF_GRAINS; position++)
{
fscanf(fp,"%d ",&position);
for (i = 0; i < CF_OBSERVABLES; i++)
{
for (day = 0; day < 7; day++)
{
fscanf(fp,"%lf ",&(HISTOGRAM[i][day][position]));
if (HISTOGRAM[i][day][position] < 0)
{
HISTOGRAM[i][day][position] = 0;
}
if (HISTOGRAM[i][day][position] > maxval[i])
{
maxval[i] = HISTOGRAM[i][day][position];
}
HISTOGRAM[i][day][position] *= 1000.0/maxval[i];
}
}
}
fclose(fp);
}
/*********************************************************************/
void StartServer(int argc,char **argv)
{
char timekey[CF_SMALLBUF];
struct Averages averages;
struct Promise *pp = NewPromise("monitor_cfengine","the monitor daemon");
struct Attributes dummyattr;
struct CfLock thislock;
#ifdef MINGW
if(!NO_FORK)
{
CfOut(cf_verbose, "", "Windows does not support starting processes in the background - starting in foreground");
}
#else /* NOT MINGW */
if ((!NO_FORK) && (fork() != 0))
{
CfOut(cf_inform,"","cf-monitord: starting\n");
exit(0);
}
if (!NO_FORK)
{
ActAsDaemon(0);
}
#endif /* NOT MINGW */
memset(&dummyattr,0,sizeof(dummyattr));
dummyattr.transaction.ifelapsed = 0;
dummyattr.transaction.expireafter = 0;
thislock = AcquireLock(pp->promiser,VUQNAME,CFSTARTTIME,dummyattr,pp,false);
if (thislock.lock == NULL)
{
return;
}
WritePID("cf-monitord.pid");
MonNetworkSnifferOpen();
while (true)
{
GetQ();
snprintf(timekey, sizeof(timekey), "%s", GenTimeKey(time(NULL)));
averages = EvalAvQ(timekey);
LeapDetection();
ArmClasses(averages,timekey);
ZeroArrivals();
MonNetworkSnifferSniff(ITER, CF_THIS);
ITER++;
}
}
/*********************************************************************/
static void GetQ(void)
{
Debug("========================= GET Q ==============================\n");
MonEntropyClassesReset();
ZeroArrivals();
MonProcessesGatherData(CF_THIS);
#ifndef MINGW
MonCPUGatherData(CF_THIS);
MonLoadGatherData(CF_THIS);
MonDiskGatherData(CF_THIS);
MonNetworkGatherData(CF_THIS);
MonNetworkSnifferGatherData(CF_THIS);
MonTempGatherData(CF_THIS);
#endif /* NOT MINGW */
MonOtherGatherData(CF_THIS);
GatherPromisedMeasures();
}
/*********************************************************************/
static struct Averages EvalAvQ(char *t)
{
struct Averages *currentvals,newvals;
double This[CF_OBSERVABLES];
char name[CF_MAXVARSIZE];
int i;
Banner("Evaluating and storing new weekly averages");
if ((currentvals = GetCurrentAverages(t)) == NULL)
{
CfOut(cf_error,"","Error reading average database");
exit(1);
}
/* Discard any apparently anomalous behaviour before renormalizing database */
for (i = 0; i < CF_OBSERVABLES; i++)
{
double delta2;
name[0] = '\0';
CfGetClassName(i,name);
/* Overflow protection */
if (currentvals->Q[i].expect < 0)
{
currentvals->Q[i].expect = 0;
}
if (currentvals->Q[i].q < 0)
{
currentvals->Q[i].q = 0;
}
if (currentvals->Q[i].var < 0)
{
currentvals->Q[i].var = 0;
}
This[i] = RejectAnomaly(CF_THIS[i],currentvals->Q[i].expect,currentvals->Q[i].var,LOCALAV.Q[i].expect,LOCALAV.Q[i].var);
newvals.Q[i].q = This[i];
LOCALAV.Q[i].q = This[i];
Debug("Current %s.q %lf\n",name,currentvals->Q[i].q);
Debug("Current %s.var %lf\n",name,currentvals->Q[i].var);
Debug("Current %s.ex %lf\n",name,currentvals->Q[i].expect);
Debug("CF_THIS[%s] = %lf\n",name,CF_THIS[i]);
Debug("This[%s] = %lf\n",name,This[i]);
newvals.Q[i].expect = WAverage(This[i],currentvals->Q[i].expect,WAGE);
LOCALAV.Q[i].expect = WAverage(newvals.Q[i].expect,LOCALAV.Q[i].expect,ITER);
delta2 = (This[i] - currentvals->Q[i].expect)*(This[i] - currentvals->Q[i].expect);
if (currentvals->Q[i].var > delta2*2.0)
{
/* Clean up past anomalies */
newvals.Q[i].var = delta2;
LOCALAV.Q[i].var = WAverage(newvals.Q[i].var,LOCALAV.Q[i].var,ITER);
}
else
{
newvals.Q[i].var = WAverage(delta2,currentvals->Q[i].var,WAGE);
LOCALAV.Q[i].var = WAverage(newvals.Q[i].var,LOCALAV.Q[i].var,ITER);
}
CfOut(cf_verbose, "", "[%d] %s q=%lf, var=%lf, ex=%lf", i, name,
newvals.Q[i].q, newvals.Q[i].var, newvals.Q[i].expect);
CfOut(cf_verbose,"","[%d] = %lf -> (%lf#%lf) local [%lf#%lf]\n", i, This[i],newvals.Q[i].expect,sqrt(newvals.Q[i].var),LOCALAV.Q[i].expect,sqrt(LOCALAV.Q[i].var));
if (This[i] > 0)
{
CfOut(cf_verbose,"","Storing %.2lf in %s\n",This[i],name);
}
}
UpdateAverages(t,newvals);
UpdateDistributions(t,currentvals); /* Distribution about mean */
return newvals;
}
/*********************************************************************/
static void LeapDetection(void)
{
int i,last_pos = LDT_POS;
double n1,n2,d;
double padding = 0.2;
if (++LDT_POS >= LDT_BUFSIZE)
{
LDT_POS = 0;
if (!LDT_FULL)
{
Debug("LDT Buffer full at %d\n",LDT_BUFSIZE);
LDT_FULL = true;
}
}
for (i = 0; i < CF_OBSERVABLES; i++)
{
/* First do some anomaly rejection. Sudden jumps must be numerical errors. */
if (LDT_BUF[i][last_pos] > 0 && CF_THIS[i]/LDT_BUF[i][last_pos] > 1000)
{
CF_THIS[i] = LDT_BUF[i][last_pos];
}
/* Note AVG should contain n+1 but not SUM, hence funny increments */
LDT_AVG[i] = LDT_AVG[i] + CF_THIS[i]/((double)LDT_BUFSIZE + 1.0);
d = (double)(LDT_BUFSIZE * (LDT_BUFSIZE + 1)) * LDT_AVG[i];
if (LDT_FULL && (LDT_POS == 0))
{
n2 = (LDT_SUM[i] - (double)LDT_BUFSIZE * LDT_MAX[i]);
if (d < 0.001)
{
CHI_LIMIT[i] = 0.5;
}
else
{
CHI_LIMIT[i] = padding + sqrt(n2*n2/d);
}
LDT_MAX[i] = 0.0;
}
if (CF_THIS[i] > LDT_MAX[i])
{
LDT_MAX[i] = CF_THIS[i];
}
n1 = (LDT_SUM[i] - (double)LDT_BUFSIZE * CF_THIS[i]);
if (d < 0.001)
{
CHI[i] = 0.0;
}
else
{
CHI[i] = sqrt(n1*n1/d);
}
LDT_AVG[i] = LDT_AVG[i] - LDT_BUF[i][LDT_POS]/((double)LDT_BUFSIZE + 1.0);
LDT_BUF[i][LDT_POS] = CF_THIS[i];
LDT_SUM[i] = LDT_SUM[i] - LDT_BUF[i][LDT_POS] + CF_THIS[i];
}
}
/*********************************************************************/
static void ArmClasses(struct Averages av,char *timekey)
{
double sigma;
struct Item *classlist = NULL;
int i,j,k;
char buff[CF_BUFSIZE],ldt_buff[CF_BUFSIZE],name[CF_MAXVARSIZE];
static int anomaly[CF_OBSERVABLES][LDT_BUFSIZE];
static double anomaly_chi[CF_OBSERVABLES];
static double anomaly_chi_limit[CF_OBSERVABLES];
Debug("Arm classes for %s\n",timekey);
for (i = 0; i < CF_OBSERVABLES; i++)
{
CfGetClassName(i,name);
sigma = SetClasses(name,CF_THIS[i],av.Q[i].expect,av.Q[i].var,LOCALAV.Q[i].expect,LOCALAV.Q[i].var,&classlist,timekey);
SetVariable(name,CF_THIS[i],av.Q[i].expect,sigma,&classlist);
/* LDT */
ldt_buff[0] = '\0';
anomaly[i][LDT_POS] = false;
if (!LDT_FULL)
{
anomaly[i][LDT_POS] = false;
anomaly_chi[i] = 0.0;
anomaly_chi_limit[i] = 0.0;
}
if (LDT_FULL && (CHI[i] > CHI_LIMIT[i]))
{
anomaly[i][LDT_POS] = true; /* Remember the last anomaly value */
anomaly_chi[i] = CHI[i];
anomaly_chi_limit[i] = CHI_LIMIT[i];
CfOut(cf_verbose,"","LDT(%d) in %s chi = %.2f thresh %.2f \n",LDT_POS,name,CHI[i],CHI_LIMIT[i]);
/* Last printed element is now */
for (j = LDT_POS+1, k = 0; k < LDT_BUFSIZE; j++,k++)
{
if (j == LDT_BUFSIZE) /* Wrap */
{
j = 0;
}
if (anomaly[i][j])
{
snprintf(buff,CF_BUFSIZE," *%.2f*",LDT_BUF[i][j]);
}
else
{
snprintf(buff,CF_BUFSIZE," %.2f",LDT_BUF[i][j]);
}
strcat(ldt_buff,buff);
}
if (CF_THIS[i] > av.Q[i].expect)
{
snprintf(buff,CF_BUFSIZE,"%s_high_ldt",name);
}
else
{
snprintf(buff,CF_BUFSIZE,"%s_high_ldt",name);
}
AppendItem(&classlist,buff,"2");
NewPersistentContext(buff,CF_PERSISTENCE,cfpreserve);
}
else
{
for (j = LDT_POS+1, k = 0; k < LDT_BUFSIZE; j++,k++)
{
if (j == LDT_BUFSIZE) /* Wrap */
{
j = 0;
}
if (anomaly[i][j])
{
snprintf(buff,CF_BUFSIZE," *%.2f*",LDT_BUF[i][j]);
}
else
{
snprintf(buff,CF_BUFSIZE," %.2f",LDT_BUF[i][j]);
}
strcat(ldt_buff,buff);
}
}
/* Not using these for now
snprintf(buff,CF_MAXVARSIZE,"ldtbuf_%s=%s",name,ldt_buff);
AppendItem(&classlist,buff,"");
snprintf(buff,CF_MAXVARSIZE,"ldtchi_%s=%.2f",name,anomaly_chi[i]);
AppendItem(&classlist,buff,"");
snprintf(buff,CF_MAXVARSIZE,"ldtlimit_%s=%.2f",name,anomaly_chi_limit[i]);
AppendItem(&classlist,buff,"");
*/
}
SetMeasurementPromises(&classlist);
/* Publish class list */
MonEntropyClassesPublish(classlist);
}
/*****************************************************************************/
static struct Averages *GetCurrentAverages(char *timekey)
{
CF_DB *dbp;
static struct Averages entry;
if (!OpenDB(AVDB,&dbp))
{
return NULL;
}
memset(&entry,0,sizeof(entry));
AGE++;
WAGE = AGE / CF_WEEK * CF_MEASURE_INTERVAL;
if (ReadDB(dbp,timekey,&entry,sizeof(struct Averages)))
{
int i;
for (i = 0; i < CF_OBSERVABLES; i++)
{
Debug("Previous values (%lf,..) for time index %s\n\n",entry.Q[i].expect,timekey);
}
}
else
{
Debug("No previous value for time index %s\n",timekey);
}
CloseDB(dbp);
return &entry;
}
/*****************************************************************************/
static void UpdateAverages(char *timekey,struct Averages newvals)
{
CF_DB *dbp;
if (!OpenDB(AVDB,&dbp))
{
return;
}
CfOut(cf_inform,"","Updated averages at %s\n",timekey);
WriteDB(dbp,timekey,&newvals,sizeof(struct Averages));
WriteDB(dbp,"DATABASE_AGE",&AGE,sizeof(double));
CloseDB(dbp);
HistoryUpdate(newvals);
}
/*****************************************************************************/
static void UpdateDistributions(char *timekey,struct Averages *av)
{
int position,day,i;
char filename[CF_BUFSIZE];
FILE *fp;
/* Take an interval of 4 standard deviations from -2 to +2, divided into CF_GRAINS
parts. Centre each measurement on CF_GRAINS/2 and scale each measurement by the
std-deviation for the current time.
*/
if (IsDefinedClass("Min40_45"))
{
day = Day2Number(timekey);
for (i = 0; i < CF_OBSERVABLES; i++)
{
position = CF_GRAINS/2 + (int)(0.5+(CF_THIS[i] - av->Q[i].expect)*CF_GRAINS/(4*sqrt((av->Q[i].var))));
if (0 <= position && position < CF_GRAINS)
{
HISTOGRAM[i][day][position]++;
}
}
snprintf(filename,CF_BUFSIZE,"%s/state/histograms",CFWORKDIR);
if ((fp = fopen(filename,"w")) == NULL)
{
CfOut(cf_error,"fopen","Unable to save histograms");
return;
}
for (position = 0; position < CF_GRAINS; position++)
{
fprintf(fp,"%d ",position);
for (i = 0; i < CF_OBSERVABLES; i++)
{
for (day = 0; day < 7; day++)
{
fprintf(fp,"%.0lf ",HISTOGRAM[i][day][position]);
}
}
fprintf(fp,"\n");
}
fclose(fp);
}
}
/*****************************************************************************/
/* For a couple of weeks, learn eagerly. Otherwise variances will
be way too large. Then downplay newer data somewhat, and rely on
experience of a couple of months of data ... */
static double WAverage(double anew,double aold,double age)
{
double av,cf_sane_monitor_limit = 9999999.0;
double wnew,wold;
/* First do some database corruption self-healing */
if (aold > cf_sane_monitor_limit && anew > cf_sane_monitor_limit)
{
return 0;
}
if (aold > cf_sane_monitor_limit)
{
return anew;
}
if (aold > cf_sane_monitor_limit)
{
return aold;
}
/* Now look at the self-learning */
if (FORGETRATE > 0.9 || FORGETRATE < 0.1)
{
FORGETRATE = 0.6;
}
if (age < 2.0) /* More aggressive learning for young database */
{
wnew = FORGETRATE;
wold = (1.0-FORGETRATE);
}
else
{
wnew = (1.0-FORGETRATE);
wold = FORGETRATE;
}
if (aold == 0 && anew == 0)
{
return 0;
}
/*
* AV = (Wnew*Anew + Wold*Aold) / (Wnew + Wold).
*
* Wnew + Wold always equals to 1, so we omit it for better precision and
* performance.
*/
av = (wnew*anew + wold*aold);
if (av < 0)
{
/* Accuracy lost - something wrong */
return 0.0;
}
return av;
}
/*****************************************************************************/
static double SetClasses(char * name,double variable,double av_expect,double av_var,double localav_expect,double localav_var,struct Item **classlist,char *timekey)
{
char buffer[CF_BUFSIZE],buffer2[CF_BUFSIZE];
double dev,delta,sigma,ldelta,lsigma,sig;
Debug("\n SetClasses(%s,X=%lf,avX=%lf,varX=%lf,lavX=%lf,lvarX=%lf,%s)\n",name,variable,av_expect,av_var,localav_expect,localav_var,timekey);
delta = variable - av_expect;
sigma = sqrt(av_var);
ldelta = variable - localav_expect;
lsigma = sqrt(localav_var);
sig = sqrt(sigma*sigma+lsigma*lsigma);
Debug(" delta = %lf,sigma = %lf, lsigma = %lf, sig = %lf\n",delta,sigma,lsigma,sig);
if (sigma == 0.0 || lsigma == 0.0)
{
Debug(" No sigma variation .. can't measure class\n");
return sig;
}
Debug("Setting classes for %s...\n",name);
if (fabs(delta) < cf_noise_threshold) /* Arbitrary limits on sensitivity */
{
Debug(" Sensitivity too high ..\n");
buffer[0] = '\0';
strcpy(buffer,name);
if ((delta > 0) && (ldelta > 0))
{
strcat(buffer,"_high");
}
else if ((delta < 0) && (ldelta < 0))
{
strcat(buffer,"_low");
}
else
{
strcat(buffer,"_normal");
}
dev = sqrt(delta*delta/(1.0+sigma*sigma)+ldelta*ldelta/(1.0+lsigma*lsigma));
if (dev > 2.0*sqrt(2.0))
{
strcpy(buffer2,buffer);
strcat(buffer2,"_microanomaly");
AppendItem(classlist,buffer2,"2");
NewPersistentContext(buffer2,CF_PERSISTENCE,cfpreserve);
}
return sig; /* Granularity makes this silly */
}
else
{
buffer[0] = '\0';
strcpy(buffer,name);
if ((delta > 0) && (ldelta > 0))
{
strcat(buffer,"_high");
}
else if ((delta < 0) && (ldelta < 0))
{
strcat(buffer,"_low");
}
else
{
strcat(buffer,"_normal");
}
dev = sqrt(delta*delta/(1.0+sigma*sigma)+ldelta*ldelta/(1.0+lsigma*lsigma));
if (dev <= sqrt(2.0))
{
strcpy(buffer2,buffer);
strcat(buffer2,"_normal");
AppendItem(classlist,buffer2,"0");
}
else
{
strcpy(buffer2,buffer);
strcat(buffer2,"_dev1");
AppendItem(classlist,buffer2,"0");
}
/* Now use persistent classes so that serious anomalies last for about
2 autocorrelation lengths, so that they can be cross correlated and
seen by normally scheduled cfagent processes ... */
if (dev > 2.0*sqrt(2.0))
{
strcpy(buffer2,buffer);
strcat(buffer2,"_dev2");
AppendItem(classlist,buffer2,"2");
NewPersistentContext(buffer2,CF_PERSISTENCE,cfpreserve);
}
if (dev > 3.0*sqrt(2.0))
{
strcpy(buffer2,buffer);
strcat(buffer2,"_anomaly");
AppendItem(classlist,buffer2,"3");
NewPersistentContext(buffer2,CF_PERSISTENCE,cfpreserve);
}
return sig;
}
}
/*****************************************************************************/
static void SetVariable(char *name,double value,double average,double stddev,struct Item **classlist)
{
char var[CF_BUFSIZE];
snprintf(var,CF_MAXVARSIZE,"value_%s=%.0lf",name,value);
AppendItem(classlist,var,"");
snprintf(var,CF_MAXVARSIZE,"av_%s=%.2lf",name,average);
AppendItem(classlist,var,"");
snprintf(var,CF_MAXVARSIZE,"dev_%s=%.2lf",name,stddev);
AppendItem(classlist,var,"");
}
/*****************************************************************************/
static void ZeroArrivals()
{
memset(CF_THIS, 0, sizeof(CF_THIS));
}
/*****************************************************************************/
static double RejectAnomaly(double new,double average,double variance,double localav,double localvar)
{
double dev = sqrt(variance+localvar); /* Geometrical average dev */
double delta;
int bigger;
if (average == 0)
{
return new;
}
if (new > MON_THRESHOLD_HIGH*4.0)
{
return 0.0;
}
if (new > MON_THRESHOLD_HIGH)
{
return average;
}
if ((new-average)*(new-average) < cf_noise_threshold*cf_noise_threshold)
{
return new;
}
if (new - average > 0)
{
bigger = true;
}
else
{
bigger = false;
}
/* This routine puts some inertia into the changes, so that the system
doesn't respond to every little change ... IR and UV cutoff */
delta = sqrt((new-average)*(new-average)+(new-localav)*(new-localav));
if (delta > 4.0*dev) /* IR */
{
srand48((unsigned int)time(NULL));
if (drand48() < 0.7) /* 70% chance of using full value - as in learning policy */
{
return new;
}
else
{
if (bigger)
{
return average+2.0*dev;
}
else
{
return average-2.0*dev;
}
}
}
else
{
CfOut(cf_verbose,"","Value accepted\n");
return new;
}
}
/***************************************************************/
/* Level 5 */
/***************************************************************/
static void GatherPromisedMeasures(void)
{
struct Bundle *bp;
struct SubType *sp;
struct Promise *pp;
char *scope;
for (bp = BUNDLES; bp != NULL; bp = bp->next) /* get schedule */
{
scope = bp->name;
SetNewScope(bp->name);
if ((strcmp(bp->type,CF_AGENTTYPES[cf_monitor]) == 0) || (strcmp(bp->type,CF_AGENTTYPES[cf_common]) == 0))
{
for (sp = bp->subtypes; sp != NULL; sp = sp->next) /* get schedule */
{
for (pp = sp->promiselist; pp != NULL; pp=pp->next)
{
ExpandPromise(cf_monitor,scope,pp,KeepMonitorPromise);
}
}
}
}
DeleteAllScope();
}
/*********************************************************************/
/* Level */
/*********************************************************************/
static void KeepMonitorPromise(struct Promise *pp)
{
char *sp = NULL;
if (!IsDefinedClass(pp->classes))
{
CfOut(cf_verbose,"","\n");
CfOut(cf_verbose,"",". . . . . . . . . . . . . . . . . . . . . . . . . . . . \n");
CfOut(cf_verbose,"","Skipping whole next promise (%s), as context %s is not relevant\n",pp->promiser,pp->classes);
CfOut(cf_verbose,"",". . . . . . . . . . . . . . . . . . . . . . . . . . . . \n");
return;
}
if (VarClassExcluded(pp,&sp))
{
CfOut(cf_verbose,"","\n");
CfOut(cf_verbose,"",". . . . . . . . . . . . . . . . . . . . . . . . . . . . \n");
CfOut(cf_verbose,"","Skipping whole next promise (%s), as var-context %s is not relevant\n",pp->promiser,sp);
CfOut(cf_verbose,"",". . . . . . . . . . . . . . . . . . . . . . . . . . . . \n");
return;
}
if (strcmp("classes",pp->agentsubtype) == 0)
{
KeepClassContextPromise(pp);
return;
}
if (strcmp("measurements",pp->agentsubtype) == 0)
{
VerifyMeasurementPromise(CF_THIS,pp);
*pp->donep = false;
return;
}
}
/*****************************************************************************/
void MonOtherInit(void)
{
#ifdef HAVE_NOVA
Nova_MonOtherInit();
#endif
}
/*********************************************************************/
void MonOtherGatherData(double *cf_this)
{
#ifdef HAVE_NOVA
Nova_MonOtherGatherData(cf_this);
#endif
}
cfengine-3.2.4/src/ontology.c 0000644 0001750 0001750 00000043176 11715232734 013044 0000000 0000000 /*
Copyright (C) Cfengine AS
This file is part of Cfengine 3 - written and maintained by Cfengine 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 Commerical Open Source License
(COSL) may apply to this file if you as a licensee so wish it. See
included file COSL.txt.
*/
/*****************************************************************************/
/* */
/* File: ontology.c */
/* */
/*****************************************************************************/
#include "cf3.defs.h"
#include "cf3.extern.h"
static char *GetTopicContext(char *topic_name);
static int ClassifiedTopicMatch(char *ttopic1,char *ttopic2);
static void DeClassifyCanonicalTopic(char *typed_topic,char *topic,char *type);
static char *ClassifiedTopic(char *topic,char *type);
static char *URLHint(char *s);
static char *NormalizeTopic(char *s);
int GLOBAL_ID = 1; // Used as a primary key for convenience, 0 reserved
extern struct Occurrences *OCCURRENCES;
/*****************************************************************************/
struct Topic *IdempInsertTopic(char *classified_name)
{ char context[CF_MAXVARSIZE],topic[CF_MAXVARSIZE];
context[0] = '\0';
topic[0] = '\0';
DeClassifyTopic(classified_name,topic,context);
return InsertTopic(topic,context);
}
/*****************************************************************************/
struct Topic *InsertTopic(char *name,char *context)
{ int slot = GetHash(ToLowerStr(name));
return AddTopic(&(TOPICHASH[slot]),name,context);
}
/*****************************************************************************/
struct Topic *FindTopic(char *name)
{ int slot = GetHash(ToLowerStr(name));
return GetTopic(TOPICHASH[slot],name);
}
/*****************************************************************************/
struct Topic *AddTopic(struct Topic **list,char *name,char *context)
{ struct Topic *tp;
if ((tp = TopicExists(name,context)))
{
CfOut(cf_verbose,""," -> Topic %s already defined, ok\n",name);
}
else
{
if ((tp = (struct Topic *)malloc(sizeof(struct Topic))) == NULL)
{
CfOut(cf_error,"malloc"," !! Memory failure in AddTopic");
FatalError("");
}
tp->topic_name = strdup(NormalizeTopic(name));
if (context && strlen(context) > 0)
{
tp->topic_context = strdup(NormalizeTopic(context));
}
else
{
tp->topic_context = strdup("any");
}
tp->id = GLOBAL_ID++;
tp->associations = NULL;
tp->next = *list;
*list = tp;
CF_TOPICS++;
// This section must come last, as there is possible recursion and memory ref needs to be complete first
if (strcmp(tp->topic_context,"any") != 0)
{
// Every topic in a special context is generalized by itself in context "any"
char gen[CF_BUFSIZE];
struct Rlist *rlist = 0;
snprintf(gen,CF_BUFSIZE-1,"any::%s",tp->topic_name);
PrependRScalar(&rlist,gen,CF_SCALAR);
AddTopicAssociation(tp,&(tp->associations),KM_GENERALIZES_B,KM_GENERALIZES_F,rlist,true,tp->topic_context,tp->topic_name);
DeleteRlist(rlist);
}
}
return tp;
}
/*****************************************************************************/
void AddTopicAssociation(struct Topic *this_tp,struct TopicAssociation **list,char *fwd_name,char *bwd_name,struct Rlist *passociates,int ok_to_add_inverse,char *from_context,char *from_topic)
{ struct TopicAssociation *ta = NULL,*texist;
char fwd_context[CF_MAXVARSIZE];
struct Rlist *rp,*rpc;
struct Topic *new_tp;
char contexttopic[CF_BUFSIZE],ntopic[CF_BUFSIZE],ncontext[CF_BUFSIZE];
strncpy(ntopic,NormalizeTopic(from_topic),CF_BUFSIZE-1);
strncpy(ncontext,NormalizeTopic(from_context),CF_BUFSIZE-1);
snprintf(contexttopic,CF_MAXVARSIZE,"%s::%s",ncontext,ntopic);
strncpy(fwd_context,CanonifyName(fwd_name),CF_MAXVARSIZE-1);
if (passociates == NULL || passociates->item == NULL)
{
CfOut(cf_error," !! A topic must have at least one associate in association %s",fwd_name);
return;
}
if ((texist = AssociationExists(*list,fwd_name,bwd_name)) == NULL)
{
if ((ta = (struct TopicAssociation *)malloc(sizeof(struct TopicAssociation))) == NULL)
{
CfOut(cf_error,"malloc","Memory failure in AddTopicAssociation");
FatalError("");
}
if ((ta->fwd_name = strdup(fwd_name)) == NULL)
{
CfOut(cf_error,"malloc","Memory failure in AddTopicAssociation");
FatalError("");
}
ta->bwd_name = NULL;
if (bwd_name && ((ta->bwd_name = strdup(bwd_name)) == NULL))
{
CfOut(cf_error,"malloc","Memory failure in AddTopicAssociation");
FatalError("");
}
if ((ta->fwd_context = strdup(fwd_context)) == NULL)
{
CfOut(cf_error,"malloc","Memory failure in AddTopicAssociation");
FatalError("");
}
ta->associates = NULL;
ta->bwd_context = NULL;
ta->next = *list;
*list = ta;
}
else
{
ta = texist;
}
/* Association now exists, so add new members */
if (ok_to_add_inverse)
{
CfOut(cf_verbose,""," -> BEGIN add fwd associates for %s::%s",ncontext,ntopic);
}
else
{
CfOut(cf_verbose,""," ---> BEGIN reverse associations %s::%s",ncontext,ntopic);
}
// First make sure topics pointed to exist so that they can point to us also
for (rp = passociates; rp != NULL; rp=rp->next)
{
char normalform[CF_BUFSIZE] = {0};
strncpy(normalform,NormalizeTopic(rp->item),CF_BUFSIZE-1);
new_tp = IdempInsertTopic(normalform);
if (strcmp(contexttopic,normalform) == 0)
{
CfOut(cf_verbose,""," ! Excluding self-reference to %s",rp->item);
continue;
}
if (ok_to_add_inverse)
{
CfOut(cf_verbose,""," --> Adding '%s' with id %d as an associate of '%s::%s'",normalform,new_tp->id,this_tp->topic_context,this_tp->topic_name);
}
else
{
CfOut(cf_verbose,""," ---> Reverse '%s' with id %d as an associate of '%s::%s' (inverse)",normalform,new_tp->id,this_tp->topic_context,this_tp->topic_name);
}
if (!IsItemIn(ta->associates,normalform))
{
PrependFullItem(&(ta->associates),normalform,NULL,new_tp->id,0);
if (ok_to_add_inverse)
{
// inverse is from normalform to ncontext::ntopic
char rev[CF_BUFSIZE],ndt[CF_BUFSIZE],ndc[CF_BUFSIZE];
struct Rlist *rlist = 0;
snprintf(rev,CF_BUFSIZE-1,"%s::%s",ncontext,ntopic);
PrependRScalar(&rlist,rev,CF_SCALAR);
// Stupid to have to declassify + reclassify, but ..
DeClassifyTopic(normalform,ndt,ndc);
AddTopicAssociation(new_tp,&(new_tp->associations),bwd_name,fwd_name,rlist,false,ndc,ndt);
DeleteRlist(rlist);
}
}
else
{
CfOut(cf_verbose,""," -> Already in %s::%s's associate list",ncontext,ntopic);
}
CF_EDGES++;
}
if (ok_to_add_inverse)
{
CfOut(cf_verbose,""," -> END add fwd associates for %s::%s",ncontext,ntopic);
}
else
{
CfOut(cf_verbose,""," ---> END reverse associations %s::%s",ncontext,ntopic);
}
}
/*****************************************************************************/
void AddOccurrence(struct Occurrence **list,char *reference,struct Rlist *represents,enum representations rtype,char *context)
{ struct Occurrence *op = NULL;
struct Rlist *rp;
if ((op = OccurrenceExists(*list,reference,rtype,context)) == NULL)
{
if ((op = (struct Occurrence *)malloc(sizeof(struct Occurrence))) == NULL)
{
CfOut(cf_error,"malloc","Memory failure in AddOccurrence");
FatalError("");
}
op->represents = NULL;
op->occurrence_context = strdup(ToLowerStr(context));
op->locator = strdup(reference);
op->rep_type = rtype;
op->next = *list;
*list = op;
CF_OCCUR++;
CfOut(cf_verbose,""," -> Noted occurrence for %s::%s",context,reference);
}
/* Occurrence now exists, so add new subtype promises */
if (represents == NULL)
{
CfOut(cf_error,""," !! Topic occurrence \"%s\" claims to represent no aspect of its topic, discarding...",reference);
return;
}
for (rp = represents; rp != NULL; rp=rp->next)
{
IdempPrependRScalar(&(op->represents),rp->item,rp->type);
}
}
/*********************************************************************/
void AddInference(struct Inference **list,char *result,char *pre,char *qual)
{ struct Inference *ip;
if ((ip = (struct Inference *)malloc(sizeof(struct Occurrence))) == NULL)
{
CfOut(cf_error,"malloc","Memory failure in AddOccurrence");
FatalError("");
}
ip->inference = strdup(result);
ip->precedent = strdup(pre);
ip->qualifier = strdup(qual);
ip->next = *list;
*list = ip;
}
/*********************************************************************/
static char *ClassifiedTopic(char *topic,char *context)
{ static char name[CF_MAXVARSIZE];
Debug("CONTEXT(%s)/TOPIC(%s)",context,topic);
if (context && strlen(context) > 0)
{
snprintf(name,CF_MAXVARSIZE,"%s::%s",context,topic);
}
else
{
snprintf(name,CF_MAXVARSIZE,"%s",topic);
}
return name;
}
/*********************************************************************/
void DeClassifyTopic(char *classified_topic,char *topic,char *context)
{
context[0] = '\0';
topic[0] = '\0';
if (classified_topic == NULL)
{
return;
}
if (*classified_topic == ':')
{
sscanf(classified_topic,"::%255[^\n]",topic);
}
else if (strstr(classified_topic,"::"))
{
sscanf(classified_topic,"%255[^:]::%255[^\n]",context,topic);
if (strlen(topic) == 0)
{
sscanf(classified_topic,"::%255[^\n]",topic);
}
}
else
{
strncpy(topic,classified_topic,CF_MAXVARSIZE-1);
}
if (strlen(context) == 0)
{
strcpy(context,"any");
}
}
/*********************************************************************/
static void DeClassifyCanonicalTopic(char *classified_topic,char *topic,char *context)
{
context[0] = '\0';
topic[0] = '\0';
if (*classified_topic == '.')
{
sscanf(classified_topic,".%255[^\n]",topic);
}
else if (strstr(classified_topic,"."))
{
sscanf(classified_topic,"%255[^.].%255[^\n]",context,topic);
if (strlen(topic) == 0)
{
sscanf(classified_topic,".%255[^\n]",topic);
}
}
else
{
strncpy(topic,classified_topic,CF_MAXVARSIZE-1);
}
if (strlen(context) == 0)
{
strcpy(context,"any");
}
}
/*********************************************************************/
static int ClassifiedTopicMatch(char *ttopic1,char *ttopic2)
{ char context1[CF_MAXVARSIZE],topic1[CF_MAXVARSIZE];
char context2[CF_MAXVARSIZE],topic2[CF_MAXVARSIZE];
if (strcmp(ttopic1,ttopic2) == 0)
{
return true;
}
context1[0] = '\0';
topic1[0] = '\0';
context2[0] = '\0';
topic2[0] = '\0';
DeClassifyTopic(ttopic1,topic1,context1);
DeClassifyTopic(ttopic2,topic2,context2);
if (strlen(context1) > 0 && strlen(context2) > 0)
{
if (strcmp(topic1,topic2) == 0 && strcmp(context1,context2) == 0)
{
return true;
}
}
else
{
if (strcmp(topic1,topic2) == 0)
{
return true;
}
}
return false;
}
/*****************************************************************************/
int GetTopicPid(char *classified_topic)
{ struct Topic *tp;
int slot;
char context[CF_MAXVARSIZE],name[CF_MAXVARSIZE];
name[0] = '\0';
DeClassifyTopic(classified_topic,name,context);
slot = GetHash(ToLowerStr(name));
if ((tp = GetTopic(TOPICHASH[slot],classified_topic)))
{
return tp->id;
}
return 0;
}
/*****************************************************************************/
static char *URLHint(char *url)
{ char *sp;
for (sp = url+strlen(url); *sp != '/'; sp--)
{
}
return sp;
}
/*****************************************************************************/
/* Level */
/*****************************************************************************/
struct Topic *TopicExists(char *topic_name,char *topic_context)
{ struct Topic *tp;
int slot;
slot = GetHash(ToLowerStr(topic_name));
for (tp = TOPICHASH[slot]; tp != NULL; tp=tp->next)
{
if (strcmp(tp->topic_name,NormalizeTopic(topic_name)) == 0)
{
if (topic_context)
{
if (strlen(topic_context) > 0 && strcmp(tp->topic_context,NormalizeTopic(topic_context)) == 0)
{
return tp;
}
if (strlen(topic_context) == 0 && strcmp(tp->topic_context,"any") == 0)
{
return tp;
}
}
}
}
return NULL;
}
/*****************************************************************************/
struct TopicAssociation *AssociationExists(struct TopicAssociation *list,char *fwd,char *bwd)
{ struct TopicAssociation *ta;
int yfwd = false,ybwd = false;
enum cfreport level;
char l[CF_BUFSIZE],r[CF_BUFSIZE];
level = cf_verbose;
if (fwd == NULL || (fwd && strlen(fwd) == 0))
{
CfOut(cf_error,"","NULL forward association name\n");
return NULL;
}
if (bwd == NULL || (bwd && strlen(bwd) == 0))
{
CfOut(cf_verbose,"","NULL backward association name\n");
}
for (ta = list; ta != NULL; ta=ta->next)
{
if (fwd && (strcmp(fwd,ta->fwd_name) == 0))
{
CfOut(cf_verbose,"","Association '%s' exists already\n",fwd);
yfwd = true;
}
else if (fwd && ta->fwd_name)
{
strncpy(l,ToLowerStr(fwd),CF_MAXVARSIZE);
strncpy(r,ToLowerStr(ta->fwd_name),CF_MAXVARSIZE);
if (strcmp(l,r) == 0)
{
CfOut(cf_error,""," ! Association \"%s\" exists with different capitalization \"%s\"\n",fwd,ta->fwd_name);
yfwd = true;
}
else
{
yfwd = false;
}
}
else
{
yfwd = false;
}
if (bwd && (strcmp(bwd,ta->bwd_name) == 0))
{
CfOut(cf_verbose,""," ! Association '%s' exists already\n",bwd);
ybwd = true;
}
else if (bwd && ta->bwd_name)
{
strncpy(l,ToLowerStr(bwd),CF_MAXVARSIZE);
strncpy(r,ToLowerStr(ta->bwd_name),CF_MAXVARSIZE);
if (strcmp(l,r) == 0)
{
CfOut(cf_inform,""," ! Association \"%s\" exists with different capitalization \"%s\"\n",bwd,ta->bwd_name);
}
ybwd = true;
}
else
{
ybwd = false;
}
if (yfwd && ybwd)
{
return ta;
}
}
return NULL;
}
/*****************************************************************************/
struct Occurrence *OccurrenceExists(struct Occurrence *list,char *locator,enum representations rep_type,char *context)
{ struct Occurrence *op;
for (op = list; op != NULL; op=op->next)
{
if (strcmp(locator,op->locator) == 0 && strcmp(op->occurrence_context,context) == 0)
{
return op;
}
}
return NULL;
}
/*****************************************************************************/
struct Topic *GetTopic(struct Topic *list,char *topic_name)
{ struct Topic *tp;
char context[CF_MAXVARSIZE],name[CF_MAXVARSIZE];
strncpy(context,topic_name,CF_MAXVARSIZE-1);
name[0] = '\0';
DeClassifyTopic(topic_name,name,context);
for (tp = list; tp != NULL; tp=tp->next)
{
if (strlen(context) == 0)
{
if (strcmp(topic_name,tp->topic_name) == 0)
{
return tp;
}
}
else
{
if ((strcmp(name,tp->topic_name)) == 0 && (strcmp(context,tp->topic_context) == 0))
{
return tp;
}
}
}
return NULL;
}
/*****************************************************************************/
struct Topic *GetCanonizedTopic(struct Topic *list,char *topic_name)
{ struct Topic *tp;
char context[CF_MAXVARSIZE],name[CF_MAXVARSIZE];
DeClassifyCanonicalTopic(topic_name,name,context);
for (tp = list; tp != NULL; tp=tp->next)
{
if (strlen(context) == 0)
{
if (strcmp(name,CanonifyName(tp->topic_name)) == 0)
{
return tp;
}
}
else
{
if ((strcmp(name,CanonifyName(tp->topic_name))) == 0 && (strcmp(context,CanonifyName(tp->topic_context)) == 0))
{
return tp;
}
}
}
return NULL;
}
/*****************************************************************************/
static char *GetTopicContext(char *topic_name)
{ struct Topic *tp;
static char context1[CF_MAXVARSIZE],topic1[CF_MAXVARSIZE];
int slot = GetHash(topic_name);
context1[0] = '\0';
DeClassifyTopic(topic_name,topic1,context1);
if (strlen(context1) > 0)
{
return context1;
}
for (tp = TOPICHASH[slot]; tp != NULL; tp=tp->next)
{
if (strcmp(topic1,tp->topic_name) == 0)
{
return tp->topic_context;
}
}
return NULL;
}
/*****************************************************************************/
static char *NormalizeTopic(char *s)
{ char *sp;
int special = false;
for (sp = s; *sp != '\0'; sp++)
{
if (strchr("/\\&|=$@", *sp))
{
special = true;
break;
}
}
if (special)
{
return s;
}
else
{
return ToLowerStr(s);
}
}
cfengine-3.2.4/src/string_expressions.h 0000644 0001750 0001750 00000005704 11715232734 015142 0000000 0000000 /*
Copyright (C) Cfengine AS
This file is part of Cfengine 3 - written and maintained by Cfengine 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 Commerical Open Source License
(COSL) may apply to this file if you as a licensee so wish it. See
included file COSL.txt.
*/
#ifndef CFENGINE_STRING_EXPRESSIONS_H
#define CFENGINE_STRING_EXPRESSIONS_H
/*
String expressions grammar:
::= ::= ::= [a-zA-Z0-9_]+
::= $( )
${ }
::= .
Subsequent s are concatenated during evaluation.
*/
typedef enum StringOp
{
CONCAT,
LITERAL,
VARREF
} StringOp;
typedef struct StringExpression
{
StringOp op;
union StringExpressionValue
{
struct ConcatExpression
{
struct StringExpression *lhs;
struct StringExpression *rhs;
} concat;
struct LiteralExpression
{
char *literal;
} literal;
struct VarRefExpression
{
struct StringExpression *name;
} varref;
} val;
} StringExpression;
/* Parsing and evaluation */
/*
* Result of parsing.
*
* if succeeded, then result is the result of parsing and position is last
* character consumed.
*
* if not succeded, then result is NULL and position is last character consumed
* before the error.
*/
typedef struct StringParseResult
{
StringExpression *result;
int position;
} StringParseResult;
StringParseResult ParseStringExpression(const char *expr, int start, int end);
/*
* Evaluator should return either heap-allocated string or NULL. In later case
* evaluation will be aborted and NULL will be returned from
* EvalStringExpression.
*/
typedef char * (*VarRefEvaluator)(const char *varname, void *param);
/*
* Result is heap-allocated. In case evalfn() returns NULL whole
* EvalStringExpression returns NULL as well.
*/
char *EvalStringExpression(const StringExpression *expr, VarRefEvaluator evalfn,
void *param);
/*
* Frees StringExpression produced by ParseStringExpression. NULL-safe.
*/
void FreeStringExpression(StringExpression *expr);
#endif
cfengine-3.2.4/src/cf3lex.l 0000644 0001750 0001750 00000014574 11715233007 012361 0000000 0000000 %{
/*
Copyright (C) Cfengine AS
This file is part of Cfengine 3 - written and maintained by Cfengine 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 Commerical Open Source License
(COSL) may apply to this file if you as a licensee so wish it. See
included file COSL.txt.
*/
/*******************************************************************/
/* */
/* LEXER for cfengine 3 */
/* */
/*******************************************************************/
#include "cf3.defs.h"
#include "cf3.extern.h"
#include "cf3parse.h"
// Do not use lex - flex only
%}
%option noyywrap
space [ \t]+
newline ([\n]|[\xd][\xa])
comment #[^\n]*
promises bundle
body body
nakedvar [$@][(][a-zA-Z0-9_\200-\377.]+[)]|[$@][{][a-zA-Z0-9_\200-\377.]+[}]
id [a-zA-Z0-9_\200-\377]+
assign =>
arrow ->
/*
* Three types of quoted strings:
*
* - string in double quotes, starts with double quote, runs until another
* double quote, \" masks the double quote.
* - string in single quotes, starts with single quote, runs until another
* single quote, \' masks the single quote.
* - string in backquotes, starts with backquote, runs until another backquote.
*
* The same rule formatted for the better readability:
*
* := \" \" | \' \' | ` `
* = *
* = \\ | [^"\\]
* = *
* = \\ | [^'\\]
* = *
* = [^`]
* = . | \n
*
*/
qstring \"((\\(.|\n))|[^"\\])*\"|\'((\\(.|\n))|[^'\\])*\'|`[^`]*`
class [.|&!()a-zA-Z0-9_\200-\377]+::
category [a-zA-Z_]+:
%%
{newline} {
P.line_no++;
P.line_pos = 0;
}
{promises} {
/* Note this has to come before "id" since it is a subset of id */
if (P.currentclasses != NULL)
{
free(P.currentclasses);
P.currentclasses = NULL;
}
P.line_pos += strlen(yytext);
return BUNDLE;
}
{body} {
/* Note this has to come before "id" since it is a subset of id */
if (P.currentclasses != NULL)
{
free(P.currentclasses);
P.currentclasses = NULL;
}
P.line_pos += strlen(yytext);
return BODY;
}
{id} {
P.line_pos += strlen(yytext);
if (strlen(yytext) > CF_MAXVARSIZE-1)
{
yyerror("identifier too long");
}
strncpy(P.currentid,yytext,CF_MAXVARSIZE);
return ID;
}
{assign} {
P.line_pos += strlen(yytext);
return ASSIGN;
}
{arrow} {
P.line_pos += strlen(yytext);
return ARROW;
}
{class} {
P.line_pos += strlen(yytext);
if (P.currentclasses != NULL)
{
free(P.currentclasses);
}
yytext[strlen(yytext)-2] = '\0';
ValidateClassSyntax(yytext);
P.currentclasses = strdup(yytext);
return CLASS;
}
{category} {
P.line_pos += strlen(yytext);
yytext[strlen(yytext)-1] = '\0';
strncpy(P.currenttype,yytext,CF_MAXVARSIZE);
if (P.currentclasses != NULL)
{
free(P.currentclasses);
P.currentclasses = NULL;
}
return CATEGORY;
}
{qstring} {
char *tmp = NULL;
int less = 0;
P.line_pos += strlen(yytext);
if ((tmp = malloc(strlen(yytext)+1)) == NULL)
{
FatalError("Malloc failure in parsing");
}
if ((less = DeEscapeQuotedString(yytext,tmp)) > 0)
{
yyless(less);
}
if (P.currentstring)
{
free(P.currentstring);
}
P.currentstring = strdup(tmp);
if (THIS_AGENT_TYPE == cf_common)
{
IsCf3VarString(tmp);
}
free(tmp);
return QSTRING;
}
{nakedvar} {
P.line_pos += strlen(yytext);
P.currentstring = strdup(yytext);
return NAKEDVAR;
}
{space}+ {
P.line_pos += strlen(yytext);
}
{comment} {
}
. {
P.line_pos++;
return yytext[0];
}
%%
/* EOF */
cfengine-3.2.4/src/cfkey.c 0000644 0001750 0001750 00000015335 11715232734 012267 0000000 0000000 /*
Copyright (C) Cfengine AS
This file is part of Cfengine 3 - written and maintained by Cfengine 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 Commerical Open Source License
(COSL) may apply to this file if you as a licensee so wish it. See
included file COSL.txt.
*/
/*****************************************************************************/
/* */
/* File: exec.c */
/* */
/*****************************************************************************/
#include "cf3.defs.h"
#include "cf3.extern.h"
int SHOWHOSTS = false;
bool REMOVEKEYS = false;
const char *remove_keys_host;
void ShowLastSeenHosts(void);
static int RemoveKeys(const char *host);
int main (int argc,char *argv[]);
/*******************************************************************/
/* Command line options */
/*******************************************************************/
const char *ID = "The cfengine's generator makes key pairs for remote authentication.\n";
const struct option OPTIONS[17] =
{
{ "help",no_argument,0,'h' },
{ "debug",optional_argument,0,'d' },
{ "verbose",no_argument,0,'v' },
{ "version",no_argument,0,'V' },
{ "output-file",required_argument,0,'f'},
{ "show-hosts",no_argument,0,'s'},
{ "remove-keys",required_argument,0,'r'},
{ NULL,0,0,'\0' }
};
const char *HINTS[17] =
{
"Print the help message",
"Set debugging level 0,1,2,3",
"Output verbose information about the behaviour of the agent",
"Output the version of the software",
"Specify an alternative output file than the default (localhost)",
"Show lastseen hostnames and IP addresses",
"Remove keys for specified hostname/IP",
NULL
};
/*****************************************************************************/
int main(int argc,char *argv[])
{
CheckOpts(argc,argv);
THIS_AGENT_TYPE = cf_keygen;
GenericInitialize(argc,argv,"keygenerator");
if (SHOWHOSTS)
{
ShowLastSeenHosts();
return 0;
}
if (REMOVEKEYS)
{
return RemoveKeys(remove_keys_host);
}
KeepKeyPromises();
return 0;
}
/*****************************************************************************/
/* Level */
/*****************************************************************************/
void CheckOpts(int argc,char **argv)
{ extern char *optarg;
int optindex = 0;
int c;
while ((c=getopt_long(argc,argv,"d:vf:VMsr:",OPTIONS,&optindex)) != EOF)
{
switch ((char) c)
{
case 'f':
snprintf(CFPRIVKEYFILE,CF_BUFSIZE,"%s.priv",optarg);
snprintf(CFPUBKEYFILE,CF_BUFSIZE,"%s.pub",optarg);
break;
case 'd':
switch ((optarg==NULL) ? '3' : *optarg)
{
case '1':
D1 = true;
DEBUG = true;
break;
case '2':
D2 = true;
DEBUG = true;
break;
default:
DEBUG = true;
break;
}
break;
case 'V': PrintVersionBanner("cf-key");
exit(0);
case 'v':
VERBOSE = true;
break;
case 's':
SHOWHOSTS = true;
break;
case 'r':
REMOVEKEYS = true;
remove_keys_host = optarg;
break;
case 'h': Syntax("cf-key - cfengine's key generator",OPTIONS,HINTS,ID);
exit(0);
case 'M': ManPage("cf-key - cfengine's key generator",OPTIONS,HINTS,ID);
exit(0);
default: Syntax("cf-key - cfengine's key generator",OPTIONS,HINTS,ID);
exit(1);
}
}
}
/*****************************************************************************/
void ShowLastSeenHosts()
{ CF_DB *dbp;
CF_DBC *dbcp;
char *key;
void *value;
char name[CF_BUFSIZE],hostname[CF_BUFSIZE],address[CF_MAXVARSIZE];
struct CfKeyHostSeen entry;
int ksize,vsize;
int count = 0;
snprintf(name,CF_BUFSIZE-1,"%s/%s",CFWORKDIR,CF_LASTDB_FILE);
MapName(name);
if (!OpenDB(name,&dbp))
{
return;
}
/* Acquire a cursor for the database. */
if (!NewDBCursor(dbp,&dbcp))
{
CfOut(cf_inform,""," !! Unable to scan last-seen database");
CloseDB(dbp);
return;
}
/* Initialize the key/data return pair. */
printf("%9.9s %17.17s %-25.25s %15.15s\n","Direction","IP","Name","Key");
/* Walk through the database and print out the key/data pairs. */
while(NextDB(dbp,dbcp,&key,&ksize,&value,&vsize))
{
if (value != NULL)
{
memset(&entry, 0, sizeof(entry));
memset(hostname, 0, sizeof(hostname));
memset(address, 0, sizeof(address));
memcpy(&entry,value,sizeof(entry));
strncpy(hostname,(char *)key,sizeof(hostname)-1);
strncpy(address,(char *)entry.address,sizeof(address)-1);
++count;
}
else
{
continue;
}
CfOut(cf_verbose,""," -> Reporting on %s",hostname);
printf("%-9.9s %17.17s %-25.25s %s\n",
hostname[0] == '+' ? "Outgoing" : "Incoming",
address,
IPString2Hostname(address),
hostname+1
);
}
printf("Total Entries: %d\n",count);
DeleteDBCursor(dbp,dbcp);
CloseDB(dbp);
}
/*****************************************************************************/
static int RemoveKeys(const char *host)
{
RemoveHostFromLastSeen(host,NULL);
int removed_keys = RemovePublicKeys(remove_keys_host);
if (removed_keys < 0)
{
CfOut(cf_error, "", "Unable to remove keys for the host %s", remove_keys_host);
return 255;
}
else if (removed_keys == 0)
{
CfOut(cf_error, "", "No keys for host %s were found", remove_keys_host);
return 1;
}
else
{
CfOut(cf_inform, "", "Removed %d key(s) for host %s", removed_keys, remove_keys_host);
return 0;
}
}
cfengine-3.2.4/src/cf3globals.c 0000644 0001750 0001750 00000046677 11715232734 013222 0000000 0000000 /*
Copyright (C) Cfengine AS
This file is part of Cfengine 3 - written and maintained by Cfengine 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 Commerical Open Source License
(COSL) may apply to this file if you as a licensee so wish it. See
included file COSL.txt.
*/
/*****************************************************************************/
/* */
/* File: cf3globals.c */
/* */
/* Created: Thu Aug 2 11:08:10 2007 */
/* */
/*****************************************************************************/
#include "cf3.defs.h"
/*****************************************************************************/
/* flags */
/*****************************************************************************/
int SHOWREPORTS = false;
/*****************************************************************************/
/* operational state */
/*****************************************************************************/
int VERBOSE = false;
int INFORM = false;
int PARSING = false;
int CFPARANOID = false;
int REQUIRE_COMMENTS = CF_UNDEFINED;
int LOOKUP = false;
int IGNORE_MISSING_INPUTS = false;
int IGNORE_MISSING_BUNDLES = false;
int FIPS_MODE = false;
int ALWAYS_VALIDATE = false;
struct utsname VSYSNAME;
FILE *FREPORT_HTML = NULL;
FILE *FREPORT_TXT = NULL;
FILE *FKNOW = NULL;
int XML = false;
struct FnCallStatus FNCALL_STATUS;
int CFA_MAXTHREADS = 10;
int CFA_BACKGROUND = 0;
int CFA_BACKGROUND_LIMIT = 1;
int AM_BACKGROUND_PROCESS = false;
int CF_PERSISTENCE = 10;
char *THIS_BUNDLE = NULL;
char THIS_AGENT[CF_MAXVARSIZE] = {0};
enum cfagenttype THIS_AGENT_TYPE;
char SYSLOGHOST[CF_MAXVARSIZE] = {0};
unsigned short SYSLOGPORT = 514;
time_t PROMISETIME = 0;
time_t CF_LOCKHORIZON = CF_MONTH;
int LICENSES = 0;
int AM_NOVA = false;
int AM_CONSTELLATION = false;
char EXPIRY[CF_SMALLBUF] = {0};
char LICENSE_COMPANY[CF_SMALLBUF] = {0};
int INSTALL_SKIP = false;
int KEYTTL = 0;
// These are used to measure graph complexity in know/agent
int CSV=false;
int CF_TOPICS = 0; // objects
int CF_OCCUR = 0; // objects
int CF_EDGES = 0; // links or promises between them
struct Rlist *MOUNTEDFSLIST = NULL;
struct Rlist *SERVERLIST = NULL;
struct PromiseIdent *PROMISE_ID_LIST = NULL;
struct Item *PROCESSTABLE = NULL;
struct Item *PROCESSREFRESH = NULL;
struct Item *ROTATED = NULL;
struct Item *FSTABLIST = NULL;
struct Item *ABORTBUNDLEHEAP = NULL;
struct Item *DONELIST = NULL;
struct Rlist *CBUNDLESEQUENCE = NULL;
struct Rlist *SERVER_KEYSEEN = NULL;
char *CBUNDLESEQUENCE_STR;
int EDIT_MODEL = false;
int CF_MOUNTALL = false;
int FSTAB_EDITS;
int ABORTBUNDLE = false;
int BOOTSTRAP = false;
char HASHDB[CF_BUFSIZE] = {0};
/*****************************************************************************/
/* Measurements */
/*****************************************************************************/
double METER_KEPT[meter_endmark];
double METER_REPAIRED[meter_endmark];
double Q_MEAN;
double Q_SIGMA;
/*****************************************************************************/
/* Internal data structures */
/*****************************************************************************/
struct PromiseParser P = {0};
struct Bundle *BUNDLES = NULL;
struct Body *BODIES = NULL;
struct Scope *VSCOPE = NULL;
struct Rlist *VINPUTLIST = NULL;
struct Rlist *BODYPARTS = NULL;
struct Rlist *SUBBUNDLES = NULL;
struct Rlist *ACCESSLIST = NULL;
struct Rlist *SINGLE_COPY_LIST = NULL;
struct Rlist *AUTO_DEFINE_LIST = NULL;
struct Rlist *SINGLE_COPY_CACHE = NULL;
struct Rlist *CF_STCK = NULL;
struct Item *EDIT_ANCHORS = NULL;
int CF_STCKFRAME = 0;
int LASTSEENEXPIREAFTER = CF_WEEK;
char POLICY_SERVER[CF_BUFSIZE] = {0};
char WEBDRIVER[CF_MAXVARSIZE] = {0};
char DOCROOT[CF_MAXVARSIZE] = {0};
char BANNER[2*CF_BUFSIZE] = {0};
char FOOTER[CF_BUFSIZE] = {0};
char STYLESHEET[CF_BUFSIZE] = {0};
struct Topic *TOPICHASH[CF_HASHTABLESIZE];
char SQL_DATABASE[CF_MAXVARSIZE] = {0};
char SQL_OWNER[CF_MAXVARSIZE] = {0};
char SQL_PASSWD[CF_MAXVARSIZE] = {0};
char SQL_SERVER[CF_MAXVARSIZE] = {0};
char SQL_CONNECT_NAME[CF_MAXVARSIZE] = {0};
enum cfdbtype SQL_TYPE = cfd_notype;
/*****************************************************************************/
/* Windows version constants */
/*****************************************************************************/
unsigned int WINVER_MAJOR = 0;
unsigned int WINVER_MINOR = 0;
unsigned int WINVER_BUILD = 0;
/*****************************************************************************/
/* Constants */
/*****************************************************************************/
struct SubTypeSyntax CF_NOSTYPE = {NULL,NULL,NULL};
/*********************************************************************/
/* Object variables */
/*********************************************************************/
char *DAY_TEXT[] =
{
"Monday",
"Tuesday",
"Wednesday",
"Thursday",
"Friday",
"Saturday",
"Sunday",
NULL
};
char *MONTH_TEXT[] =
{
"January",
"February",
"March",
"April",
"May",
"June",
"July",
"August",
"September",
"October",
"November",
"December",
NULL
};
char *SHIFT_TEXT[] =
{
"Night",
"Morning",
"Afternoon",
"Evening",
NULL
};
/*****************************************************************************/
char *CF_DATATYPES[] = /* see enum cfdatatype */
{
"string",
"int",
"real",
"slist",
"ilist",
"rlist",
"(menu option)",
"(option list)",
"(ext body)",
"(ext bundle)",
"class",
"clist",
"irange [int,int]",
"rrange [real,real]",
"counter",
"",
};
/*****************************************************************************/
char *CF_AGENTTYPES[] = /* see enum cfagenttype */
{
CF_COMMONC,
CF_AGENTC,
CF_SERVERC,
CF_MONITORC,
CF_EXECC,
CF_RUNC,
CF_KNOWC,
CF_REPORTC,
CF_KEYGEN,
CF_HUBC,
"",
};
/*****************************************************************************/
/* Compatability infrastructure */
/*****************************************************************************/
double FORGETRATE = 0.7;
int IGNORELOCK = false;
int DONTDO = false;
int DEBUG = false;
int D1 = false;
int D2 = false;
int AUDIT = false;
int LOGGING = false;
char VFQNAME[CF_MAXVARSIZE] = {0};
char VUQNAME[CF_MAXVARSIZE] = {0};
char VDOMAIN[CF_MAXVARSIZE] = {0};
char VYEAR[5] = {0};
char VDAY[3] = {0};
char VMONTH[4] = {0};
char VSHIFT[12] = {0};
char PADCHAR = ' ';
char PURGE = 'n';
int ERRORCOUNT = 0;
char VPREFIX[CF_MAXVARSIZE] = {0};
char VINPUTFILE[CF_BUFSIZE] = {0};
char CONTEXTID[32] = {0};
char CFPUBKEYFILE[CF_BUFSIZE] = {0};
char CFPRIVKEYFILE[CF_BUFSIZE] = {0};
char AVDB[CF_MAXVARSIZE] = {0};
char CFWORKDIR[CF_BUFSIZE] = {0};
char PIDFILE[CF_BUFSIZE] = {0};
char *DEFAULT_COPYTYPE = NULL;
RSA *PRIVKEY = NULL, *PUBKEY = NULL;
char PUBKEY_DIGEST[CF_MAXVARSIZE] = {0};
pthread_attr_t PTHREADDEFAULTS;
#ifdef PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP
pthread_mutex_t MUTEX_SYSCALL = PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP;
pthread_mutex_t MUTEX_LOCK = PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP;
pthread_mutex_t MUTEX_COUNT = PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP;
pthread_mutex_t MUTEX_OUTPUT = PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP;
pthread_mutex_t MUTEX_DBHANDLE = PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP;
pthread_mutex_t MUTEX_POLICY = PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP;
pthread_mutex_t MUTEX_GETADDR = PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP;
pthread_mutex_t MUTEX_DB_LASTSEEN = PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP;
pthread_mutex_t MUTEX_DB_REPORT = PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP;
pthread_mutex_t MUTEX_VSCOPE = PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP;
pthread_mutex_t MUTEX_SERVER_KEYSEEN = PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP;
pthread_mutex_t MUTEX_SERVER_CHILDREN = PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP;
#else
# if defined HAVE_PTHREAD_H && (defined HAVE_LIBPTHREAD || defined BUILDTIN_GCC_THREAD)
pthread_mutex_t MUTEX_SYSCALL = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t MUTEX_LOCK = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t MUTEX_COUNT = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t MUTEX_OUTPUT = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t MUTEX_DBHANDLE = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t MUTEX_POLICY = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t MUTEX_GETADDR = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t MUTEX_DB_LASTSEEN = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t MUTEX_DB_REPORT = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t MUTEX_VSCOPE = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t MUTEX_SERVER_KEYSEEN = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t MUTEX_SERVER_CHILDREN = PTHREAD_MUTEX_INITIALIZER;
# endif
#endif
char VIPADDRESS[18] = {0};
int CFSIGNATURE = 0;
char *PROTOCOL[] =
{
"EXEC",
"AUTH", /* old protocol */
"GET",
"OPENDIR",
"SYNCH",
"CLASSES",
"MD5",
"SMD5",
"CAUTH",
"SAUTH",
"SSYNCH",
"SGET",
"VERSION",
"SOPENDIR",
"VAR",
"SVAR",
"CONTEXT",
"SCONTEXT",
"SQUERY",
NULL
};
struct Item *IPADDRESSES = NULL;
int PR_KEPT = 0;
int PR_REPAIRED = 0;
int PR_NOTKEPT = 0;
double VAL_KEPT = 0;
double VAL_REPAIRED = 0;
double VAL_NOTKEPT = 0;
/*******************************************************************/
/* Context Management */
/*******************************************************************/
struct AlphaList VHEAP;
struct AlphaList VADDCLASSES;
struct Item *VNEGHEAP = NULL;
struct Item *VDELCLASSES = NULL;
struct Rlist *PRIVCLASSHEAP = NULL;
struct Rlist *GOALS = NULL;
struct Rlist *GOALCATEGORIES = NULL;
/*******************************************************************/
/* */
/* Checksums */
/* */
/*******************************************************************/
/* These string lengths should not exceed CF_MAXDIGESTNAMELEN
characters for packing */
char *CF_DIGEST_TYPES[10][2] =
{
{"md5","m"},
{"sha224","c"},
{"sha256","C"},
{"sha384","h"},
{"sha512","H"},
{"sha1","S"},
{"sha","s"}, /* Should come last, since substring */
{"best","b"},
{"crypt","o"},
{NULL,NULL}
};
int CF_DIGEST_SIZES[10] =
{
CF_MD5_LEN,
CF_SHA224_LEN,
CF_SHA256_LEN,
CF_SHA384_LEN,
CF_SHA512_LEN,
CF_SHA1_LEN,
CF_SHA_LEN,
CF_BEST_LEN,
CF_CRYPT_LEN,
0
};
enum cfhashes CF_DEFAULT_DIGEST;
int CF_DEFAULT_DIGEST_LEN;
/***********************************************************/
struct Audit *AUDITPTR;
struct Audit *VAUDIT = NULL;
CF_DB *AUDITDBP = NULL;
char GRAPHDIR[CF_BUFSIZE] = {0};
char CFLOCK[CF_BUFSIZE] = {0};
char CFLOG[CF_BUFSIZE] = {0};
char CFLAST[CF_BUFSIZE] = {0};
char LOCKDB[CF_BUFSIZE] = {0};
char LOGFILE[CF_MAXVARSIZE] = {0};
char *SIGNALS[highest_signal];
time_t CFSTARTTIME;
time_t CFINITSTARTTIME;
char STR_CFENGINEPORT[16] = {0};
unsigned short SHORT_CFENGINEPORT;
time_t CONNTIMEOUT = 10; /* seconds */
time_t RECVTIMEOUT = 30; /* seconds */
int RPCTIMEOUT = 60; /* seconds */
pid_t ALARM_PID = -1;
int SKIPIDENTIFY = false;
int EDITFILESIZE = 10000;
int EDITBINFILESIZE = 100000;
int VIFELAPSED = 1;
int VEXPIREAFTER = 120;
int CHECKSUMUPDATES = false;
char BINDINTERFACE[CF_BUFSIZE] = {0};
int MINUSF = false;
int EXCLAIM = true;
mode_t DEFAULTMODE = (mode_t) 0755;
char *VREPOSITORY = NULL;
char REPOSCHAR = '_';
struct Item *VDEFAULTROUTE=NULL;
struct Item *VSETUIDLIST = NULL;
struct Item *SUSPICIOUSLIST = NULL;
enum classes VSYSTEMHARDCLASS = unused1;
struct Item *NONATTACKERLIST = NULL;
struct Item *MULTICONNLIST = NULL;
struct Item *TRUSTKEYLIST = NULL;
struct Item *DHCPLIST = NULL;
struct Item *ALLOWUSERLIST = NULL;
struct Item *SKIPVERIFY = NULL;
struct Item *ATTACKERLIST = NULL;
struct Item *ABORTHEAP = NULL;
struct Item *VREPOSLIST=NULL;
/*******************************************************************/
/* Anomaly */
/*******************************************************************/
struct sock ECGSOCKS[ATTR] = /* extended to map old to new using enum*/
{
{"137","netbiosns",ob_netbiosns_in,ob_netbiosns_out},
{"138","netbiosdgm",ob_netbiosdgm_in,ob_netbiosdgm_out},
{"139","netbiosssn",ob_netbiosssn_in,ob_netbiosssn_out},
{"194","irc",ob_irc_in,ob_irc_out},
{"5308","cfengine",ob_cfengine_in,ob_cfengine_out},
{"2049","nfsd",ob_nfsd_in,ob_nfsd_out},
{"25","smtp",ob_smtp_in,ob_smtp_out},
{"80","www",ob_www_in,ob_www_out},
{"21","ftp",ob_ftp_in,ob_ftp_out},
{"22","ssh",ob_ssh_in,ob_ssh_out},
{"443","wwws",ob_wwws_in,ob_wwws_out}
};
char *TCPNAMES[CF_NETATTR] =
{
"icmp",
"udp",
"dns",
"tcpsyn",
"tcpack",
"tcpfin",
"misc"
};
char *OBS[CF_OBSERVABLES][2] =
{
{"users","Users with active processes"},
{"rootprocs","Sum privileged system processes"},
{"otherprocs","Sum non-privileged process"},
{"diskfree","Free disk on / partition"},
{"loadavg","Kernel load average utilization (sum over cores)"},
{"netbiosns_in","netbios name lookups (in)"},
{"netbiosns_out","netbios name lookups (out)"},
{"netbiosdgm_in","netbios name datagrams (in)"},
{"netbiosdgm_out","netbios name datagrams (out)"},
{"netbiosssn_in","netbios name sessions (in)"},
{"netbiosssn_out","netbios name sessions (out)"},
{"irc_in","IRC connections (in)"},
{"irc_out","IRC connections (out)"},
{"cfengine_in","cfengine connections (in)"},
{"cfengine_out","cfengine connections (out)"},
{"nfsd_in","nfs connections (in)"},
{"nfsd_out","nfs connections (out)"},
{"smtp_in","smtp connections (in)"},
{"smtp_out","smtp connections (out)"},
{"www_in","www connections (in)"},
{"www_out","www connections (out)"},
{"ftp_in","ftp connections (in)"},
{"ftp_out","ftp connections (out)"},
{"ssh_in","ssh connections (in)"},
{"ssh_out","ssh connections (out)"},
{"wwws_in","wwws connections (in)"},
{"wwws_out","wwws connections (out)"},
{"icmp_in","ICMP packets (in)"},
{"icmp_out","ICMP packets (out)"},
{"udp_in","UDP dgrams (in)"},
{"udp_out","UDP dgrams (out)"},
{"dns_in","DNS requests (in)"},
{"dns_out","DNS requests (out)"},
{"tcpsyn_in","TCP sessions (in)"},
{"tcpsyn_out","TCP sessions (out)"},
{"tcpack_in","TCP acks (in)"},
{"tcpack_out","TCP acks (out)"},
{"tcpfin_in","TCP finish (in)"},
{"tcpfin_out","TCP finish (out)"},
{"tcpmisc_in","TCP misc (in)"},
{"tcpmisc_out","TCP misc (out)"},
{"webaccess","Webserver hits"},
{"weberrors","Webserver errors"},
{"syslog","New log entries (Syslog)"},
{"messages","New log entries (messages)"},
{"temp0","CPU Temperature 0"},
{"temp1","CPU Temperature 1"},
{"temp2","CPU Temperature 2"},
{"temp3","CPU Temperature 3"},
{"cpu","%CPU utilization (all)"},
{"cpu0","%CPU utilization 0"},
{"cpu1","%CPU utilization 1"},
{"cpu2","%CPU utilization 2"},
{"cpu3","%CPU utilization 3"},
{"spare","unused"},
{"spare","unused"},
{"spare","unused"},
{"spare","unused"},
{"spare","unused"},
{"spare","unused"},
{"spare","unused"},
{"spare","unused"},
{"spare","unused"},
{"spare","unused"},
{"spare","unused"},
{"spare","unused"},
{"spare","unused"},
{"spare","unused"},
{"spare","unused"},
{"spare","unused"},
{"spare","unused"},
{"spare","unused"},
{"spare","unused"},
{"spare","unused"},
{"spare","unused"},
{"spare","unused"},
{"spare","unused"},
{"spare","unused"},
{"spare","unused"},
{"spare","unused"},
{"spare","unused"},
{"spare","unused"},
{"spare","unused"},
{"spare","unused"},
{"spare","unused"},
{"spare","unused"},
{"spare","unused"},
{"spare","unused"},
{"spare","unused"},
{"spare","unused"},
{"spare","unused"},
};
/**********************************************************************************/
/* Report names */
/**********************************************************************************/
// See enum in cf3.defs.h
char *BASIC_REPORTS[cfrep_unknown+1][2] =
{
{"Bundle profile","Status of promise bundles and when they were last verified"},
{"Business value report","Accumulated value of promises kept"},
{"Class profile","User defined classes observed on the system"},
{"Compliance by promise","Compliance of each promise individually"},
{"Compliance summary","Total summary of host compliance"},
{"File change log","Log of all detected changes to files from changes promises"},
{"File change diffs","Delta/difference comparison showing file changes"},
{"Last saw hosts","Log of when neighbouring hosts were last observed online"},
{"Patches available","A list of patches currently claimed to be available by the local package manager"},
{"Patch status","A list of (un)applied patches according to the local package manager"},
{"Performance","Execution time used to verify selected promises"},
{"Promises repaired log","Log of actual repairs made to the system"},
{"Promises repaired summary","Cumulative (histogram) summary of promises repaired"},
{"Promises not kept log","Log of promises that could not or would not be kept"},
{"Promises not kept summary","Cumulative (histogram) summary of promises not kept"},
{"Setuid/gid root programs","Current list of observed setuid/setgid root programs"},
{"Software installed","List of software packages claimed to be installed according to the local package manager"},
{"Variables","Table of variable values last observed"},
{NULL,NULL}
};
// See enum in cf3.defs.h
char *CDP_REPORTS[cdp_unknown+1][2] =
{
{"ACLs","File access controls"},
{"Commands","Scheduled commands to execute"},
{"File Changes","File changes observed on the system"},
{"File Diffs","Delta/difference comparison showing file changes"},
{"Registry","Promised Windows registry setting status"},
{"Services","System services status"},
{NULL,NULL}
};
cfengine-3.2.4/src/matching.c 0000644 0001750 0001750 00000065207 11715232734 012763 0000000 0000000 /*
Copyright (C) Cfengine AS
This file is part of Cfengine 3 - written and maintained by Cfengine 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 Commerical Open Source License
(COSL) may apply to this file if you as a licensee so wish it. See
included file COSL.txt.
*/
/*****************************************************************************/
/* */
/* File: matching.c */
/* */
/*****************************************************************************/
#include "cf3.defs.h"
#include "cf3.extern.h"
#ifdef HAVE_PCRE_H
#include
#endif
#ifdef HAVE_PCRE_PCRE_H
#include
#endif
struct CfRegEx
{
int failed;
const char *regexp;
pcre *rx;
const char *err;
int err_offset;
};
static int FullTextCaseMatch (char *regexp,const char *teststring);
static int BlockTextCaseMatch(char *regexp,char *teststring,int *start,int *end);
/*********************************************************************/
/* Wrappers */
/*********************************************************************/
static struct CfRegEx CompileRegExp(const char *regexp)
{ struct CfRegEx this;
pcre *rx;
const char *errorstr;
int erroffset;
memset(&this,0,sizeof(struct CfRegEx));
rx = pcre_compile(regexp,PCRE_MULTILINE|PCRE_DOTALL,&errorstr,&erroffset,NULL);
if (rx == NULL)
{
CfOut(cf_error,"","Regular expression error \"%s\" in expression \"%s\" at %d\n",errorstr,regexp,erroffset);
this.failed = true;
}
else
{
this.failed = false;
this.rx = rx;
}
this.regexp = regexp;
return this;
}
/*********************************************************************/
static struct CfRegEx CaseCompileRegExp(const char *regexp)
{ struct CfRegEx this;
pcre *rx;
const char *errorstr;
int erroffset;
memset(&this,0,sizeof(struct CfRegEx));
rx = pcre_compile(regexp,PCRE_CASELESS|PCRE_MULTILINE|PCRE_DOTALL,&errorstr,&erroffset,NULL);
if (rx == NULL)
{
CfOut(cf_error,"","Regular expression error %s in %s at %d: %s\n",errorstr,regexp,erroffset);
this.failed = true;
}
else
{
this.failed = false;
this.rx = rx;
}
this.regexp = regexp;
return this;
}
/*********************************************************************/
static int RegExMatchSubString(struct CfRegEx rex,char *teststring,int *start,int *end)
{
pcre *rx;
int ovector[OVECCOUNT],i,rc;
rx = rex.rx;
if ((rc = pcre_exec(rx,NULL,teststring,strlen(teststring),0,0,ovector,OVECCOUNT)) >= 0)
{
*start = ovector[0];
*end = ovector[1];
DeleteScope("match");
NewScope("match");
for (i = 0; i < rc; i++) /* make backref vars $(1),$(2) etc */
{
char substring[CF_MAXVARSIZE];
char lval[4];
char *backref_start = teststring + ovector[i*2];
int backref_len = ovector[i*2+1] - ovector[i*2];
if (backref_len < CF_MAXVARSIZE)
{
memset(substring,0,CF_MAXVARSIZE);
strncpy(substring,backref_start,backref_len);
snprintf(lval,3,"%d",i);
ForceScalar(lval,substring);
}
}
pcre_free(rx);
return true;
}
else
{
*start = 0;
*end = 0;
pcre_free(rx);
return false;
}
}
/*********************************************************************/
static int RegExMatchFullString(struct CfRegEx rex, const char *teststring)
{
pcre *rx;
int ovector[OVECCOUNT],i,rc,match_len;
const char *match_start;
rx = rex.rx;
if ((rc = pcre_exec(rx,NULL,teststring,strlen(teststring),0,0,ovector,OVECCOUNT)) >= 0)
{
match_start = teststring + ovector[0];
match_len = ovector[1] - ovector[0];
DeleteScope("match");
NewScope("match");
for (i = 0; i < rc; i++) /* make backref vars $(1),$(2) etc */
{
char substring[CF_MAXVARSIZE];
char lval[4];
const char *backref_start = teststring + ovector[i*2];
int backref_len = ovector[i*2+1] - ovector[i*2];
memset(substring,0,CF_MAXVARSIZE);
if (backref_len < CF_MAXVARSIZE)
{
strncpy(substring,backref_start,backref_len);
snprintf(lval,3,"%d",i);
ForceScalar(lval,substring);
}
}
if (rx)
{
pcre_free(rx);
}
if ((match_start == teststring) && (match_len == strlen(teststring)))
{
return true;
}
else
{
return false;
}
}
else
{
pcre_free(rx);
return false;
}
}
/*********************************************************************/
static char *FirstBackReference(struct CfRegEx rex,char *regex, const char *teststring)
{ static char backreference[CF_BUFSIZE];
pcre *rx;
int ovector[OVECCOUNT],i,rc,match_len;
const char *match_start;
rx = rex.rx;
memset(backreference,0,CF_BUFSIZE);
if ((rc = pcre_exec(rx,NULL,teststring,strlen(teststring),0,0,ovector,OVECCOUNT)) >= 0)
{
match_start = teststring + ovector[0];
match_len = ovector[1] - ovector[0];
for (i = 1; i < rc; i++) /* make backref vars $(1),$(2) etc */
{
const char *backref_start = teststring + ovector[i*2];
int backref_len = ovector[i*2+1] - ovector[i*2];
if (backref_len < CF_MAXVARSIZE)
{
strncpy(backreference,backref_start,backref_len);
}
break;
}
}
pcre_free(rx);
if (strlen(backreference) == 0)
{
Debug("The regular expression \"%s\" yielded no matching back-reference\n",regex);
strncpy(backreference,"CF_NOMATCH",CF_MAXVARSIZE);
}
else
{
Debug("The regular expression \"%s\" yielded backreference \"%s\" on %s\n",regex,backreference,teststring);
}
return backreference;
}
bool ValidateRegEx(const char *regex)
{
struct CfRegEx rex = CompileRegExp(regex);
return !rex.failed;
}
/*************************************************************************/
/* WILDCARD TOOLKIT : Level 0 */
/*************************************************************************/
int FullTextMatch(char *regexp,const char *teststring)
{ struct CfRegEx rex;
if (strcmp(regexp,teststring) == 0)
{
return true;
}
rex = CompileRegExp(regexp);
if (rex.failed)
{
CfOut(cf_error,"","!! Could not parse regular expression '%s'", regexp);
return false;
}
if (RegExMatchFullString(rex,teststring))
{
return true;
}
else
{
return false;
}
}
/*************************************************************************/
char *ExtractFirstReference(char *regexp, const char *teststring)
{ struct CfRegEx rex;
static char *nothing = "";
if (regexp == NULL || teststring == NULL)
{
return nothing;
}
rex = CompileRegExp(regexp);
if (rex.failed)
{
return nothing;
}
return FirstBackReference(rex,regexp,teststring);
}
/*************************************************************************/
static int FullTextCaseMatch (char *regexp, const char *teststring)
{ struct CfRegEx rex;
rex = CaseCompileRegExp(regexp);
if (rex.failed)
{
return 0;
}
if (RegExMatchFullString(rex,teststring))
{
return true;
}
else
{
return false;
}
}
/*************************************************************************/
int BlockTextMatch(char *regexp,char *teststring,int *start,int *end)
{ struct CfRegEx rex;
rex = CompileRegExp(regexp);
if (rex.failed)
{
return 0;
}
if (RegExMatchSubString(rex,teststring,start,end))
{
return true;
}
else
{
return false;
}
}
/*************************************************************************/
static int BlockTextCaseMatch(char *regexp,char *teststring,int *start,int *end)
{ struct CfRegEx rex;
rex = CaseCompileRegExp(regexp);
if (rex.failed)
{
return 0;
}
if (RegExMatchSubString(rex,teststring,start,end))
{
return true;
}
else
{
return false;
}
}
/*********************************************************************/
int IsRegex(char *str)
{ char *sp;
int ret = false;
enum { r_norm, r_norepeat, r_literal } special = r_norepeat;
int bracket = 0;
int paren = 0;
/* Try to see when something is intended as a regular expression */
for (sp = str; *sp != '\0'; sp++)
{
if (special == r_literal)
{
special = r_norm;
continue;
}
else if (*sp == '\\')
{
special = r_literal;
continue;
}
else if (bracket && *sp != ']')
{
if (*sp == '[')
{
return false;
}
continue;
}
switch (*sp)
{
case '^':
special = (sp == str) ? r_norepeat : r_norm;
break;
case '*':
case '+':
if (special == r_norepeat)
{
return false;
}
special = r_norepeat;
ret = true;
break;
case '[':
special = r_norm;
bracket++;
ret = true;
break;
case ']':
if (bracket == 0)
{
return false;
}
bracket = 0;
special = r_norm;
break;
case '(':
special = r_norepeat;
paren++;
break;
case ')':
special = r_norm;
paren--;
if (paren < 0)
{
return false;
}
break;
case '|':
special = r_norepeat;
if (paren > 0)
{
ret = true;
}
break;
default:
special = r_norm;
}
}
if (bracket != 0 || paren != 0 || special == r_literal)
{
return false;
}
else
{
return ret;
}
}
/*********************************************************************/
int IsPathRegex(char *str)
{ char *sp;
int result = false,s = 0,r = 0;
if ((result = IsRegex(str)))
{
for (sp = str; *sp != '\0'; sp++)
{
switch(*sp)
{
case '[':
s++;
break;
case ']':
s--;
if (s % 2 == 0)
{
result++;
}
break;
case '(':
r++;
break;
case')':
r--;
if (r % 2 == 0)
{
result++;
}
break;
default:
if (*sp == FILE_SEPARATOR && (r || s))
{
CfOut(cf_error,"","Path regular expression %s seems to use expressions containing the directory symbol %c",str,FILE_SEPARATOR);
CfOut(cf_error,"","Use a work-around to avoid pathological behaviour\n");
return false;
}
break;
}
}
}
return result;
}
/*********************************************************************/
int IsRegexItemIn(struct Item *list,char *regex)
/* Checks whether item matches a list of wildcards */
{ struct Item *ptr;
for (ptr = list; ptr != NULL; ptr=ptr->next)
{
if (ptr->classes && IsExcluded(ptr->classes))
{
continue;
}
/* Avoid using regex if possible, due to memory leak */
if (strcmp(regex,ptr->name) == 0)
{
return(true);
}
/* Make it commutative */
if (FullTextMatch(regex,ptr->name) || FullTextMatch(ptr->name,regex))
{
Debug("IsRegexItem(%s,%s)\n",regex,ptr->name);
return(true);
}
}
return(false);
}
/*********************************************************************/
int MatchPolicy(char *camel,char *haystack,struct Attributes a,struct Promise *pp)
{ struct Rlist *rp;
char *sp,*spto,*firstchar,*lastchar;
enum insert_match opt;
char work[CF_BUFSIZE],final[CF_BUFSIZE];
struct Item *list = SplitString(camel,'\n'),*ip;
int direct_cmp = false, ok = false;
//Split into separate lines first
for (ip = list; ip != NULL; ip = ip->next)
{
ok = false;
direct_cmp = (strcmp(camel,haystack) == 0);
if (a.insert_match == NULL)
{
// No whitespace policy means exact_match
ok = ok || direct_cmp;
break;
}
memset(final,0,CF_BUFSIZE);
strncpy(final,ip->name,CF_BUFSIZE-1);
for (rp = a.insert_match; rp != NULL; rp=rp->next)
{
opt = String2InsertMatch(rp->item);
/* Exact match can be done immediately */
if (opt == cf_exact_match)
{
if (rp->next != NULL || rp != a.insert_match)
{
CfOut(cf_error,""," !! Multiple policies conflict with \"exact_match\", using exact match");
PromiseRef(cf_error,pp);
}
ok = ok || direct_cmp;
break;
}
if (opt == cf_ignore_embedded)
{
memset(work,0,CF_BUFSIZE);
// Strip initial and final first
for (firstchar = final; isspace(*firstchar); firstchar++)
{
}
for (lastchar = final+strlen(final)-1; lastchar > firstchar && isspace(*lastchar); lastchar--)
{
}
for (sp = final,spto = work; *sp != '\0'; sp++)
{
if (sp > firstchar && sp < lastchar)
{
if (isspace(*sp))
{
while (isspace(*(sp+1)))
{
sp++;
}
strcat(spto,"\\s+");
spto += 3;
}
else
{
*spto++ = *sp;
}
}
else
{
*spto++ = *sp;
}
}
strcpy(final,work);
}
if (opt == cf_ignore_leading)
{
if (strncmp(final,"\\s*",3) != 0)
{
for (sp = final; isspace(*sp); sp++)
{
}
strcpy(work,sp);
snprintf(final,CF_BUFSIZE,"\\s*%s",work);
}
}
if (opt == cf_ignore_trailing)
{
if (strncmp(final+strlen(final)-4,"\\s*",3) != 0)
{
strcpy(work,final);
snprintf(final,CF_BUFSIZE,"%s\\s*",work);
}
}
ok = ok || FullTextMatch(final,haystack);
}
if (!ok) // All lines in region need to match to avoid insertions
{
break;
}
strcmp(final,work);
}
DeleteItemList(list);
return ok;
}
/*********************************************************************/
int MatchRlistItem(struct Rlist *listofregex, const char *teststring)
/* Checks whether item matches a list of wildcards */
{ struct Rlist *rp;
for (rp = listofregex; rp != NULL; rp=rp->next)
{
/* Avoid using regex if possible, due to memory leak */
if (strcmp(teststring,rp->item) == 0)
{
return(true);
}
/* Make it commutative */
if (FullTextMatch(rp->item,teststring))
{
Debug("MatchRlistItem(%s > %s)\n", (char *)rp->item, teststring);
return true;
}
}
return false;
}
/*********************************************************************/
/* Enumerated languages - fuzzy match model */
/*********************************************************************/
int FuzzyMatchParse(char *s)
{ char *sp;
short isCIDR = false, isrange = false, isv6 = false, isv4 = false, isADDR = false;
char address[CF_ADDRSIZE];
int mask,count = 0;
Debug("Check ParsingIPRange(%s)\n",s);
for (sp = s; *sp != '\0'; sp++) /* Is this an address or hostname */
{
if (!isxdigit((int)*sp))
{
isADDR = false;
break;
}
if (*sp == ':') /* Catches any ipv6 address */
{
isADDR = true;
break;
}
if (isdigit((int)*sp)) /* catch non-ipv4 address - no more than 3 digits */
{
count++;
if (count > 3)
{
isADDR = false;
break;
}
}
else
{
count = 0;
}
}
if (! isADDR)
{
return true;
}
if (strstr(s,"/") != 0)
{
isCIDR = true;
}
if (strstr(s,"-") != 0)
{
isrange = true;
}
if (strstr(s,".") != 0)
{
isv4 = true;
}
if (strstr(s,":") != 0)
{
isv6 = true;
}
if (isv4 && isv6)
{
CfOut(cf_error,"","Mixture of IPv6 and IPv4 addresses");
return false;
}
if (isCIDR && isrange)
{
CfOut(cf_error,"","Cannot mix CIDR notation with xx-yy range notation");
return false;
}
if (isv4 && isCIDR)
{
if (strlen(s) > 4+3*4+1+2) /* xxx.yyy.zzz.mmm/cc */
{
CfOut(cf_error,"","IPv4 address looks too long");
return false;
}
address[0] = '\0';
mask = 0;
sscanf(s,"%16[^/]/%d",address,&mask);
if (mask < 8)
{
CfOut(cf_error,"","Mask value %d in %s is less than 8",mask,s);
return false;
}
if (mask > 30)
{
CfOut(cf_error,"","Mask value %d in %s is silly (> 30)",mask,s);
return false;
}
}
if (isv4 && isrange)
{
long i, from = -1, to = -1;
char *sp1,buffer1[CF_MAX_IP_LEN];
sp1 = s;
for (i = 0; i < 4; i++)
{
buffer1[0] = '\0';
sscanf(sp1,"%[^.]",buffer1);
sp1 += strlen(buffer1)+1;
if (strstr(buffer1,"-"))
{
sscanf(buffer1,"%ld-%ld",&from,&to);
if (from < 0 || to < 0)
{
CfOut(cf_error,"","Error in IP range - looks like address, or bad hostname");
return false;
}
if (to < from)
{
CfOut(cf_error,"","Bad IP range");
return false;
}
}
}
}
if (isv6 && isCIDR)
{
char address[CF_ADDRSIZE];
int mask,blocks;
if (strlen(s) < 20)
{
CfOut(cf_error,"","IPv6 address looks too short");
return false;
}
if (strlen(s) > 42)
{
CfOut(cf_error,"","IPv6 address looks too long");
return false;
}
address[0] = '\0';
mask = 0;
sscanf(s,"%40[^/]/%d",address,&mask);
blocks = mask/8;
if (mask % 8 != 0)
{
CfOut(cf_error,"","Cannot handle ipv6 masks which are not 8 bit multiples (fix me)");
return false;
}
if (mask > 15)
{
CfOut(cf_error,"","IPv6 CIDR mask is too large");
return false;
}
}
return true;
}
/*********************************************************************/
int FuzzySetMatch(char *s1,char *s2)
/* Match two IP strings - with : or . in hex or decimal
s1 is the test string, and s2 is the reference e.g.
FuzzySetMatch("128.39.74.10/23","128.39.75.56") == 0 */
{ short isCIDR = false, isrange = false, isv6 = false, isv4 = false;
char address[CF_ADDRSIZE];
int mask;
unsigned long a1,a2;
if (strcmp(s1,s2) == 0)
{
return 0;
}
if (strstr(s1,"/") != 0)
{
isCIDR = true;
}
if (strstr(s1,"-") != 0)
{
isrange = true;
}
if (strstr(s1,".") != 0)
{
isv4 = true;
}
if (strstr(s1,":") != 0)
{
isv6 = true;
}
if (strstr(s2,".") != 0)
{
isv4 = true;
}
if (strstr(s2,":") != 0)
{
isv6 = true;
}
if (isv4 && isv6)
{
/* This is just wrong */
return -1;
}
if (isCIDR && isrange)
{
CfOut(cf_error,"","Cannot mix CIDR notation with xxx-yyy range notation: %s",s1);
return -1;
}
if (!(isv6 || isv4))
{
CfOut(cf_error,"","Not a valid address range - or not a fully qualified name: %s",s1);
return -1;
}
if (!(isrange||isCIDR))
{
if (strlen(s2) > strlen(s1))
{
if (*(s2+strlen(s1)) != '.')
{
return -1; // Because xxx.1 should not match xxx.12 in the same octet
}
}
return strncmp(s1,s2,strlen(s1)); /* do partial string match */
}
if (isv4)
{
if (isCIDR)
{
struct sockaddr_in addr1,addr2;
int shift;
address[0] = '\0';
mask = 0;
sscanf(s1,"%16[^/]/%d",address,&mask);
shift = 32 - mask;
sockaddr_pton(AF_INET, address, &addr1);
sockaddr_pton(AF_INET, s2, &addr2);
a1 = htonl(addr1.sin_addr.s_addr);
a2 = htonl(addr2.sin_addr.s_addr);
a1 = a1 >> shift;
a2 = a2 >> shift;
if (a1 == a2)
{
return 0;
}
else
{
return -1;
}
}
else
{
long i, from = -1, to = -1, cmp = -1;
char *sp1,*sp2,buffer1[CF_MAX_IP_LEN],buffer2[CF_MAX_IP_LEN];
sp1 = s1;
sp2 = s2;
for (i = 0; i < 4; i++)
{
buffer1[0] = '\0';
sscanf(sp1,"%[^.]",buffer1);
if (strlen(buffer1) == 0)
{
break;
}
sp1 += strlen(buffer1)+1;
sscanf(sp2,"%[^.]",buffer2);
sp2 += strlen(buffer2)+1;
if (strstr(buffer1,"-"))
{
sscanf(buffer1,"%ld-%ld",&from,&to);
sscanf(buffer2,"%ld",&cmp);
if (from < 0 || to < 0)
{
Debug("Couldn't read range\n");
return -1;
}
if ((from > cmp) || (cmp > to))
{
Debug("Out of range %ld > %ld > %ld (range %s)\n",from,cmp,to,buffer2);
return -1;
}
}
else
{
sscanf(buffer1,"%ld",&from);
sscanf(buffer2,"%ld",&cmp);
if (from != cmp)
{
Debug("Unequal\n");
return -1;
}
}
Debug("Matched octet %s with %s\n",buffer1,buffer2);
}
Debug("Matched IP range\n");
return 0;
}
}
#if defined(HAVE_GETADDRINFO)
if (isv6)
{
int i;
if (isCIDR)
{
int blocks;
struct sockaddr_in6 addr1,addr2;
address[0] = '\0';
mask = 0;
sscanf(s1,"%40[^/]/%d",address,&mask);
blocks = mask/8;
if (mask % 8 != 0)
{
CfOut(cf_error,"","Cannot handle ipv6 masks which are not 8 bit multiples (fix me)");
return -1;
}
sockaddr_pton(AF_INET6, address, &addr1);
sockaddr_pton(AF_INET6, s2, &addr2);
for (i = 0; i < blocks; i++) /* blocks < 16 */
{
if (addr1.sin6_addr.s6_addr[i] != addr2.sin6_addr.s6_addr[i])
{
return -1;
}
}
return 0;
}
else
{
long i, from = -1, to = -1, cmp = -1;
char *sp1,*sp2,buffer1[CF_MAX_IP_LEN],buffer2[CF_MAX_IP_LEN];
sp1 = s1;
sp2 = s2;
for (i = 0; i < 8; i++)
{
sscanf(sp1,"%[^:]",buffer1);
sp1 += strlen(buffer1)+1;
sscanf(sp2,"%[^:]",buffer2);
sp2 += strlen(buffer2)+1;
if (strstr(buffer1,"-"))
{
sscanf(buffer1,"%lx-%lx",&from,&to);
sscanf(buffer2,"%lx",&cmp);
if (from < 0 || to < 0)
{
return -1;
}
if ((from >= cmp) || (cmp > to))
{
Debug("%lx < %lx < %lx\n",from,cmp,to);
return -1;
}
}
else
{
sscanf(buffer1,"%ld",&from);
sscanf(buffer2,"%ld",&cmp);
if (from != cmp)
{
return -1;
}
}
}
return 0;
}
}
#endif
return -1;
}
/*********************************************************************/
int FuzzyHostParse(char *arg1,char *arg2)
{
long start = -1, end = -1, where = -1;
int n;
n = sscanf(arg2,"%ld-%ld%n",&start,&end,&where);
if (n != 2)
{
CfOut(cf_error,"","HostRange syntax error: second arg should have X-Y format where X and Y are decimal numbers");
return false;
}
return true;
}
/*********************************************************************/
int FuzzyHostMatch(char *arg0, char* arg1, char *refhost)
{
char *sp, refbase[CF_MAXVARSIZE];
long cmp = -1, start = -1, end = -1;
char buf1[CF_BUFSIZE], buf2[CF_BUFSIZE];
strlcpy(refbase,refhost,CF_MAXVARSIZE);
sp = refbase + strlen(refbase) - 1;
while ( isdigit((int)*sp) )
{
sp--;
}
sp++;
sscanf(sp,"%ld",&cmp);
*sp = '\0';
if (cmp < 0)
{
return 1;
}
if (strlen(refbase) == 0)
{
return 1;
}
sscanf(arg1,"%ld-%ld",&start,&end);
if ( cmp < start || cmp > end )
{
return 1;
}
strncpy(buf1,ToLowerStr(refbase),CF_BUFSIZE-1);
strncpy(buf2,ToLowerStr(arg0),CF_BUFSIZE-1);
if (strcmp(buf1,buf2) != 0)
{
return 1;
}
return 0;
}
/*********************************************************************/
void EscapeSpecialChars(char *str, char *strEsc, int strEscSz, char *noEsc)
/* Escapes non-alphanumeric chars, except sequence given in noEsc */
{ char *sp;
int strEscPos = 0;
if (noEsc == NULL)
{
noEsc = "";
}
memset(strEsc, 0, strEscSz);
for (sp = str; (*sp != '\0') && (strEscPos < strEscSz - 2); sp++)
{
if (strncmp(sp, noEsc, strlen(noEsc)) == 0)
{
if (strEscSz <= strEscPos + strlen(noEsc))
{
break;
}
strcat(strEsc, noEsc);
strEscPos += strlen(noEsc);
sp += strlen(noEsc);
}
if (*sp != '\0' && !isalnum(*sp))
{
strEsc[strEscPos++] = '\\';
}
strEsc[strEscPos++] = *sp;
}
}
/*********************************************************************/
char *EscapeChar(char *str, int strSz, char esc)
/* Escapes characters esc in the string str of size strSz */
{ char strDup[CF_BUFSIZE];
int strPos, strDupPos;
if(sizeof(strDup) < strSz)
{
FatalError("Too large string passed to EscapeCharInplace()\n");
}
snprintf(strDup, sizeof(strDup), "%s", str);
memset(str, 0, strSz);
for(strPos = 0, strDupPos = 0; strPos < strSz - 2; strPos++, strDupPos++)
{
if(strDup[strDupPos] == esc)
{
str[strPos] = '\\';
strPos++;
}
str[strPos] = strDup[strDupPos];
}
return str;
}
/*********************************************************************/
void AnchorRegex(char *regex, char *out, int outSz)
{
if (EMPTY(regex))
{
memset(out,0,outSz);
}
else
{
snprintf(out,outSz,"^(%s)$",regex);
}
}
/* EOF */
cfengine-3.2.4/src/promises.c 0000644 0001750 0001750 00000052537 11715232734 013034 0000000 0000000 /*
Copyright (C) Cfengine AS
This file is part of Cfengine 3 - written and maintained by Cfengine 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 Commerical Open Source License
(COSL) may apply to this file if you as a licensee so wish it. See
included file COSL.txt.
*/
/*****************************************************************************/
/* */
/* File: promises.c */
/* */
/*****************************************************************************/
#include "cf3.defs.h"
#include "cf3.extern.h"
static void DeleteDeRefPromise(char *scopeid,struct Promise *pp);
static void DebugPromise(struct Promise *pp);
static void DereferenceComment(struct Promise *pp);
/*****************************************************************************/
char *BodyName(struct Promise *pp)
{ char *name,*sp;
int i,size = 0;
struct Constraint *cp;
/* Return a type template for the promise body for lock-type identification */
if ((name = malloc(CF_MAXVARSIZE)) == NULL)
{
FatalError("BodyName");
}
sp = pp->agentsubtype;
if (size + strlen(sp) < CF_MAXVARSIZE-CF_BUFFERMARGIN)
{
strcpy(name,sp);
strcat(name,".");
size += strlen(sp);
}
for (i = 0,cp = pp->conlist; (i < 5) && cp != NULL; i++,cp=cp->next)
{
if (strcmp(cp->lval,"args") == 0) /* Exception for args, by symmetry, for locking */
{
continue;
}
if (size + strlen(cp->lval) < CF_MAXVARSIZE-CF_BUFFERMARGIN)
{
strcat(name,cp->lval);
strcat(name,".");
size += strlen(cp->lval);
}
}
return name;
}
/*****************************************************************************/
struct Promise *DeRefCopyPromise(char *scopeid,struct Promise *pp)
{ struct Promise *pcopy;
struct Constraint *cp,*scp;
struct Rval returnval;
if (pp->promisee)
{
Debug("CopyPromise(%s->",pp->promiser);
if (DEBUG)
{
ShowRval(stdout,pp->promisee,pp->petype);
}
Debug("\n");
}
else
{
Debug("CopyPromise(%s->)\n",pp->promiser);
}
if ((pcopy = (struct Promise *)malloc(sizeof(struct Promise))) == NULL)
{
CfOut(cf_error,"malloc","Promise allocation failure");
FatalError("memory");
}
if (pp->promiser)
{
pcopy->promiser = strdup(pp->promiser);
}
if (pp->promisee)
{
pcopy->promisee = CopyRvalItem(pp->promisee,pp->petype);
pcopy->petype = pp->petype;
}
else
{
pcopy->promisee = NULL;
}
if (pp->classes)
{
pcopy->classes = strdup(pp->classes);
}
if (pcopy->promiser == NULL || (pp->promisee != NULL && pcopy->promisee == NULL) || pcopy->classes == NULL)
{
CfOut(cf_error,"malloc","Promise detail allocation failure");
FatalError("memory");
}
pcopy->bundletype = strdup(pp->bundletype);
pcopy->audit = pp->audit;
pcopy->lineno = pp->lineno;
pcopy->petype = pp->petype; /* rtype of promisee - list or scalar recipient? */
pcopy->bundle = strdup(pp->bundle);
pcopy->ref = pp->ref;
pcopy->ref_alloc = pp->ref_alloc;
pcopy->agentsubtype = pp->agentsubtype;
pcopy->done = pp->done;
pcopy->conlist = NULL;
pcopy->next = NULL;
pcopy->cache = NULL;
pcopy->inode_cache = pp->inode_cache;
pcopy->this_server = pp->this_server;
pcopy->donep = pp->donep;
pcopy->conn = pp->conn;
pcopy->edcontext = pp->edcontext;
Debug("Copying promise constraints\n\n");
/* No further type checking should be necessary here, already done by CheckConstraintTypeMatch */
for (cp = pp->conlist; cp != NULL; cp=cp->next)
{
struct Body *bp = NULL;
struct FnCall *fp = NULL;
struct Rlist *rnew;
char *bodyname = NULL;
/* A body template reference could look like a scalar or fn to the parser w/w () */
switch (cp->type)
{
case CF_SCALAR:
bodyname = (char *)cp->rval;
if (cp->isbody)
{
bp = IsBody(BODIES,bodyname);
}
fp = NULL;
break;
case CF_FNCALL:
fp = (struct FnCall *)cp->rval;
bodyname = fp->name;
bp = IsBody(BODIES,bodyname);
break;
default:
bp = NULL;
fp = NULL;
bodyname = NULL;
break;
}
/* First case is: we have a body template to expand lval = body(args), .. */
if (bp != NULL)
{
if (strcmp(bp->type,cp->lval) != 0)
{
CfOut(cf_error,"","Body type mismatch for body reference \"%s\" in promise at line %d of %s (%s != %s)\n",bodyname,pp->lineno,(pp->audit)->filename,bp->type,cp->lval);
ERRORCOUNT++;
}
/* Keep the referent body type as a boolean for convenience when checking later */
AppendConstraint(&(pcopy->conlist),cp->lval,strdup("true"),CF_SCALAR,cp->classes,false);
Debug("Handling body-lval \"%s\"\n",cp->lval);
if (bp->args != NULL)
{
/* There are arguments to insert*/
if (fp == NULL || fp->args == NULL)
{
CfOut(cf_error,"","Argument mismatch for body reference \"%s\" in promise at line %d of %s\n",bodyname,pp->lineno,(pp->audit)->filename);
}
NewScope("body");
if (fp && bp && fp->args && bp->args && !MapBodyArgs("body",fp->args,bp->args))
{
ERRORCOUNT++;
CfOut(cf_error,"","Number of arguments does not match for body reference \"%s\" in promise at line %d of %s\n",bodyname,pp->lineno,(pp->audit)->filename);
}
for (scp = bp->conlist; scp != NULL; scp = scp->next)
{
Debug("Doing arg-mapped sublval = %s (promises.c)\n",scp->lval);
returnval = ExpandPrivateRval("body",scp->rval,scp->type);
AppendConstraint(&(pcopy->conlist),scp->lval,returnval.item,returnval.rtype,scp->classes,false);
}
DeleteScope("body");
}
else
{
/* No arguments to deal with or body undeclared */
if (fp != NULL)
{
CfOut(cf_error,"","An apparent body \"%s()\" was undeclared or could have incorrect args, but used in a promise near line %d of %s (possible unquoted literal value)",bodyname,pp->lineno,(pp->audit)->filename);
}
else
{
for (scp = bp->conlist; scp != NULL; scp = scp->next)
{
Debug("Doing sublval = %s (promises.c)\n",scp->lval);
rnew = CopyRvalItem(scp->rval,scp->type);
AppendConstraint(&(pcopy->conlist),scp->lval,rnew,scp->type,scp->classes,false);
}
}
}
}
else
{
if (cp->isbody && !IsBundle(BUNDLES,bodyname))
{
CfOut(cf_error,"","Apparent body \"%s()\" was undeclared, but used in a promise near line %d of %s (possible unquoted literal value)",bodyname,pp->lineno,(pp->audit)->filename);
}
rnew = CopyRvalItem(cp->rval,cp->type);
scp = AppendConstraint(&(pcopy->conlist),cp->lval,rnew,cp->type,cp->classes,false);
}
}
return pcopy;
}
/*****************************************************************************/
struct Promise *ExpandDeRefPromise(char *scopeid,struct Promise *pp)
{ struct Promise *pcopy;
struct Constraint *cp;
struct Rval returnval,final;
Debug("ExpandDerefPromise()\n");
if ((pcopy = (struct Promise *)malloc(sizeof(struct Promise))) == NULL)
{
CfOut(cf_error,"malloc","Promise allocation failure");
FatalError("memory");
}
returnval = ExpandPrivateRval("this",pp->promiser,CF_SCALAR);
pcopy->promiser = (char *)returnval.item;
if (pp->promisee)
{
returnval = EvaluateFinalRval(scopeid,pp->promisee,pp->petype,true,pp);
pcopy->promisee = (struct Rlist *)returnval.item;
pcopy->petype = returnval.rtype;
}
else
{
pcopy->petype = CF_NOPROMISEE;
pcopy->promisee = NULL;
}
if (pp->classes)
{
pcopy->classes = strdup(pp->classes);
}
else
{
pcopy->classes = strdup("any");
}
if (pcopy->promiser == NULL || pcopy->classes == NULL)
{
CfOut(cf_error,"malloc","ExpandPromise detail allocation failure");
FatalError("memory");
}
pcopy->bundletype = strdup(pp->bundletype);
pcopy->done = pp->done;
pcopy->donep = pp->donep;
pcopy->audit = pp->audit;
pcopy->lineno = pp->lineno;
pcopy->bundle = strdup(pp->bundle);
pcopy->ref = pp->ref;
pcopy->ref_alloc = pp->ref_alloc;
pcopy->agentsubtype = pp->agentsubtype;
pcopy->conlist = NULL;
pcopy->next = NULL;
pcopy->cache = pp->cache;
pcopy->inode_cache = pp->inode_cache;
pcopy->this_server = pp->this_server;
pcopy->conn = pp->conn;
pcopy->edcontext = pp->edcontext;
/* No further type checking should be necessary here, already done by CheckConstraintTypeMatch */
for (cp = pp->conlist; cp != NULL; cp=cp->next)
{
struct Rval returnval;
if (ExpectedDataType(cp->lval) == cf_bundle)
{
final = ExpandBundleReference(scopeid,cp->rval,cp->type);
}
else
{
returnval = EvaluateFinalRval(scopeid,cp->rval,cp->type,false,pp);
final = ExpandDanglers(scopeid,returnval,pp);
DeleteRvalItem(returnval.item,returnval.rtype);
}
AppendConstraint(&(pcopy->conlist),cp->lval,final.item,final.rtype,cp->classes,false);
if (strcmp(cp->lval,"comment") == 0)
{
if (final.rtype != CF_SCALAR)
{
char err[CF_BUFSIZE];
snprintf(err,CF_BUFSIZE,"Comments can only be scalar objects (not %c in \"%s\")",final.rtype,pp->promiser);
yyerror(err);
}
else
{
pcopy->ref = final.item; /* No alloc reference to comment item */
if (pcopy->ref && (strstr(pcopy->ref,"$(this.promiser)") || strstr(pcopy->ref,"${this.promiser}")))
{
DereferenceComment(pcopy);
}
}
}
}
return pcopy;
}
/*****************************************************************************/
struct Promise *CopyPromise(char *scopeid,struct Promise *pp)
{ struct Promise *pcopy;
struct Constraint *cp;
struct Rval returnval,final;
Debug("CopyPromise()\n");
if ((pcopy = (struct Promise *)malloc(sizeof(struct Promise))) == NULL)
{
CfOut(cf_error,"malloc","Promise allocation failure");
FatalError("memory");
}
pcopy->promiser = strdup(pp->promiser);
if (pp->promisee)
{
returnval = EvaluateFinalRval(scopeid,pp->promisee,pp->petype,true,pp);
pcopy->promisee = (struct Rlist *)returnval.item;
pcopy->petype = returnval.rtype;
}
else
{
pcopy->petype = CF_NOPROMISEE;
pcopy->promisee = NULL;
}
if (pp->classes)
{
pcopy->classes = strdup(pp->classes);
}
else
{
pcopy->classes = strdup("any");
}
if (pcopy->promiser == NULL || pcopy->classes == NULL)
{
CfOut(cf_error,"malloc","ExpandPromise detail allocation failure");
FatalError("memory");
}
pcopy->bundletype = strdup(pp->bundletype);
pcopy->done = pp->done;
pcopy->donep = pp->donep;
pcopy->audit = pp->audit;
pcopy->lineno = pp->lineno;
pcopy->bundle = strdup(pp->bundle);
pcopy->ref = pp->ref;
pcopy->ref_alloc = pp->ref_alloc;
pcopy->agentsubtype = pp->agentsubtype;
pcopy->conlist = NULL;
pcopy->next = NULL;
pcopy->cache = pp->cache;
pcopy->inode_cache = pp->inode_cache;
pcopy->this_server = pp->this_server;
pcopy->conn = pp->conn;
pcopy->edcontext = pp->edcontext;
/* No further type checking should be necessary here, already done by CheckConstraintTypeMatch */
for (cp = pp->conlist; cp != NULL; cp=cp->next)
{
struct Rval returnval;
if (ExpectedDataType(cp->lval) == cf_bundle)
{
/* sub-bundles do not expand here */
returnval = ExpandPrivateRval(scopeid,cp->rval,cp->type);
}
else
{
returnval = EvaluateFinalRval(scopeid,cp->rval,cp->type,false,pp);
}
final = ExpandDanglers(scopeid,returnval,pp);
AppendConstraint(&(pcopy->conlist),cp->lval,final.item,final.rtype,cp->classes,false);
if (strcmp(cp->lval,"comment") == 0)
{
if (final.rtype != CF_SCALAR)
{
yyerror("Comments can only be scalar objects");
}
else
{
pcopy->ref = final.item; /* No alloc reference to comment item */
}
}
}
return pcopy;
}
/*******************************************************************/
static void DebugPromise(struct Promise *pp)
{ struct Constraint *cp;
struct Body *bp;
struct FnCall *fp;
struct Rlist *rp;
char *v,rettype;
void *retval;
if (GetVariable("control_common","version",&retval,&rettype) != cf_notype)
{
v = (char *)retval;
}
else
{
v = "not specified";
}
if (pp->promisee != NULL)
{
fprintf(stdout,"%s promise by \'%s\' -> ",pp->agentsubtype,pp->promiser);
ShowRval(stdout,pp->promisee,pp->petype);
fprintf(stdout," if context is %s\n",pp->classes);
}
else
{
fprintf(stdout,"%s promise by \'%s\' (implicit) if context is %s\n",pp->agentsubtype,pp->promiser,pp->classes);
}
fprintf(stdout,"in bundle %s of type %s\n",pp->bundle,pp->bundletype);
for (cp = pp->conlist; cp != NULL; cp = cp->next)
{
fprintf(stdout,"%10s => ",cp->lval);
switch (cp->type)
{
case CF_SCALAR:
if ((bp = IsBody(BODIES,(char *)cp->rval)))
{
ShowBody(bp,15);
}
else
{
ShowRval(stdout,cp->rval,cp->type); /* literal */
}
break;
case CF_LIST:
rp = (struct Rlist *)cp->rval;
ShowRlist(stdout,rp);
break;
case CF_FNCALL:
fp = (struct FnCall *)cp->rval;
if ((bp = IsBody(BODIES,fp->name)))
{
ShowBody(bp,15);
}
else
{
ShowRval(stdout,cp->rval,cp->type); /* literal */
}
break;
default:
printf("Unknown RHS type %c\n",cp->type);
}
if (cp->type != CF_FNCALL)
{
fprintf(stdout," if body context %s\n",cp->classes);
}
}
}
/*******************************************************************/
struct Body *IsBody(struct Body *list,char *key)
{ struct Body *bp;
for (bp = list; bp != NULL; bp = bp->next)
{
if (strcmp(bp->name,key) == 0)
{
return bp;
}
}
return NULL;
}
/*******************************************************************/
struct Bundle *IsBundle(struct Bundle *list,char *key)
{ struct Bundle *bp;
for (bp = list; bp != NULL; bp = bp->next)
{
if (strcmp(bp->name,key) == 0)
{
return bp;
}
}
return NULL;
}
/*****************************************************************************/
/* Cleanup */
/*****************************************************************************/
void DeletePromises(struct Promise *pp)
{
if (pp == NULL)
{
return;
}
if (pp->this_server != NULL)
{
ThreadLock(cft_policy);
free(pp->this_server);
ThreadUnlock(cft_policy);
}
if (pp->next != NULL)
{
DeletePromises(pp->next);
}
if (pp->ref_alloc == 'y')
{
ThreadLock(cft_policy);
free(pp->ref);
ThreadUnlock(cft_policy);
}
DeletePromise(pp);
}
/*****************************************************************************/
struct Promise *NewPromise(char *typename,char *promiser)
{ struct Promise *pp;
ThreadLock(cft_policy);
if ((pp = (struct Promise *)malloc(sizeof(struct Promise))) == NULL)
{
CfOut(cf_error,"malloc","Unable to allocate Promise");
FatalError("");
}
pp->audit = AUDITPTR;
pp->lineno = 0;
pp->bundle = strdup("internal_bundle");
pp->promiser = strdup(promiser);
ThreadUnlock(cft_policy);
pp->promisee = NULL;
pp->petype = CF_NOPROMISEE;
pp->classes = NULL;
pp->done = false;
pp->donep = &(pp->done);
pp->this_server = NULL;
pp->cache = NULL;
pp->conn = NULL;
pp->inode_cache = NULL;
pp->cache = NULL;
pp->bundletype = NULL;
pp->agentsubtype = typename; /* cache this, not copy strdup(typename);*/
pp->ref = NULL; /* cache a reference if given*/
pp->ref_alloc = 'n';
pp->next = NULL;
pp->conlist = NULL; // this fn is used for internal promises only
AppendConstraint(&(pp->conlist), "handle", strdup("internal_promise"),CF_SCALAR,NULL,false);
return pp;
}
/*****************************************************************************/
void DeletePromise(struct Promise *pp)
{
if (pp == NULL)
{
return;
}
Debug("DeletePromise(%s->[%c])\n",pp->promiser,pp->petype);
ThreadLock(cft_policy);
if (pp->promiser != NULL)
{
free(pp->promiser);
}
if (pp->promisee != NULL)
{
DeleteRvalItem(pp->promisee,pp->petype);
}
free(pp->bundle);
free(pp->bundletype);
free(pp->classes);
// ref and agentsubtype are only references, do not free
DeleteConstraintList(pp->conlist);
free((char *)pp);
ThreadUnlock(cft_policy);
}
/*****************************************************************************/
static void DeleteDeRefPromise(char *scopeid,struct Promise *pp)
{ struct Constraint *cp;
Debug("DeleteDeRefPromise()\n");
free(pp->promiser);
if (pp->promisee)
{
DeleteRvalItem(pp->promisee,pp->petype);
}
if (pp->classes)
{
free(pp->classes);
}
free(pp->bundle);
for (cp = pp->conlist; cp != NULL; cp=cp->next)
{
free(cp->lval);
DeleteRvalItem(cp->rval,cp->type);
}
free(pp);
}
/*****************************************************************************/
void PromiseRef(enum cfreport level,struct Promise *pp)
{ char *v,rettype;
void *retval;
if (pp == NULL)
{
return;
}
if (GetVariable("control_common","version",&retval,&rettype) != cf_notype)
{
v = (char *)retval;
}
else
{
v = "not specified";
}
if (pp->audit)
{
CfOut(level,"","Promise (version %s) belongs to bundle \'%s\' in file \'%s\' near line %d\n",v,pp->bundle,pp->audit->filename,pp->lineno);
}
else
{
CfOut(level,"","Promise (version %s) belongs to bundle \'%s\' near line %d\n",v,pp->bundle,pp->lineno);
}
if (pp->ref)
{
CfOut(level,"","Comment: %s\n",pp->ref);
}
}
/*******************************************************************/
void HashPromise(char *salt,struct Promise *pp,unsigned char digest[EVP_MAX_MD_SIZE+1],enum cfhashes type)
{ EVP_MD_CTX context;
int md_len;
const EVP_MD *md = NULL;
struct Constraint *cp;
struct Rlist *rp;
struct FnCall *fp;
char *noRvalHash[] = { "mtime", "atime", "ctime", NULL };
int doHash;
int i;
md = EVP_get_digestbyname(FileHashName(type));
EVP_DigestInit(&context,md);
// multiple packages (promisers) may share same package_list_update_ifelapsed lock
if (!(salt && (strncmp(salt, PACK_UPIFELAPSED_SALT, sizeof(PACK_UPIFELAPSED_SALT) - 1) == 0)))
{
EVP_DigestUpdate(&context,pp->promiser,strlen(pp->promiser));
}
if (pp->ref)
{
EVP_DigestUpdate(&context,pp->ref,strlen(pp->ref));
}
if (pp->this_server)
{
EVP_DigestUpdate(&context,pp->this_server,strlen(pp->this_server));
}
if (salt)
{
EVP_DigestUpdate(&context,salt,strlen(salt));
}
for (cp = pp->conlist; cp != NULL; cp=cp->next)
{
EVP_DigestUpdate(&context,cp->lval,strlen(cp->lval));
// don't hash rvals that change (e.g. times)
doHash = true;
for (i = 0; noRvalHash[i] != NULL; i++ )
{
if (strcmp(cp->lval, noRvalHash[i]) == 0)
{
doHash = false;
break;
}
}
if (!doHash)
{
continue;
}
switch(cp->type)
{
case CF_SCALAR:
EVP_DigestUpdate(&context,cp->rval,strlen(cp->rval));
break;
case CF_LIST:
for (rp = cp->rval; rp != NULL; rp=rp->next)
{
EVP_DigestUpdate(&context,rp->item,strlen(rp->item));
}
break;
case CF_FNCALL:
/* Body or bundle */
fp = (struct FnCall *)cp->rval;
EVP_DigestUpdate(&context,fp->name,strlen(fp->name));
for (rp = fp->args; rp != NULL; rp=rp->next)
{
EVP_DigestUpdate(&context,rp->item,strlen(rp->item));
}
break;
}
}
EVP_DigestFinal(&context,digest,&md_len);
/* Digest length stored in md_len */
}
/*******************************************************************/
static void DereferenceComment(struct Promise *pp)
{ char pre_buffer[CF_BUFSIZE],post_buffer[CF_BUFSIZE],buffer[CF_BUFSIZE],*sp;
int offset = 0;
strlcpy(pre_buffer,pp->ref,CF_BUFSIZE);
if ((sp = strstr(pre_buffer,"$(this.promiser)")) || (sp = strstr(pre_buffer, "${this.promiser}")))
{
*sp = '\0';
offset = sp - pre_buffer + strlen("$(this.promiser)");
strncpy(post_buffer,pp->ref+offset,CF_BUFSIZE);
snprintf(buffer,CF_BUFSIZE,"%s%s%s",pre_buffer,pp->promiser,post_buffer);
if (pp->ref_alloc == 'y')
{
free(pp->ref);
}
pp->ref = strdup(buffer);
pp->ref_alloc = 'y';
}
}
cfengine-3.2.4/src/mod_common.c 0000644 0001750 0001750 00000057445 11715232734 013325 0000000 0000000 /*
Copyright (C) Cfengine AS
This file is part of Cfengine 3 - written and maintained by Cfengine 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 Commerical Open Source License
(COSL) may apply to this file if you as a licensee so wish it. See
included file COSL.txt.
*/
/*****************************************************************************/
/* */
/* File: mod_common.c */
/* */
/* This is a root node in the syntax tree */
/* */
/*****************************************************************************/
#define CF3_MOD_COMMON
#include "cf3.defs.h"
#include "cf3.extern.h"
struct BodySyntax CF_TRANSACTION_BODY[] =
{
{"action_policy",cf_opts,"fix,warn,nop","Whether to repair or report about non-kept promises"},
{"ifelapsed",cf_int,CF_VALRANGE,"Number of minutes before next allowed assessment of promise"},
{"expireafter",cf_int,CF_VALRANGE,"Number of minutes before a repair action is interrupted and retried"},
{"log_string",cf_str,"","A message to be written to the log when a promise verification leads to a repair"},
{"log_level",cf_opts,"inform,verbose,error,log","The reporting level sent to syslog"},
{"log_kept",cf_str,CF_LOGRANGE,"This should be filename of a file to which log_string will be saved, if undefined it goes to the system logger"},
{"log_priority",cf_opts,"emergency,alert,critical,error,warning,notice,info,debug","The priority level of the log message, as interpreted by a syslog server"},
{"log_repaired",cf_str,CF_LOGRANGE,"This should be filename of a file to which log_string will be saved, if undefined it goes to the system logger"},
{"log_failed",cf_str,CF_LOGRANGE,"This should be filename of a file to which log_string will be saved, if undefined it goes to the system logger"},
{"value_kept",cf_real,CF_REALRANGE,"A real number value attributed to keeping this promise"},
{"value_repaired",cf_real,CF_REALRANGE,"A real number value attributed to reparing this promise"},
{"value_notkept",cf_real,CF_REALRANGE,"A real number value (possibly negative) attributed to not keeping this promise"},
{"audit",cf_opts,CF_BOOL,"true/false switch for detailed audit records of this promise"},
{"background",cf_opts,CF_BOOL,"true/false switch for parallelizing the promise repair"},
{"report_level",cf_opts,"inform,verbose,error,log","The reporting level for standard output for this promise"},
{"measurement_class",cf_str,"","If set performance will be measured and recorded under this identifier"},
{NULL,cf_notype,NULL,NULL}
};
/*********************************************************/
struct BodySyntax CF_DEFINECLASS_BODY[] =
{
{"promise_repaired",cf_slist,CF_IDRANGE,"A list of classes to be defined globally"},
{"repair_failed",cf_slist,CF_IDRANGE,"A list of classes to be defined globally"},
{"repair_denied",cf_slist,CF_IDRANGE,"A list of classes to be defined globally"},
{"repair_timeout",cf_slist,CF_IDRANGE,"A list of classes to be defined globally"},
{"promise_kept",cf_slist,CF_IDRANGE,"A list of classes to be defined globally"},
{"cancel_kept",cf_slist,CF_IDRANGE,"A list of classes to be cancelled if the promise is kept"},
{"cancel_repaired",cf_slist,CF_IDRANGE,"A list of classes to be cancelled if the promise is repaired"},
{"cancel_notkept",cf_slist,CF_IDRANGE,"A list of classes to be cancelled if the promise is not kept for any reason"},
{"kept_returncodes",cf_slist,CF_INTLISTRANGE,"A list of return codes indicating a kept command-related promise"},
{"repaired_returncodes",cf_slist,CF_INTLISTRANGE,"A list of return codes indicating a repaired command-related promise"},
{"failed_returncodes",cf_slist,CF_INTLISTRANGE,"A list of return codes indicating a failed command-related promise"},
{"persist_time",cf_int,CF_VALRANGE,"A number of minutes the specified classes should remain active"},
{"timer_policy",cf_opts,"absolute,reset","Whether a persistent class restarts its counter when rediscovered"},
{NULL,cf_notype,NULL,NULL}
};
/*********************************************************/
struct BodySyntax CF_VARBODY[] =
{
{"string",cf_str,"","A scalar string"},
{"int",cf_int,CF_INTRANGE,"A scalar integer"},
{"real",cf_real,CF_REALRANGE,"A scalar real number"},
{"slist",cf_slist,"","A list of scalar strings"},
{"ilist",cf_ilist,CF_INTRANGE,"A list of integers"},
{"rlist",cf_rlist,CF_REALRANGE,"A list of real numbers"},
{"policy",cf_opts,"free,overridable,constant,ifdefined","The policy for (dis)allowing (re)definition of variables"},
{NULL,cf_notype,NULL,NULL}
};
/*********************************************************/
struct BodySyntax CF_CLASSBODY[] =
{
{"or",cf_clist,CF_CLASSRANGE,"Combine class sources with inclusive OR"},
{"and",cf_clist,CF_CLASSRANGE,"Combine class sources with AND"},
{"xor",cf_clist,CF_CLASSRANGE,"Combine class sources with XOR"},
{"dist",cf_rlist,CF_REALRANGE,"Generate a probabilistic class distribution (from strategies in cfengine 2)"},
{"expression",cf_class,CF_CLASSRANGE,"Evaluate string expression of classes in normal form"},
{"not",cf_class,CF_CLASSRANGE,"Evaluate the negation of string expression in normal form"},
{"select_class",cf_rlist,CF_CLASSRANGE,"Select one of the named list of classes to define based on host identity"},
{NULL,cf_notype,NULL,NULL}
};
/*********************************************************/
/* Control bodies */
/*********************************************************/
struct BodySyntax CFG_CONTROLBODY[] =
{
{"bundlesequence",cf_slist,".*","List of promise bundles to verify in order"},
{"goal_categories",cf_slist,"","A list of context names that represent parent categories for goals (goal patterns)"},
{"goal_patterns",cf_slist,"","A list of regular expressions that match promisees/topics considered to be organizational goals"},
{"ignore_missing_bundles",cf_opts,CF_BOOL,"If any bundles in the bundlesequence do not exist, ignore and continue"},
{"ignore_missing_inputs",cf_opts,CF_BOOL,"If any input files do not exist, ignore and continue"},
{"inputs",cf_slist,".*","List of additional filenames to parse for promises"},
{"version",cf_str,"","Scalar version string for this configuration"},
{"lastseenexpireafter",cf_int,CF_VALRANGE,"Number of minutes after which last-seen entries are purged"},
{"output_prefix",cf_str,"","The string prefix for standard output"},
{"domain",cf_str,".*","Specify the domain name for this host"},
{"require_comments",cf_opts,CF_BOOL,"Warn about promises that do not have comment documentation"},
{"host_licenses_paid",cf_int,CF_VALRANGE,"The number of licenses that you promise to have paid for by setting this value (legally binding for commercial license)"},
{"site_classes",cf_clist,CF_CLASSRANGE,"A list of classes that will represent geographical site locations for hosts. These should be defined elsewhere in the configuration in a classes promise."},
{"syslog_host",cf_str,CF_IPRANGE,"The name or address of a host to which syslog messages should be sent directly by UDP"},
{"syslog_port",cf_int,CF_VALRANGE,"The port number of a UDP syslog service"},
{"fips_mode",cf_opts,CF_BOOL,"Activate full FIPS mode restrictions"},
{NULL,cf_notype,NULL,NULL}
};
struct BodySyntax CFA_CONTROLBODY[] =
{
{"abortclasses",cf_slist,".*","A list of classes which if defined lead to termination of cf-agent"},
{"abortbundleclasses",cf_slist,".*","A list of classes which if defined lead to termination of current bundle"},
{"addclasses",cf_slist,".*","A list of classes to be defined always in the current context"},
{"agentaccess",cf_slist,".*","A list of user names allowed to execute cf-agent"},
{"agentfacility",cf_opts,CF_FACILITY,"The syslog facility for cf-agent"},
{"alwaysvalidate",cf_opts,CF_BOOL,"true/false flag to determine whether configurations will always be checked before executing, or only after updates"},
{"auditing",cf_opts,CF_BOOL,"true/false flag to activate the cf-agent audit log"},
{"binarypaddingchar",cf_str,"","Character used to pad unequal replacements in binary editing"},
{"bindtointerface",cf_str,".*","Use this interface for outgoing connections"},
{"hashupdates",cf_opts,CF_BOOL,"true/false whether stored hashes are updated when change is detected in source"},
{"childlibpath",cf_str,".*","LD_LIBRARY_PATH for child processes"},
{"checksum_alert_time",cf_int,"0,60","The persistence time for the checksum_alert class"},
{"defaultcopytype",cf_opts,"mtime,atime,ctime,digest,hash,binary"},
{"dryrun",cf_opts,CF_BOOL,"All talk and no action mode"},
{"editbinaryfilesize",cf_int,CF_VALRANGE,"Integer limit on maximum binary file size to be edited"},
{"editfilesize",cf_int,CF_VALRANGE,"Integer limit on maximum text file size to be edited"},
{"environment",cf_slist,"[A-Za-z0-9_]+=.*","List of environment variables to be inherited by children"},
{"exclamation",cf_opts,CF_BOOL,"true/false print exclamation marks during security warnings"},
{"expireafter",cf_int,CF_VALRANGE,"Global default for time before on-going promise repairs are interrupted"},
{"files_single_copy",cf_slist,"","List of filenames to be watched for multiple-source conflicts"},
{"files_auto_define",cf_slist,"","List of filenames to define classes if copied"},
{"hostnamekeys",cf_opts,CF_BOOL,"true/false label ppkeys by hostname not IP address"},
{"ifelapsed",cf_int,CF_VALRANGE,"Global default for time that must elapse before promise will be rechecked"},
{"inform",cf_opts,CF_BOOL,"true/false set inform level default"},
{"intermittency",cf_opts,CF_BOOL,"true/false store detailed recordings of last observed time for all client-server connections for reliability assessment (false)"},
{"max_children",cf_int,CF_VALRANGE,"Maximum number of background tasks that should be allowed concurrently"},
{"maxconnections",cf_int,CF_VALRANGE,"Maximum number of outgoing connections to cf-serverd"},
{"mountfilesystems",cf_opts,CF_BOOL,"true/false mount any filesystems promised"},
{"nonalphanumfiles",cf_opts,CF_BOOL,"true/false warn about filenames with no alphanumeric content"},
{"repchar",cf_str,".","The character used to canonize pathnames in the file repository"},
{"refresh_processes",cf_slist,CF_IDRANGE,"Reload the process table before verifying the bundles named in this list (lazy evaluation)"},
{"default_repository",cf_str,CF_ABSPATHRANGE,"Path to the default file repository"},
{"secureinput",cf_opts,CF_BOOL,"true/false check whether input files are writable by unauthorized users"},
{"sensiblecount",cf_int,CF_VALRANGE,"Minimum number of files a mounted filesystem is expected to have"},
{"sensiblesize",cf_int,CF_VALRANGE,"Minimum number of bytes a mounted filesystem is expected to have"},
{"skipidentify",cf_opts,CF_BOOL,"Do not send IP/name during server connection because address resolution is broken"},
{"suspiciousnames",cf_slist,"","List of names to warn about if found during any file search"},
{"syslog",cf_opts,CF_BOOL,"true/false switches on output to syslog at the inform level"},
{"track_value",cf_opts,CF_BOOL,"true/false switches on tracking of promise valuation"},
{"timezone",cf_slist,"","List of allowed timezones this machine must comply with"},
{"default_timeout",cf_int,CF_VALRANGE,"Maximum time a network connection should attempt to connect"},
{"verbose",cf_opts,CF_BOOL,"true/false switches on verbose standard output"},
{NULL,cf_notype,NULL,NULL}
};
struct BodySyntax CFS_CONTROLBODY[] =
{
{"allowallconnects",cf_slist,"","List of IPs or hostnames that may have more than one connection to the server port"},
{"allowconnects",cf_slist,"","List of IPs or hostnames that may connect to the server port"},
{"allowusers",cf_slist,"","List of usernames who may execute requests from this server"},
{"auditing",cf_opts,CF_BOOL,"true/false activate auditing of server connections"},
{"bindtointerface",cf_str,"","IP of the interface to which the server should bind on multi-homed hosts"},
{"cfruncommand",cf_str,CF_ABSPATHRANGE,"Path to the cf-agent command or cf-execd wrapper for remote execution"},
{"denybadclocks",cf_opts,CF_BOOL,"true/false accept connections from hosts with clocks that are out of sync"},
{"denyconnects",cf_slist,"","List of IPs or hostnames that may NOT connect to the server port"},
{"dynamicaddresses",cf_slist,"","List of IPs or hostnames for which the IP/name binding is expected to change"},
{"hostnamekeys",cf_opts,CF_BOOL,"true/false store keys using hostname lookup instead of IP addresses"},
{"keycacheTTL",cf_int,CF_VALRANGE,"Maximum number of hours to hold public keys in the cache"},
{"logallconnections",cf_opts,CF_BOOL,"true/false causes the server to log all new connections to syslog"},
{"logencryptedtransfers",cf_opts,CF_BOOL,"true/false log all successful transfers required to be encrypted"},
{"maxconnections",cf_int,CF_VALRANGE,"Maximum number of connections that will be accepted by cf-serverd"},
{"port",cf_int,"1024,99999","Default port for cfengine server"},
{"serverfacility",cf_opts,CF_FACILITY,"Menu option for syslog facility level"},
{"skipverify",cf_slist,"","List of IPs or hostnames for which we expect no DNS binding and cannot verify"},
{"trustkeysfrom",cf_slist,"","List of IPs from whom we accept public keys on trust"},
{NULL,cf_notype,NULL,NULL}
};
struct BodySyntax CFM_CONTROLBODY[] =
{
{"forgetrate",cf_real,"0,1","Decimal fraction [0,1] weighting of new values over old in 2d-average computation"},
{"monitorfacility",cf_opts,CF_FACILITY,"Menu option for syslog facility"},
{"histograms",cf_opts,CF_BOOL,"Ignored, kept for backward compatibility"},
{"tcpdump",cf_opts,CF_BOOL,"true/false use tcpdump if found"},
{"tcpdumpcommand",cf_str,CF_ABSPATHRANGE,"Path to the tcpdump command on this system"},
{NULL,cf_notype,NULL,NULL}
};
struct BodySyntax CFR_CONTROLBODY[] =
{
{"hosts",cf_slist,"","List of host or IP addresses to attempt connection with"},
{"port",cf_int,"1024,99999","Default port for cfengine server"},
{"force_ipv4",cf_opts,CF_BOOL,"true/false force use of ipv4 in connection"},
{"trustkey",cf_opts,CF_BOOL,"true/false automatically accept all keys on trust from servers"},
{"encrypt",cf_opts,CF_BOOL,"true/false encrypt connections with servers"},
{"background_children",cf_opts,CF_BOOL,"true/false parallelize connections to servers"},
{"max_children",cf_int,CF_VALRANGE,"Maximum number of simultaneous connections to attempt"},
{"output_to_file",cf_opts,CF_BOOL,"true/false whether to send collected output to file(s)"},
{"output_directory",cf_str,CF_ABSPATHRANGE,"Directory where the output is stored"},
{"timeout",cf_int,"1,9999","Connection timeout, sec"},
{NULL,cf_notype,NULL,NULL}
};
struct BodySyntax CFEX_CONTROLBODY[] = /* enum cfexcontrol */
{
{"splaytime",cf_int,CF_VALRANGE,"Time in minutes to splay this host based on its name hash"},
{"mailfrom",cf_str,".*@.*","Email-address cfengine mail appears to come from"},
{"mailto",cf_str,".*@.*","Email-address cfengine mail is sent to"},
{"smtpserver",cf_str,".*","Name or IP of a willing smtp server for sending email"},
{"mailmaxlines",cf_int,"0,1000","Maximum number of lines of output to send by email"},
{"schedule",cf_slist,"","The class schedule used by cf-execd for activating cf-agent"},
{"executorfacility",cf_opts,CF_FACILITY,"Menu option for syslog facility level"},
{"exec_command",cf_str,CF_ABSPATHRANGE,"The full path and command to the executable run by default (overriding builtin)"},
{NULL,cf_notype,NULL,NULL}
};
struct BodySyntax CFK_CONTROLBODY[] =
{
{"build_directory",cf_str,".*","The directory in which to generate output files"},
{"document_root",cf_str,".*","The directory in which the web root resides"},
{"generate_manual",cf_opts,CF_BOOL,"true/false generate texinfo manual page skeleton for this version"},
{"graph_directory",cf_str,CF_ABSPATHRANGE,"Path to directory where rendered .png files will be created"},
{"graph_output",cf_opts,CF_BOOL,"true/false generate png visualization of topic map if possible (requires lib)"},
{"html_banner",cf_str,"","HTML code for a banner to be added to rendered in html after the header"},
{"html_footer",cf_str,"","HTML code for a page footer to be added to rendered in html before the end body tag"},
{"id_prefix",cf_str,".*","The LTM identifier prefix used to label topic maps (used for disambiguation in merging)"},
{"manual_source_directory",cf_str,CF_ABSPATHRANGE,"Path to directory where raw text about manual topics is found (defaults to build_directory)"},
{"query_engine",cf_str,"","Name of a dynamic web-page used to accept and drive queries in a browser"},
{"query_output",cf_opts,"html,text","Menu option for generated output format"},
{"sql_type",cf_opts,"mysql,postgres","Menu option for supported database type"},
{"sql_database",cf_str,"","Name of database used for the topic map"},
{"sql_owner",cf_str,"","User id of sql database user"},
{"sql_passwd",cf_str,"","Embedded password for accessing sql database"},
{"sql_server",cf_str,"","Name or IP of database server (or localhost)"},
{"sql_connection_db",cf_str,"","The name of an existing database to connect to in order to create/manage other databases"},
{"style_sheet",cf_str,"","Name of a style-sheet to be used in rendering html output (added to headers)"},
{"view_projections",cf_opts,CF_BOOL,"Perform view-projection analytics in graph generation"},
{NULL,cf_notype,NULL,NULL}
};
struct BodySyntax CFRE_CONTROLBODY[] = /* enum cfrecontrol */
{
{"aggregation_point",cf_str,CF_ABSPATHRANGE,"The root directory of the data cache for CMDB aggregation"},
{"auto_scaling",cf_opts,CF_BOOL,"true/false whether to auto-scale graph output to optimize use of space"},
{"build_directory",cf_str,".*","The directory in which to generate output files"},
{"csv2xml",cf_slist,"","A list of csv formatted files in the build directory to convert to simple xml"},
{"error_bars",cf_opts,CF_BOOL,"true/false whether to generate error bars on graph output"},
{"html_banner",cf_str,"","HTML code for a banner to be added to rendered in html after the header"},
{"html_embed",cf_opts,CF_BOOL,"If true, no header and footer tags will be added to html output"},
{"html_footer",cf_str,"","HTML code for a page footer to be added to rendered in html before the end body tag"},
{"query_engine",cf_str,"","Name of a dynamic web-page used to accept and drive queries in a browser"},
{"reports",cf_olist,"all,audit,performance,all_locks,active_locks,hashes,classes,last_seen,monitor_now,monitor_history,monitor_summary,compliance,setuid,file_changes,installed_software,software_patches,value,variables","A list of reports that may be generated"},
{"report_output",cf_opts,"csv,html,text,xml","Menu option for generated output format. Applies only to text reports, graph data remain in xydy format."},
{"style_sheet",cf_str,"","Name of a style-sheet to be used in rendering html output (added to headers)"},
{"time_stamps",cf_opts,CF_BOOL,"true/false whether to generate timestamps in the output directory name"},
{NULL,cf_notype,NULL,NULL}
};
struct BodySyntax CFH_CONTROLBODY[] = /* enum cfh_control */
{
{"export_zenoss",cf_opts,CF_BOOL,"Make data available for Zenoss integration in docroot/reports/summary.z"},
{"federation",cf_slist,"","The list of CFEngine servers supporting constellation integration with this hub"},
{"exclude_hosts",cf_slist,"","A list of IP addresses of hosts to exclude from report collection"},
{"hub_schedule",cf_slist,"","The class schedule used by cf-hub for report collation"},
{"port",cf_int,"1024,99999","Default port for contacting hub nodes"},
{NULL,cf_notype,NULL,NULL}
};
/*********************************************************/
/* This list is for checking free standing body lval => rval bindings */
struct SubTypeSyntax CF_ALL_BODIES[] =
{
{CF_COMMONC,"control",CFG_CONTROLBODY},
{CF_AGENTC,"control",CFA_CONTROLBODY},
{CF_SERVERC,"control",CFS_CONTROLBODY},
{CF_MONITORC,"control",CFM_CONTROLBODY},
{CF_RUNC,"control",CFR_CONTROLBODY},
{CF_EXECC,"control",CFEX_CONTROLBODY},
{CF_KNOWC,"control",CFK_CONTROLBODY},
{CF_REPORTC,"control",CFRE_CONTROLBODY},
{CF_HUBC,"control",CFH_CONTROLBODY},
// get others from modules e.g. "agent","files",CF_FILES_BODIES,
{NULL,NULL,NULL}
};
/*********************************************************/
/* */
/* Constraint values/types */
/* */
/*********************************************************/
/* This is where we place lval => rval bindings that
apply to more than one subtype, e.g. generic
processing behavioural details */
struct BodySyntax CF_COMMON_BODIES[] =
{
{CF_TRANSACTION,cf_body,CF_TRANSACTION_BODY,"Output behaviour"},
{CF_DEFINECLASSES,cf_body,CF_DEFINECLASS_BODY,"Signalling behaviour"},
{"ifvarclass",cf_str,"","Extended classes ANDed with context"},
{"handle",cf_str,CF_IDRANGE,"A unique id-tag string for referring to this as a promisee elsewhere"},
{"depends_on",cf_slist,"","A list of promise handles that this promise builds on or depends on somehow (for knowledge management)"},
{"comment",cf_str,"","A comment about this promise's real intention that follows through the program"},
{NULL,cf_notype,NULL,NULL}
};
/*********************************************************/
/* This is where we place promise subtypes that apply
to more than one type of bundle, e.g. agent,server.. */
struct SubTypeSyntax CF_COMMON_SUBTYPES[] =
{
{"*","vars",CF_VARBODY},
{"*","classes",CF_CLASSBODY},
{"*","reports",CF_REPORT_BODIES},
{"*","*",CF_COMMON_BODIES},
{NULL,NULL,NULL}
};
/*********************************************************/
/* THIS IS WHERE TO ATTACH SYNTAX MODULES */
/*********************************************************/
/* Read in all parsable Bundle definitions */
/* REMEMBER TO REGISTER THESE IN cf3.extern.h */
struct SubTypeSyntax *CF_ALL_SUBTYPES[CF3_MODULES] =
{
CF_COMMON_SUBTYPES, /* Add modules after this, mod_report.c is here */
CF_EXEC_SUBTYPES, /* mod_exec.c */
CF_DATABASES_SUBTYPES, /* mod_databases.c */
CF_ENVIRONMENT_SUBTYPES, /* mod_environ.c */
CF_FILES_SUBTYPES, /* mod_files.c */
CF_INTERFACES_SUBTYPES, /* mod_interfaces.c */
CF_METHOD_SUBTYPES, /* mod_methods.c */
CF_OUTPUTS_SUBTYPES, /* mod_outputs.c */
CF_PACKAGES_SUBTYPES, /* mod_packages.c */
CF_PROCESS_SUBTYPES, /* mod_process.c */
CF_SERVICES_SUBTYPES, /* mod_services.c */
CF_STORAGE_SUBTYPES, /* mod_storage.c */
CF_REMACCESS_SUBTYPES, /* mod_access.c */
CF_KNOWLEDGE_SUBTYPES, /* mod_knowledge.c */
CF_MEASUREMENT_SUBTYPES, /* mod_measurement.c */
/* update CF3_MODULES in cf3.defs.h */
};
cfengine-3.2.4/src/modes.c 0000644 0001750 0001750 00000017351 11715232734 012275 0000000 0000000 /*
Copyright (C) Cfengine AS
This file is part of Cfengine 3 - written and maintained by Cfengine 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 Commerical Open Source License
(COSL) may apply to this file if you as a licensee so wish it. See
included file COSL.txt.
*/
/*****************************************************************************/
/* */
/* Modestring toolkit */
/* */
/*****************************************************************************/
#include "cf3.defs.h"
#include "cf3.extern.h"
/***************************************************************/
static int CheckModeState (enum modestate stateA, enum modestate stateB,enum modesort modeA, enum modesort modeB, char ch);
static int SetModeMask (char action, int value, int affected, mode_t *p, mode_t *m);
/***************************************************************/
int ParseModeString(char *modestring,mode_t *plusmask,mode_t *minusmask)
{ char *sp;
int affected = 0, value = 0, gotaction, no_error = true;
char action = '=';
enum modestate state = unknown;
enum modesort found_sort = unknown; /* Already found "sort" of mode */
enum modesort sort = unknown; /* Sort of started but not yet finished mode */
*plusmask = *minusmask = 0;
if (modestring == NULL)
{
return true;
}
Debug("ParseModeString(%s)\n",modestring);
gotaction = false;
for (sp = modestring; true ; sp++)
{
switch (*sp)
{
case 'a': no_error = CheckModeState(who,state,symbolic,sort,*sp);
affected |= 07777;
sort = symbolic;
break;
case 'u': no_error = CheckModeState(who,state,symbolic,sort,*sp);
affected |= 04700;
sort = symbolic;
break;
case 'g': no_error = CheckModeState(who,state,symbolic,sort,*sp);
affected |= 02070;
sort = symbolic;
break;
case 'o': no_error = CheckModeState(who,state,symbolic,sort,*sp);
affected |= 00007;
sort = symbolic;
break;
case '+':
case '-':
case '=':
if (gotaction)
{
CfOut(cf_error,"","Too many +-= in mode string");
return false;
}
no_error = CheckModeState(who,state,symbolic,sort,*sp);
action = *sp;
state = which;
gotaction = true;
sort = unknown;
break;
case 'r': no_error = CheckModeState(which,state,symbolic,sort,*sp);
value |= 0444 & affected;
sort = symbolic;
break;
case 'w': no_error = CheckModeState(which,state,symbolic,sort,*sp);
value |= 0222 & affected;
sort = symbolic;
break;
case 'x': no_error = CheckModeState(which,state,symbolic,sort,*sp);
value |= 0111 & affected;
sort = symbolic;
break;
case 's': no_error = CheckModeState(which,state,symbolic,sort,*sp);
value |= 06000 & affected;
sort = symbolic;
break;
case 't': no_error = CheckModeState(which,state,symbolic,sort,*sp);
value |= 01000;
sort = symbolic;
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7': no_error = CheckModeState(which,state,numeric,sort,*sp);
sort = numeric;
gotaction = true;
state = which;
affected = 07777; /* TODO: Hard-coded; see below */
sscanf(sp,"%o",&value);
if (value > 07777) /* TODO: Hardcoded !
Is this correct for all sorts of Unix ?
What about NT ?
Any (POSIX)-constants ??
*/
{
CfOut(cf_error,"","Mode-Value too big : %s\n",modestring);
return false;
}
while (isdigit((int)*sp) && (*sp != '\0'))
{
sp++;
}
sp--;
break;
case ',':
if (!SetModeMask(action,value,affected,plusmask,minusmask))
{
return false;
}
if (found_sort != unknown && found_sort != sort)
{
CfOut(cf_inform,"","Symbolic and numeric form for modes mixed");
}
found_sort = sort;
sort = unknown;
action = '=';
affected = 0;
value = 0;
gotaction = false;
state = who;
break;
case '\0':
if (state == who || value == 0)
{
if (strcmp(modestring,"0000") != 0 && strcmp(modestring,"000") != 0)
{
CfOut(cf_error,"","mode string is incomplete");
return false;
}
}
if (!SetModeMask(action,value,affected,plusmask,minusmask))
{
return false;
}
if (found_sort != unknown && found_sort != sort)
{
CfOut(cf_inform,"","Symbolic and numeric form for modes mixed");
}
Debug1("[PLUS=%o][MINUS=%o]\n",*plusmask,*minusmask);
return true;
default:
CfOut(cf_error,"","Invalid mode string (%s)",modestring);
return false;
}
}
if (!no_error)
{
CfOut(cf_error,"","Error validating mode string %s\n",modestring);
}
return no_error;
}
/*********************************************************/
static int CheckModeState(enum modestate stateA,enum modestate stateB,enum modesort sortA,enum modesort sortB,char ch)
{
if ((stateA != wild) && (stateB != wild) && (stateA != stateB))
{
CfOut(cf_error,"","Mode string constant (%c) used out of context",ch);
return false;
}
if ((sortA != unknown) && (sortB != unknown) && (sortA != sortB))
{
CfOut(cf_error,"","Symbolic and numeric filemodes mixed within expression");
return false;
}
return true;
}
/*********************************************************/
static int SetModeMask(char action,int value,int affected,mode_t *p,mode_t *m)
{
Debug1("SetMask(%c%o,%o)\n",action,value,affected);
switch(action)
{
case '+':
*p |= value;
*m |= 0;
return true;
case '-':
*p |= 0;
*m |= value;
return true;
case '=':
*p |= value;
*m |= ((~value) & 07777 & affected);
return true;
default:
CfOut(cf_error,"","Mode directive %c is unknown",action);
return false;
}
}
cfengine-3.2.4/src/verify_exec.c 0000644 0001750 0001750 00000023511 11715232734 013471 0000000 0000000 /*
Copyright (C) Cfengine AS
This file is part of Cfengine 3 - written and maintained by Cfengine 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 Commerical Open Source License
(COSL) may apply to this file if you as a licensee so wish it. See
included file COSL.txt.
*/
/*****************************************************************************/
/* */
/* File: verify_exec.c */
/* */
/*****************************************************************************/
#include "cf3.defs.h"
#include "cf3.extern.h"
static int ExecSanityChecks(struct Attributes a,struct Promise *pp);
static void PreviewProtocolLine(char *line, char *comm);
static void VerifyExec(struct Attributes a, struct Promise *pp);
/*****************************************************************************/
void VerifyExecPromise(struct Promise *pp)
{ struct Attributes a = {{0}};
a = GetExecAttributes(pp);
ExecSanityChecks(a,pp);
VerifyExec(a,pp);
DeleteScalar("this","promiser");
}
/*****************************************************************************/
/* Level */
/*****************************************************************************/
static int ExecSanityChecks(struct Attributes a,struct Promise *pp)
{
if (a.contain.nooutput && a.contain.preview)
{
CfOut(cf_error,"","no_output and preview are mutually exclusive (broken promise)");
PromiseRef(cf_error,pp);
return false;
}
#ifdef MINGW
if(a.contain.umask != CF_UNDEFINED) // TODO: Always true (077 != -1?, compare positive and negative number), make false when umask not set
{
CfOut(cf_verbose, "", "contain.umask is ignored on Windows");
}
if(a.contain.owner != CF_UNDEFINED)
{
CfOut(cf_verbose, "", "contain.exec_owner is ignored on Windows");
}
if(a.contain.group != CF_UNDEFINED)
{
CfOut(cf_verbose, "", "contain.exec_group is ignored on Windows");
}
if(a.contain.chroot != NULL)
{
CfOut(cf_verbose, "", "contain.chroot is ignored on Windows");
}
#else /* NOT MINGW */
if (a.contain.umask == CF_UNDEFINED)
{
a.contain.umask = 077;
}
#endif /* NOT MINGW */
return true;
}
/*****************************************************************************/
static void VerifyExec(struct Attributes a, struct Promise *pp)
{ struct CfLock thislock;
char unsafeLine[CF_BUFSIZE], line[sizeof(unsafeLine)*2],eventname[CF_BUFSIZE];
char comm[20];
char execstr[CF_EXPANDSIZE];
struct timespec start;
int outsourced,count = 0;
mode_t maskval = 0;
FILE *pfp;
char cmdOutBuf[CF_BUFSIZE];
int cmdOutBufPos = 0;
int lineOutLen;
if (!IsExecutable(GetArg0(pp->promiser)))
{
cfPS(cf_error,CF_FAIL,"",pp,a,"%s promises to be executable but isn't\n",pp->promiser);
if (strchr(pp->promiser, ' '))
{
CfOut(cf_verbose, "", "Paths with spaces must be inside escaped quoutes (e.g. \\\"%s\\\")", pp->promiser);
}
return;
}
else
{
CfOut(cf_verbose,""," -> Promiser string contains a valid executable (%s) - ok\n",GetArg0(pp->promiser));
}
DeleteScalar("this","promiser");
NewScalar("this","promiser",pp->promiser,cf_str);
if (a.args)
{
snprintf(execstr,CF_EXPANDSIZE-1,"%s %s",pp->promiser,a.args);
}
else
{
strncpy(execstr,pp->promiser,CF_BUFSIZE);
}
thislock = AcquireLock(execstr,VUQNAME,CFSTARTTIME,a,pp,false);
if (thislock.lock == NULL)
{
return;
}
PromiseBanner(pp);
CfOut(cf_inform,""," -> Executing \'%s\' ...(timeout=%d,owner=%d,group=%d)\n",execstr,a.contain.timeout,a.contain.owner,a.contain.group);
start = BeginMeasure();
if (DONTDO && !a.contain.preview)
{
CfOut(cf_error,"","-> Would execute script %s\n",execstr);
}
else if(a.transaction.action != cfa_fix)
{
cfPS(cf_error,CF_WARN,"",pp,a," !! Command \"%s\" needs to be executed, but only warning was promised", execstr);
}
else
{
CommPrefix(execstr,comm);
if (a.transaction.background)
{
#ifdef MINGW
outsourced = true;
#else
CfOut(cf_verbose,""," -> Backgrounding job %s\n",execstr);
outsourced = fork();
#endif
}
else
{
outsourced = false;
}
if (outsourced || !a.transaction.background) // work done here: either by child or non-background parent
{
if (a.contain.timeout != CF_NOINT)
{
SetTimeOut(a.contain.timeout);
}
#ifndef MINGW
CfOut(cf_verbose,""," -> (Setting umask to %o)\n",a.contain.umask);
maskval = umask(a.contain.umask);
if (a.contain.umask == 0)
{
CfOut(cf_verbose,""," !! Programming %s running with umask 0! Use umask= to set\n",execstr);
}
#endif /* NOT MINGW */
if (a.contain.useshell)
{
pfp = cf_popen_shsetuid(execstr,"r",a.contain.owner,a.contain.group,a.contain.chdir,a.contain.chroot,a.transaction.background);
}
else
{
pfp = cf_popensetuid(execstr,"r",a.contain.owner,a.contain.group,a.contain.chdir,a.contain.chroot,a.transaction.background);
}
if (pfp == NULL)
{
cfPS(cf_error,CF_FAIL,"cf_popen",pp,a,"!! Couldn't open pipe to command %s\n",execstr);
YieldCurrentLock(thislock);
return;
}
while (!feof(pfp))
{
if (ferror(pfp)) /* abortable */
{
cfPS(cf_error,CF_TIMEX,"ferror",pp,a,"!! Command pipe %s\n",execstr);
cf_pclose(pfp);
YieldCurrentLock(thislock);
return;
}
CfReadLine(unsafeLine,CF_BUFSIZE-1,pfp);
ReplaceStr(unsafeLine,line,sizeof(line),"%","%%"); // escape format char
if (strstr(line,"cfengine-die"))
{
break;
}
if (ferror(pfp)) /* abortable */
{
cfPS(cf_error,CF_TIMEX,"ferror",pp,a,"!! Command pipe %s\n",execstr);
cf_pclose(pfp);
YieldCurrentLock(thislock);
return;
}
if (a.contain.preview)
{
PreviewProtocolLine(line,execstr);
}
if (a.module)
{
ModuleProtocol(execstr,line,!a.contain.nooutput);
}
else if (!a.contain.nooutput && NonEmptyLine(line))
{
lineOutLen = strlen(comm) + strlen(line) + 12;
// if buffer is to small for this line, output it directly
if(lineOutLen > sizeof(cmdOutBuf))
{
CfOut(cf_cmdout,"","Q: \"...%s\": %s\n",comm,line);
}
else
{
if(cmdOutBufPos + lineOutLen > sizeof(cmdOutBuf))
{
CfOut(cf_cmdout, "", "%s", cmdOutBuf);
cmdOutBufPos = 0;
}
sprintf(cmdOutBuf + cmdOutBufPos, "Q: \"...%s\": %s\n",comm, line);
cmdOutBufPos += (lineOutLen - 1);
}
count++;
}
}
#ifdef MINGW
if (outsourced) // only get return value if we waited for command execution
{
cf_pclose(pfp);
}
else
{
cf_pclose_def(pfp,a,pp);
}
#else /* NOT MINGW */
cf_pclose_def(pfp,a,pp);
#endif
}
if (count)
{
if (cmdOutBufPos)
{
CfOut(cf_cmdout, "", "%s", cmdOutBuf);
}
CfOut(cf_cmdout,"","I: Last %d quoted lines were generated by promiser \"%s\"\n",count,execstr);
}
if (a.contain.timeout != CF_NOINT)
{
alarm(0);
signal(SIGALRM,SIG_DFL);
}
CfOut(cf_inform,""," -> Completed execution of %s\n",execstr);
#ifndef MINGW
umask(maskval);
#endif
YieldCurrentLock(thislock);
snprintf(eventname,CF_BUFSIZE-1,"Exec(%s)",execstr);
#ifndef MINGW
if (a.transaction.background && outsourced)
{
CfOut(cf_verbose,""," -> Backgrounded command (%s) is done - exiting\n",execstr);
exit(0);
}
#endif /* NOT MINGW */
}
}
/*************************************************************/
/* Level */
/*************************************************************/
void PreviewProtocolLine(char *line, char *comm)
{ int i;
enum cfreport level = cf_error;
char *message = line;
/*
* Table matching cfoutputlevel enums to log prefixes.
*/
char *prefixes[] =
{
":silent:",
":inform:",
":verbose:",
":editverbose:",
":error:",
":logonly:",
};
int precount = sizeof(prefixes)/sizeof(char *);
if (line[0] == ':')
{
/*
* Line begins with colon - see if it matches a log prefix.
*/
for (i = 0; i < precount; i++)
{
int prelen = 0;
prelen = strlen(prefixes[i]);
if (strncmp(line, prefixes[i], prelen) == 0)
{
/*
* Found log prefix - set logging level, and remove the
* prefix from the log message.
*/
level = i;
message += prelen;
break;
}
}
}
CfOut(cf_verbose,"","%s (preview of %s)\n",message,comm);
}
cfengine-3.2.4/src/env_context.c 0000644 0001750 0001750 00000077100 11715232734 013520 0000000 0000000 /*
Copyright (C) Cfengine AS
This file is part of Cfengine 3 - written and maintained by Cfengine 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 Commerical Open Source License
(COSL) may apply to this file if you as a licensee so wish it. See
included file COSL.txt.
*/
/*****************************************************************************/
/* */
/* File: env_context.c */
/* */
/*****************************************************************************/
#include "cf3.defs.h"
#include "cf3.extern.h"
#include "logic_expressions.h"
static bool ValidClassName(const char *str);
static int GetORAtom(char *start,char *buffer);
static int HasBrackets(char *s,struct Promise *pp);
static int IsBracketed(char *s);
/*****************************************************************************/
/* Level */
/*****************************************************************************/
static int EvalClassExpression(struct Constraint *cp,struct Promise *pp)
{ int result_and = true;
int result_or = false;
int result_xor = 0;
int result = 0,total = 0;
char buffer[CF_MAXVARSIZE];
struct Rlist *rp;
double prob,cum = 0,fluct;
struct Rval newret;
struct FnCall *fp;
if (cp == NULL)
{
CfOut(cf_error,""," !! EvalClassExpression internal diagnostic discovered an ill-formed condition");
}
if (!IsDefinedClass(pp->classes))
{
return false;
}
if (pp->done)
{
return false;
}
if (IsDefinedClass(pp->promiser))
{
return false;
}
switch (cp->type)
{
case CF_FNCALL:
fp = (struct FnCall *)cp->rval; /* Special expansion of functions for control, best effort only */
newret = EvaluateFunctionCall(fp,pp);
DeleteFnCall(fp);
cp->rval = newret.item;
cp->type = newret.rtype;
break;
case CF_LIST:
for (rp = (struct Rlist *)cp->rval; rp != NULL; rp = rp->next)
{
newret = EvaluateFinalRval("this",rp->item,rp->type,true,pp);
DeleteRvalItem(rp->item,rp->type);
rp->item = newret.item;
rp->type = newret.rtype;
}
break;
default:
newret = ExpandPrivateRval("this",cp->rval,cp->type);
DeleteRvalItem(cp->rval,cp->type);
cp->rval = newret.item;
cp->type = newret.rtype;
break;
}
if (strcmp(cp->lval,"expression") == 0)
{
if (cp->type != CF_SCALAR)
{
return false;
}
if (IsDefinedClass((char *)cp->rval))
{
return true;
}
else
{
return false;
}
}
if (strcmp(cp->lval,"not") == 0)
{
if (cp->type != CF_SCALAR)
{
return false;
}
if (IsDefinedClass((char *)cp->rval))
{
return false;
}
else
{
return true;
}
}
// Class selection
if (strcmp(cp->lval,"select_class") == 0)
{
char splay[CF_MAXVARSIZE];
int i,n;
double hash;
total = 0;
for (rp = (struct Rlist *)cp->rval; rp != NULL; rp = rp->next)
{
total++;
}
if (total == 0)
{
CfOut(cf_error,""," !! No classes to select on RHS");
PromiseRef(cf_error,pp);
return false;
}
snprintf(splay,CF_MAXVARSIZE,"%s+%s+%d",VFQNAME,VIPADDRESS,getuid());
hash = (double)GetHash(splay);
n = (int)(total*hash/(double)CF_HASHTABLESIZE);
for (rp = (struct Rlist *)cp->rval,i = 0; rp != NULL; rp = rp->next,i++)
{
if (i == n)
{
NewClass(rp->item);
return true;
}
}
}
// Class distributions
if (strcmp(cp->lval,"dist") == 0)
{
for (rp = (struct Rlist *)cp->rval; rp != NULL; rp = rp->next)
{
result = Str2Int(rp->item);
if (result < 0)
{
CfOut(cf_error,""," !! Non-positive integer in class distribution");
PromiseRef(cf_error,pp);
return false;
}
total += result;
}
if (total == 0)
{
CfOut(cf_error,""," !! An empty distribution was specified on RHS");
PromiseRef(cf_error,pp);
return false;
}
}
fluct = drand48(); /* Get random number 0-1 */
cum = 0.0;
/* If we get here, anything remaining on the RHS must be a clist */
if (cp->type != CF_LIST)
{
CfOut(cf_error,""," !! RHS of promise body attribute \"%s\" is not a list\n",cp->lval);
PromiseRef(cf_error,pp);
return true;
}
for (rp = (struct Rlist *)cp->rval; rp != NULL; rp = rp->next)
{
if (rp->type != CF_SCALAR)
{
return false;
}
result = IsDefinedClass((char *)(rp->item));
result_and = result_and && result;
result_or = result_or || result;
result_xor ^= result;
if (total > 0) // dist class
{
prob = ((double)Str2Int(rp->item))/((double)total);
cum += prob;
if ((fluct < cum) || rp->next == NULL)
{
snprintf(buffer,CF_MAXVARSIZE-1,"%s_%s",pp->promiser,rp->item);
*(pp->donep) = true;
if (strcmp(pp->bundletype,"common") == 0)
{
NewClass(buffer);
}
else
{
NewBundleClass(buffer,pp->bundle);
}
Debug(" ?? \'Strategy\' distribution class interval -> %s\n",buffer);
return true;
}
}
}
// Class combinations
if (strcmp(cp->lval,"or") == 0)
{
return result_or;
}
if (strcmp(cp->lval,"xor") == 0)
{
return (result_xor == 1) ? true : false;
}
if (strcmp(cp->lval,"and") == 0)
{
return result_and;
}
return false;
}
/*******************************************************************/
void KeepClassContextPromise(struct Promise *pp)
{ struct Attributes a;
a = GetClassContextAttributes(pp);
if (!FullTextMatch("[a-zA-Z0-9_]+",pp->promiser))
{
CfOut(cf_verbose,"","Class identifier \"%s\" contains illegal characters - canonifying",pp->promiser);
snprintf(pp->promiser, strlen(pp->promiser) + 1, "%s", CanonifyName(pp->promiser));
}
if (a.context.broken)
{
cfPS(cf_error,CF_FAIL,"",pp,a,"Irreconcilable constraints in classes for %s (broken promise)",pp->promiser);
return;
}
if (strcmp(pp->bundletype,"common") == 0)
{
if (EvalClassExpression(a.context.expression,pp))
{
CfOut(cf_verbose,""," ?> defining additional global class %s\n",pp->promiser);
if (!ValidClassName(pp->promiser))
{
cfPS(cf_error,CF_FAIL,"",pp,a," !! Attempted to name a class \"%s\", which is an illegal class identifier",pp->promiser);
}
else
{
NewClass(pp->promiser);
}
}
/* These are global and loaded once */
//*(pp->donep) = true;
return;
}
if (strcmp(pp->bundletype,THIS_AGENT) == 0 || FullTextMatch("edit_.*",pp->bundletype))
{
if (EvalClassExpression(a.context.expression,pp))
{
Debug(" ?> defining explicit class %s\n",pp->promiser);
if (!ValidClassName(pp->promiser))
{
cfPS(cf_error,CF_FAIL,"",pp,a," !! Attempted to name a class \"%s\", which is an illegal class identifier",pp->promiser);
}
else
{
NewBundleClass(pp->promiser,pp->bundle);
}
}
// Private to bundle, can be reloaded
*(pp->donep) = false;
return;
}
}
/*******************************************************************/
void NewClass(const char *oclass)
{
struct Item *ip;
char class[CF_MAXVARSIZE];
strncpy(class, oclass, CF_MAXVARSIZE);
Chop(class);
CanonifyNameInPlace(class);
Debug("NewClass(%s)\n",class);
if (strlen(class) == 0)
{
return;
}
if (IsRegexItemIn(ABORTBUNDLEHEAP,class))
{
CfOut(cf_error,"","Bundle aborted on defined class \"%s\"\n",class);
ABORTBUNDLE = true;
}
if (IsRegexItemIn(ABORTHEAP,class))
{
CfOut(cf_error,"","cf-agent aborted on defined class \"%s\"\n",class);
exit(1);
}
if (InAlphaList(VHEAP,class))
{
return;
}
PrependAlphaList(&VHEAP,class);
for (ip = ABORTHEAP; ip != NULL; ip = ip->next)
{
if (IsDefinedClass(ip->name))
{
CfOut(cf_error,"","cf-agent aborted on defined class \"%s\" defined in bundle %s\n",class,THIS_BUNDLE);
exit(1);
}
}
if (!ABORTBUNDLE)
{
for (ip = ABORTBUNDLEHEAP; ip != NULL; ip = ip->next)
{
if (IsDefinedClass(ip->name))
{
CfOut(cf_error,""," -> Setting abort for \"%s\" when setting \"%s\"",ip->name,class);
ABORTBUNDLE = true;
break;
}
}
}
}
/*********************************************************************/
void DeleteClass(char *class)
{ int i = (int)*class;
DeleteItemLiteral(&(VHEAP.list[i]),class);
DeleteItemLiteral(&(VADDCLASSES.list[i]),class);
}
/*******************************************************************/
void NewBundleClass(char *class,char *bundle)
{ char copy[CF_BUFSIZE];
struct Item *ip;
memset(copy,0,CF_BUFSIZE);
strncpy(copy,class,CF_MAXVARSIZE);
Chop(copy);
if (strlen(copy) == 0)
{
return;
}
Debug("NewBundleClass(%s)\n",copy);
if (IsRegexItemIn(ABORTBUNDLEHEAP,copy))
{
CfOut(cf_error,"","Bundle %s aborted on defined class \"%s\"\n",bundle,copy);
ABORTBUNDLE = true;
}
if (IsRegexItemIn(ABORTHEAP,copy))
{
CfOut(cf_error,"","cf-agent aborted on defined class \"%s\" defined in bundle %s\n",copy,bundle);
exit(1);
}
if (InAlphaList(VHEAP,copy))
{
CfOut(cf_error,"","WARNING - private class \"%s\" in bundle \"%s\" shadows a global class - you should choose a different name to avoid conflicts",copy,bundle);
}
if (InAlphaList(VADDCLASSES,copy))
{
return;
}
PrependAlphaList(&VADDCLASSES,copy);
for (ip = ABORTHEAP; ip != NULL; ip = ip->next)
{
if (IsDefinedClass(ip->name))
{
CfOut(cf_error,"","cf-agent aborted on defined class \"%s\" defined in bundle %s\n",copy,bundle);
exit(1);
}
}
if (!ABORTBUNDLE)
{
for (ip = ABORTBUNDLEHEAP; ip != NULL; ip = ip->next)
{
if (IsDefinedClass(ip->name))
{
CfOut(cf_error,""," -> Setting abort for \"%s\" when setting \"%s\"",ip->name,class);
ABORTBUNDLE = true;
break;
}
}
}
}
/*********************************************************************/
struct Rlist *SplitContextExpression(char *context,struct Promise *pp)
{ struct Rlist *list = NULL;
char *sp,cbuff[CF_MAXVARSIZE];
if (context == NULL)
{
PrependRScalar(&list,"any",CF_SCALAR);
}
else
{
for (sp = context; *sp != '\0'; sp++)
{
while (*sp == '|')
{
sp++;
}
memset(cbuff,0,CF_MAXVARSIZE);
sp += GetORAtom(sp,cbuff);
if (strlen(cbuff) == 0)
{
break;
}
if (IsBracketed(cbuff))
{
// Fully bracketed atom (protected)
cbuff[strlen(cbuff)-1] = '\0';
PrependRScalar(&list,cbuff+1,CF_SCALAR);
}
else
{
if (HasBrackets(cbuff,pp))
{
struct Rlist *andlist = SplitRegexAsRList(cbuff,"[.&]+",99,false);
struct Rlist *rp,*orlist = NULL;
char buff[CF_MAXVARSIZE];
char orstring[CF_MAXVARSIZE] = {0};
char andstring[CF_MAXVARSIZE] = {0};
// Apply distribution P.(A|B) -> P.A|P.B
for (rp = andlist; rp != NULL; rp=rp->next)
{
if (IsBracketed(rp->item))
{
// This must be an OR string to be ORed and split into a list
*((char *)rp->item+strlen((char *)rp->item)-1) = '\0';
if (strlen(orstring) > 0)
{
strcat(orstring,"|");
}
Join(orstring,(char *)(rp->item)+1,CF_MAXVARSIZE);
}
else
{
if (strlen(andstring) > 0)
{
strcat(andstring,".");
}
Join(andstring,rp->item,CF_MAXVARSIZE);
}
// foreach ORlist, AND with AND string
}
if (strlen(orstring) > 0)
{
orlist = SplitRegexAsRList(orstring,"[|]+",99,false);
for (rp = orlist; rp != NULL; rp=rp->next)
{
snprintf(buff,CF_MAXVARSIZE,"%s.%s",rp->item,andstring);
PrependRScalar(&list,buff,CF_SCALAR);
}
}
else
{
PrependRScalar(&list,andstring,CF_SCALAR);
}
DeleteRlist(orlist);
DeleteRlist(andlist);
}
else
{
// Clean atom
PrependRScalar(&list,cbuff,CF_SCALAR);
}
}
if (*sp == '\0')
{
break;
}
}
}
return list;
}
/*********************************************************************/
static int IsBracketed(char *s)
/* return true if the entire string is bracketed, not just if
if contains brackets */
{ int i, level= 0, yes = 0;
if (*s != '(')
{
return false;
}
if (*(s+strlen(s)-1) != ')')
{
return false;
}
if (strstr(s,")("))
{
CfOut(cf_error,""," !! Class expression \"%s\" has broken brackets",s);
return false;
}
for (i = 0; i < strlen(s); i++)
{
if (s[i] == '(')
{
yes++;
level++;
if (i > 0 && !strchr(".&|!(", s[i-1]))
{
CfOut(cf_error,""," !! Class expression \"%s\" has a missing operator in front of '('",s);
}
}
if (s[i] == ')')
{
yes++;
level--;
if (i < strlen(s)-1 && !strchr(".&|!)", s[i+1]))
{
CfOut(cf_error,""," !! Class expression \"%s\" has a missing operator after of ')'",s);
}
}
}
if (level != 0)
{
CfOut(cf_error,""," !! Class expression \"%s\" has broken brackets",s);
return false; /* premature ) */
}
if (yes > 2)
{
// e.g. (a|b).c.(d|e)
return false;
}
return true;
}
/*********************************************************************/
static int GetORAtom(char *start,char *buffer)
{ char *sp = start;
char *spc = buffer;
int bracklevel = 0, len = 0;
while ((*sp != '\0') && !((*sp == '|') && (bracklevel == 0)))
{
if (*sp == '(')
{
Debug("+(\n");
bracklevel++;
}
if (*sp == ')')
{
Debug("-)\n");
bracklevel--;
}
Debug("(%c)",*sp);
*spc++ = *sp++;
len++;
}
*spc = '\0';
Debug("\nGetORATom(%s)->%s\n",start,buffer);
return len;
}
/*********************************************************************/
static int HasBrackets(char *s,struct Promise *pp)
/* return true if contains brackets */
{ int i, level= 0, yes = 0;
for (i = 0; i < strlen(s); i++)
{
if (s[i] == '(')
{
yes++;
level++;
if (i > 0 && !strchr(".&|!(", s[i+1]))
{
CfOut(cf_error,""," !! Class expression \"%s\" has a missing operator in front of '('",s);
}
}
if (s[i] == ')')
{
level--;
if (i < strlen(s)-1 && !strchr(".&|!)", s[i+1]))
{
CfOut(cf_error,""," !! Class expression \"%s\" has a missing operator after ')'",s);
}
}
}
if (level != 0)
{
CfOut(cf_error,""," !! Class expression \"%s\" has unbalanced brackets",s);
PromiseRef(cf_error,pp);
return true;
}
if (yes > 1)
{
CfOut(cf_error,""," !! Class expression \"%s\" has multiple brackets",s);
PromiseRef(cf_error,pp);
}
else if (yes)
{
return true;
}
return false;
}
/**********************************************************************/
/* Utilities */
/**********************************************************************/
/* Return expression with error position highlighted. Result is on the heap. */
static char *HighlightExpressionError(const char *str, int position)
{
char *errmsg = malloc(strlen(str) + 3);
char *firstpart = strndup(str, position);
char *secondpart = strndup(str + position, strlen(str) - position);
sprintf(errmsg, "%s->%s", firstpart, secondpart);
free(secondpart);
free(firstpart);
return errmsg;
}
/**********************************************************************/
/* Debugging output */
static void IndentL(int level)
{
int i;
if (level > 0)
{
putc('\n', stderr);
for(i = 0; i < level; ++i)
{
putc(' ', stderr);
}
}
}
/**********************************************************************/
static int IncIndent(int level, int inc)
{
if (level < 0)
{
return -level + inc;
}
else
{
return level + inc;
}
}
/**********************************************************************/
static void EmitStringExpression(StringExpression *e, int level)
{
if (!e)
{
return;
}
switch (e->op)
{
case CONCAT:
IndentL(level);
fputs("(concat ", stderr);
EmitStringExpression(e->val.concat.lhs, -IncIndent(level, 8));
EmitStringExpression(e->val.concat.rhs, IncIndent(level, 8));
fputs(")", stderr);
break;
case LITERAL:
IndentL(level);
fprintf(stderr, "\"%s\"", e->val.literal.literal);
break;
case VARREF:
IndentL(level);
fputs("($ ", stderr);
EmitStringExpression(e->val.varref.name, -IncIndent(level, 3));
break;
default:
FatalError("Unknown type of string expression: %d\n", e->op);
break;
}
}
/**********************************************************************/
static void EmitExpression(Expression *e, int level)
{
if (!e)
{
return;
}
switch (e->op)
{
case OR:
case AND:
IndentL(level);
fprintf(stderr, "(%s ", e->op == OR ? "|" : "&");
EmitExpression(e->val.andor.lhs, -IncIndent(level, 3));
EmitExpression(e->val.andor.rhs, IncIndent(level, 3));
fputs(")", stderr);
break;
case NOT:
IndentL(level);
fputs("(- ", stderr);
EmitExpression(e->val.not.arg, -IncIndent(level, 3));
fputs(")", stderr);
break;
case EVAL:
IndentL(level);
fputs("(eval ", stderr);
EmitStringExpression(e->val.eval.name, -IncIndent(level, 6));
fputs(")", stderr);
break;
default:
FatalError("Unknown logic expression type: %d\n", e->op);
}
}
/*****************************************************************************/
/* Syntax-checking and evaluating various expressions */
/*****************************************************************************/
static void EmitParserError(const char *str, int position)
{
char *errmsg = HighlightExpressionError(str, position);
yyerror(errmsg);
free(errmsg);
}
/**********************************************************************/
/* To be used from parser only (uses yyerror) */
void ValidateClassSyntax(const char *str)
{
ParseResult res = ParseExpression(str, 0, strlen(str));
if (DEBUG || D1 || D2)
{
EmitExpression(res.result, 0);
putc('\n', stderr);
}
if (res.result)
{
FreeExpression(res.result);
}
if (!res.result || res.position != strlen(str))
{
EmitParserError(str, res.position);
}
}
/**********************************************************************/
static bool ValidClassName(const char *str)
{
ParseResult res = ParseExpression(str, 0, strlen(str));
if (res.result)
{
FreeExpression(res.result);
}
return res.result && res.position == strlen(str);
}
/**********************************************************************/
static ExpressionValue EvalTokenAsClass(const char *classname, void *param)
{
if (IsItemIn(VNEGHEAP, classname))
{
return false;
}
if (IsItemIn(VDELCLASSES, classname))
{
return false;
}
if (InAlphaList(VHEAP, classname))
{
return true;
}
if (InAlphaList(VADDCLASSES, classname))
{
return true;
}
return false;
}
/**********************************************************************/
static char *EvalVarRef(const char *varname, void *param)
{
/*
* There should be no unexpanded variables when we evaluate any kind of
* logic expressions, until parsing of logic expression changes and they are
* not pre-expanded before evaluation.
*/
return NULL;
}
/**********************************************************************/
bool IsDefinedClass(const char *class)
{
ParseResult res;
if (!class)
{
return true;
}
res = ParseExpression(class, 0, strlen(class));
if (!res.result)
{
char *errexpr = HighlightExpressionError(class, res.position);
CfOut(cf_error,"","Unable to parse class expression: %s", errexpr);
free(errexpr);
return false;
}
else
{
ExpressionValue r = EvalExpression(res.result,
&EvalTokenAsClass, &EvalVarRef,
NULL);
FreeExpression(res.result);
Debug("Evaluate(%s) -> %d\n", class, r);
/* r is EvalResult which could be ERROR */
return r == true;
}
}
/**********************************************************************/
bool IsExcluded(const char *exception)
{
return !IsDefinedClass(exception);
}
/**********************************************************************/
static ExpressionValue EvalTokenFromList(const char *token, void *param)
{
return InAlphaList(*(struct AlphaList *)param, token);
}
/**********************************************************************/
static bool EvalWithTokenFromList(const char *expr, struct AlphaList *token_list)
{
ParseResult res = ParseExpression(expr, 0, strlen(expr));
if (!res.result)
{
char *errexpr = HighlightExpressionError(expr, res.position);
CfOut(cf_error, "", "Syntax error in expression: %s", errexpr);
free(errexpr);
return false; /* FIXME: return error */
}
else
{
ExpressionValue r = EvalExpression(res.result,
&EvalTokenFromList,
&EvalVarRef,
token_list);
FreeExpression(res.result);
/* r is EvalResult which could be ERROR */
return r == true;
}
}
/**********************************************************************/
/* Process result expression */
bool EvalProcessResult(const char *process_result, struct AlphaList *proc_attr)
{
return EvalWithTokenFromList(process_result, proc_attr);
}
/**********************************************************************/
/* File result expressions */
bool EvalFileResult(const char *file_result, struct AlphaList *leaf_attr)
{
return EvalWithTokenFromList(file_result, leaf_attr);
}
/*****************************************************************************/
void DeleteEntireHeap()
{
DeleteAlphaList(&VHEAP);
InitAlphaList(&VHEAP);
}
/*****************************************************************************/
void DeletePrivateClassContext()
{
DeleteAlphaList(&VADDCLASSES);
InitAlphaList(&VADDCLASSES);
DeleteItemList(VDELCLASSES);
VDELCLASSES = NULL;
}
/*****************************************************************************/
void PushPrivateClassContext()
{ struct AlphaList *ap = malloc(sizeof(struct AlphaList));
// copy to heap
PushStack(&PRIVCLASSHEAP,CopyAlphaListPointers(ap,&VADDCLASSES));
InitAlphaList(&VADDCLASSES);
}
/*****************************************************************************/
void PopPrivateClassContext()
{
struct AlphaList *ap;
DeleteAlphaList(&VADDCLASSES);
PopStack(&PRIVCLASSHEAP,(void *)&ap,sizeof(VADDCLASSES));
CopyAlphaListPointers(&VADDCLASSES,ap);
free(ap);
}
/*****************************************************************************/
void NewPersistentContext(char *name,unsigned int ttl_minutes,enum statepolicy policy)
{ int errno;
CF_DB *dbp;
struct CfState state;
time_t now = time(NULL);
char filename[CF_BUFSIZE];
snprintf(filename,CF_BUFSIZE,"%s/state/%s",CFWORKDIR,CF_STATEDB_FILE);
MapName(filename);
if (!OpenDB(filename,&dbp))
{
return;
}
cf_chmod(filename,0644);
if (ReadDB(dbp,name,&state,sizeof(state)))
{
if (state.policy == cfpreserve)
{
if (now < state.expires)
{
CfOut(cf_verbose,""," -> Persisent state %s is already in a preserved state -- %d minutes to go\n",name,(state.expires-now)/60);
CloseDB(dbp);
return;
}
}
}
else
{
CfOut(cf_verbose,""," -> New persistent state %s\n",name);
state.expires = now + ttl_minutes * 60;
state.policy = policy;
}
WriteDB(dbp,name,&state,sizeof(state));
CloseDB(dbp);
}
/*****************************************************************************/
void DeletePersistentContext(char *name)
{ int errno;
CF_DB *dbp;
char filename[CF_BUFSIZE];
snprintf(filename,CF_BUFSIZE,"%s/state/%s",CFWORKDIR,CF_STATEDB_FILE);
MapName(filename);
if (!OpenDB(filename,&dbp))
{
return;
}
cf_chmod(filename,0644);
DeleteDB(dbp,name);
Debug("Deleted any persistent state %s\n",name);
CloseDB(dbp);
}
/*****************************************************************************/
void LoadPersistentContext()
{ CF_DB *dbp;
CF_DBC *dbcp;
int ksize,vsize;
char *key;
void *value;
time_t now = time(NULL);
struct CfState q;
char filename[CF_BUFSIZE];
if (LOOKUP)
{
return;
}
Banner("Loading persistent classes");
snprintf(filename,CF_BUFSIZE,"%s/state/%s",CFWORKDIR,CF_STATEDB_FILE);
MapName(filename);
if (!OpenDB(filename,&dbp))
{
return;
}
/* Acquire a cursor for the database. */
if (!NewDBCursor(dbp,&dbcp))
{
CfOut(cf_inform,""," !! Unable to scan persistence cache");
return;
}
while(NextDB(dbp,dbcp,&key,&ksize,&value,&vsize))
{
memcpy((void *)&q,value,sizeof(struct CfState));
Debug(" - Found key %s...\n",key);
if (now > q.expires)
{
CfOut(cf_verbose,""," Persistent class %s expired\n",key);
DeleteDB(dbp,key);
}
else
{
CfOut(cf_verbose,""," Persistent class %s for %d more minutes\n",key,(q.expires-now)/60);
CfOut(cf_verbose,""," Adding persistent class %s to heap\n",key);
NewClass(key);
}
}
DeleteDBCursor(dbp,dbcp);
CloseDB(dbp);
Banner("Loaded persistent memory");
}
/*****************************************************************************/
void AddEphemeralClasses(struct Rlist *classlist)
{ struct Rlist *rp;
for (rp = classlist; rp != NULL; rp = rp->next)
{
if (!InAlphaList(VHEAP,rp->item))
{
NewClass(rp->item);
}
}
}
/*********************************************************************/
void NewClassesFromString(char *classlist)
{ char *sp, currentitem[CF_MAXVARSIZE],local[CF_MAXVARSIZE];
if ((classlist == NULL) || strlen(classlist) == 0)
{
return;
}
memset(local,0,CF_MAXVARSIZE);
strncpy(local,classlist,CF_MAXVARSIZE-1);
for (sp = local; *sp != '\0'; sp++)
{
memset(currentitem,0,CF_MAXVARSIZE);
sscanf(sp,"%250[^,]",currentitem);
sp += strlen(currentitem);
if (IsHardClass(currentitem))
{
FatalError("cfengine: You cannot use -D to define a reserved class!");
}
NewClass(currentitem);
}
}
/*********************************************************************/
void NegateClassesFromString(char *classlist,struct Item **heap)
{ char *sp, currentitem[CF_MAXVARSIZE],local[CF_MAXVARSIZE];
if ((classlist == NULL) || strlen(classlist) == 0)
{
return;
}
memset(local,0,CF_MAXVARSIZE);
strncpy(local,classlist,CF_MAXVARSIZE-1);
for (sp = local; *sp != '\0'; sp++)
{
memset(currentitem,0,CF_MAXVARSIZE);
sscanf(sp,"%250[^,]",currentitem);
sp += strlen(currentitem);
if (IsHardClass(currentitem))
{ char err[CF_BUFSIZE];
sprintf (err,"Cannot negate the reserved class [%s]\n",currentitem);
FatalError(err);
}
AppendItem(heap,currentitem,NULL);
}
}
/*********************************************************************/
void AddPrefixedClasses(char *name,char *classlist)
{ char *sp, currentitem[CF_MAXVARSIZE],local[CF_MAXVARSIZE],pref[CF_BUFSIZE];
if ((classlist == NULL) || strlen(classlist) == 0)
{
return;
}
memset(local,0,CF_MAXVARSIZE);
strncpy(local,classlist,CF_MAXVARSIZE-1);
for (sp = local; *sp != '\0'; sp++)
{
memset(currentitem,0,CF_MAXVARSIZE);
sscanf(sp,"%250[^.:,]",currentitem);
sp += strlen(currentitem);
pref[0] = '\0';
snprintf(pref,CF_BUFSIZE,"%s_%s",name,currentitem);
if (IsHardClass(pref))
{
FatalError("cfengine: You cannot use -D to define a reserved class!");
}
NewClass(pref);
}
}
/*********************************************************************/
int IsHardClass(char *sp) /* true if string matches a hardwired class e.g. hpux */
{ int i;
static char *names[] =
{
"any","agent","Morning","Afternoon","Evening","Night","Q1","Q2","Q3","Q4",
"SuSE","suse","fedora","Ubuntu","lsb_compliant","localhost",
NULL
};
static char *prefixes[] =
{
"cfengine_","ipv4",
NULL
};
for (i = 2; CLASSTEXT[i] != '\0'; i++)
{
if (strcmp(CLASSTEXT[i],sp) == 0)
{
return true;
}
}
for (i = 0; i < 7; i++)
{
if (strcmp(DAY_TEXT[i],sp)==0)
{
return true;
}
}
for (i = 0; i < 12; i++)
{
if (strncmp(MONTH_TEXT[i],sp,3) == 0)
{
return true;
}
}
for (i = 0; names[i] != NULL; i++)
{
if (strcmp(names[i],sp) == 0)
{
return true;
}
}
for (i = 0; prefixes[i] != NULL; i++)
{
if (strncmp(prefixes[i],sp,strlen(prefixes[i])) == 0)
{
return true;
}
}
if (strncmp(sp,"Min",3) == 0 && isdigit(*(sp+3)))
{
return true;
}
if (strncmp(sp,"Hr",2) == 0 && isdigit(*(sp+2)))
{
return true;
}
if (strncmp(sp,"Yr",2) == 0 && isdigit(*(sp+2)))
{
return true;
}
if (strncmp(sp,"Day",3) == 0 && isdigit(*(sp+3)))
{
return true;
}
if (strncmp(sp,"GMT",3) == 0 && *(sp+3) == '_')
{
return true;
}
if (strncmp(sp,"Lcycle",strlen("Lcycle")) == 0)
{
return true;
}
return(false);
}
/***************************************************************************/
int Abort()
{
if (ABORTBUNDLE)
{
ABORTBUNDLE = false;
return true;
}
return false;
}
/*****************************************************************************/
int VarClassExcluded(struct Promise *pp,char **classes)
{
*classes = (char *)GetConstraint("ifvarclass",pp,CF_SCALAR);
if (*classes == NULL)
{
return false;
}
if (strchr(*classes,'$') || strchr(*classes,'@'))
{
Debug("Class expression did not evaluate");
return true;
}
if (*classes && IsDefinedClass(*classes))
{
return false;
}
else
{
return true;
}
}
/*******************************************************************/
void SaveClassEnvironment()
{
char file[CF_BUFSIZE];
FILE *fp;
snprintf(file,CF_BUFSIZE,"%s/state/allclasses.txt",CFWORKDIR);
if ((fp = fopen(file,"w")) == NULL)
{
CfOut(cf_inform,"","Could not open allclasses cache file");
return;
}
ListAlphaList(fp,VHEAP,'\n');
ListAlphaList(fp,VADDCLASSES,'\n');
fclose(fp);
}
cfengine-3.2.4/src/mon_processes.c 0000644 0001750 0001750 00000006103 11715232734 014036 0000000 0000000 /*
Copyright (C) Cfengine AS
This file is part of Cfengine 3 - written and maintained by Cfengine 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 Commerical Open Source License
(COSL) may apply to this file if you as a licensee so wish it. See
included file COSL.txt.
*/
#include "cf3.defs.h"
#include "cf3.extern.h"
#include "monitoring.h"
/* Prototypes */
static int GatherProcessUsers(struct Item **userList, int *userListSz, int *numRootProcs, int *numOtherProcs);
static int Unix_GatherProcessUsers(struct Item **userList, int *userListSz, int *numRootProcs, int *numOtherProcs);
/* Implementation */
void MonProcessesGatherData(double *cf_this)
{
struct Item *userList = NULL;
char vbuff[CF_BUFSIZE];
int numProcUsers = 0;
int numRootProcs = 0;
int numOtherProcs = 0;
if (!GatherProcessUsers(&userList, &numProcUsers, &numRootProcs, &numOtherProcs))
{
return;
}
cf_this[ob_users] += numProcUsers;
cf_this[ob_rootprocs] += numRootProcs;
cf_this[ob_otherprocs] += numOtherProcs;
snprintf(vbuff,CF_MAXVARSIZE,"%s/state/cf_users",CFWORKDIR);
MapName(vbuff);
RawSaveItemList(userList,vbuff);
DeleteItemList(userList);
CfOut(cf_verbose,"","(Users,root,other) = (%d,%d,%d)\n",cf_this[ob_users],cf_this[ob_rootprocs],cf_this[ob_otherprocs]);
}
static int GatherProcessUsers(struct Item **userList, int *userListSz, int *numRootProcs, int *numOtherProcs)
{
#ifdef MINGW
return NovaWin_GatherProcessUsers(userList, userListSz, numRootProcs, numOtherProcs);
#else
return Unix_GatherProcessUsers(userList, userListSz, numRootProcs, numOtherProcs);
#endif
}
#ifndef MINGW
static int Unix_GatherProcessUsers(struct Item **userList, int *userListSz, int *numRootProcs, int *numOtherProcs)
{
FILE *pp;
char pscomm[CF_BUFSIZE];
char user[CF_MAXVARSIZE];
char vbuff[CF_BUFSIZE];
snprintf(pscomm,CF_BUFSIZE,"%s %s",VPSCOMM[VSYSTEMHARDCLASS],VPSOPTS[VSYSTEMHARDCLASS]);
if ((pp = cf_popen(pscomm,"r")) == NULL)
{
return false;
}
CfReadLine(vbuff,CF_BUFSIZE,pp);
while (!feof(pp))
{
CfReadLine(vbuff,CF_BUFSIZE,pp);
sscanf(vbuff,"%s",user);
if (strcmp(user,"USER") == 0)
{
continue;
}
if (!IsItemIn(*userList,user))
{
PrependItem(userList,user,NULL);
(*userListSz)++;
}
if (strcmp(user,"root") == 0)
{
(*numRootProcs)++;
}
else
{
(*numOtherProcs)++;
}
}
cf_pclose(pp);
return true;
}
#endif
cfengine-3.2.4/src/mod_interfaces.c 0000644 0001750 0001750 00000004662 11715232734 014151 0000000 0000000 /*
Copyright (C) Cfengine AS
This file is part of Cfengine 3 - written and maintained by Cfengine 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 Commerical Open Source License
(COSL) may apply to this file if you as a licensee so wish it. See
included file COSL.txt.
*/
/*****************************************************************************/
/* */
/* File: mod_interfaces.c */
/* */
/*****************************************************************************/
#include "cf3.defs.h"
#include "cf3.extern.h"
/*****************************************************************************/
#define CF3_MOD_INTEFACES
struct BodySyntax CF_TCPIP_BODY[] =
{
{"ipv4_address",cf_str,"[0-9.]+/[0-4]+","IPv4 address for the interface"},
{"ipv4_netmask",cf_str,"[0-9.]+/[0-4]+","Netmask for the interface"},
{"ipv6_address",cf_str,"[0-9a-fA-F:]+/[0-9]+","IPv6 address for the interface"},
{NULL,cf_notype,NULL,NULL}
};
/***************************************************************/
/* This is the primary set of constraints for an interfaces object */
struct BodySyntax CF_INTERFACES_BODIES[] =
{
{"tcp_ip",cf_body,CF_TCPIP_BODY,"Interface tcp/ip properties"},
{NULL,cf_notype,NULL,NULL}
};
/***************************************************************/
/* This is the point of entry from mod_common.c */
/***************************************************************/
struct SubTypeSyntax CF_INTERFACES_SUBTYPES[] =
{
{"agent","interfaces",CF_INTERFACES_BODIES},
{NULL,NULL,NULL},
};
cfengine-3.2.4/src/iteration.c 0000644 0001750 0001750 00000015505 11715232734 013163 0000000 0000000 /*
Copyright (C) Cfengine AS
This file is part of Cfengine 3 - written and maintained by Cfengine 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 Commerical Open Source License
(COSL) may apply to this file if you as a licensee so wish it. See
included file COSL.txt.
*/
/*****************************************************************************/
/* */
/* File: iteration.c */
/* */
/*****************************************************************************/
#include "cf3.defs.h"
#include "cf3.extern.h"
static void DeleteReferenceRlist(struct Rlist *list);
/*****************************************************************************/
struct Rlist *NewIterationContext(char *scopeid,struct Rlist *namelist)
{ struct Rlist *this,*rp,*rps,*deref_listoflists = NULL;
char rtype;
void *returnval;
enum cfdatatype dtype;
struct Scope *ptr = NULL;
struct CfAssoc *new;
struct Rval newret;
Debug("\n*\nNewIterationContext(from %s)\n*\n",scopeid);
CopyScope("this",scopeid);
ptr=GetScope("this");
if (namelist == NULL)
{
Debug("No lists to iterate over\n");
return NULL;
}
for (rp = namelist; rp != NULL; rp = rp->next)
{
dtype = GetVariable(scopeid,rp->item,&returnval,&rtype);
if (dtype == cf_notype)
{
CfOut(cf_error,""," !! Couldn't locate variable %s apparently in %s\n",rp->item,scopeid);
CfOut(cf_error,""," !! Could be incorrect use of a global iterator -- see reference manual on list substitution");
continue;
}
/* Make a copy of list references in scope only, without the names */
if (rtype == CF_LIST)
{
for (rps = (struct Rlist *)returnval; rps != NULL; rps=rps->next)
{
if (rps->type == CF_FNCALL)
{
struct FnCall *fp = (struct FnCall *)rps->item;
newret = EvaluateFunctionCall(fp,NULL);
DeleteFnCall(fp);
rps->item = newret.item;
rps->type = newret.rtype;
}
}
}
if ((new = NewAssoc(rp->item,returnval,rtype,dtype)))
{
this = OrthogAppendRlist(&deref_listoflists,new,CF_LIST);
rp->state_ptr = new->rval;
while (rp->state_ptr && strcmp(rp->state_ptr->item,CF_NULL_VALUE) == 0)
{
if (rp->state_ptr)
{
rp->state_ptr = rp->state_ptr->next;
}
}
}
}
/* We now have a control list of list-variables, with internal state in state_ptr */
return deref_listoflists;
}
/*****************************************************************************/
void DeleteIterationContext(struct Rlist *deref)
{
DeleteScope("this");
if (deref != NULL)
{
DeleteReferenceRlist(deref);
}
}
/*****************************************************************************/
int IncrementIterationContext(struct Rlist *iterator,int level)
{ struct Rlist *state;
struct CfAssoc *cp;
if (iterator == NULL)
{
return false;
}
// iterator->next points to the next list
// iterator->state_ptr points to the current item in the current list
cp = (struct CfAssoc *)iterator->item;
state = iterator->state_ptr;
if (state == NULL)
{
return false;
}
/* Go ahead and increment */
Debug(" -> Incrementing (%s) from \"%s\"\n", cp->lval, (char *)iterator->state_ptr->item);
if (state->next == NULL)
{
/* This wheel has come to full revolution, so move to next */
if (iterator->next != NULL)
{
/* Increment next wheel */
if (IncrementIterationContext(iterator->next,level+1))
{
/* Not at end yet, so reset this wheel */
iterator->state_ptr = cp->rval;
iterator->state_ptr = iterator->state_ptr->next;
return true;
}
else
{
/* Reached last variable wheel - pass up */
return false;
}
}
else
{
/* Reached last variable wheel - waiting for end detection */
return false;
}
}
else
{
/* Update the current wheel */
iterator->state_ptr = state->next;
Debug(" <- Incrementing wheel (%s) to \"%s\"\n",cp->lval,iterator->state_ptr->item);
while (iterator->state_ptr && strcmp(iterator->state_ptr->item,CF_NULL_VALUE) == 0)
{
if (IncrementIterationContext(iterator->next,level+1))
{
/* Not at end yet, so reset this wheel (next because we always start with cf_null now) */
iterator->state_ptr = cp->rval;
iterator->state_ptr = iterator->state_ptr->next;
return true;
}
else
{
/* Reached last variable wheel - pass up */
break;
}
}
if (EndOfIteration(iterator))
{
return false;
}
return true;
}
}
/*****************************************************************************/
int EndOfIteration(struct Rlist *iterator)
{ struct Rlist *rp,*state;
if (iterator == NULL)
{
return true;
}
/* When all the wheels are at NULL, we have reached the end*/
for (rp = iterator; rp != NULL; rp = rp->next)
{
state = rp->state_ptr;
if (state == NULL)
{
continue;
}
if (state && state->next != NULL)
{
return false;
}
}
return true;
}
/*****************************************************************************/
int NullIterators(struct Rlist *iterator)
{ struct Rlist *rp,*state;
if (iterator == NULL)
{
return false;
}
/* When all the wheels are at NULL, we have reached the end*/
for (rp = iterator; rp != NULL; rp = rp->next)
{
state = rp->state_ptr;
if (state && strcmp(state->item,CF_NULL_VALUE) == 0)
{
return true;
}
}
return false;
}
/*******************************************************************/
static void DeleteReferenceRlist(struct Rlist *list)
/* Delete all contents, hash table in scope has own copy */
{
if (list == NULL)
{
return;
}
DeleteAssoc((struct CfAssoc *)list->item);
DeleteReferenceRlist(list->next);
free((char *)list);
}
cfengine-3.2.4/src/conf.h.in 0000644 0001750 0001750 00000037334 11715232774 012534 0000000 0000000 /* src/conf.h.in. Generated from configure.ac by autoheader. */
/* AIX build */
#undef AIX
/* AOS build */
#undef AOS
/* Special Cfengine symbol */
#undef AUTOCONF_HOSTNAME
/* Speial Cfengine symbol */
#undef AUTOCONF_SYSNAME
/* 4.3BSD build */
#undef BSD43
/* BSD/OS build */
#undef BSDOS
/* Build Test suite */
#undef BUILD_TESTSUITE
/* "Software build year" */
#undef BUILD_YEAR
/* Cray build */
#undef CFCRAY
/* Cygwin NT build */
#undef CFCYG
/* GNU build */
#undef CFGNU
/* QNX build */
#undef CFQNX
/* Define if old Berkeley API */
#undef CF_OLD_DB
/* Define to 1 if using `getloadavg.c'. */
#undef C_GETLOADAVG
/* Darwin build */
#undef DARWIN
/* Define to 1 for DGUX with . */
#undef DGUX
/* FreeBSD build */
#undef FREEBSD
/* Define to 1 if the `getloadavg' function needs to be run setuid or setgid.
*/
#undef GETLOADAVG_PRIVILEGED
/* Define to 1 if you have the header file. */
#undef HAVE_ACL_H
/* Define to 1 if you have the header file. */
#undef HAVE_ACL_LIBACL_H
/* Define to 1 if you have the `bcopy' function. */
#undef HAVE_BCOPY
/* Define to 1 if you have the `chflags' function. */
#undef HAVE_CHFLAGS
/* Define to 1 if the system has the type `clockid_t'. */
#undef HAVE_CLOCKID_T
/* Define to 1 if you have the `clock_gettime' function. */
#undef HAVE_CLOCK_GETTIME
/* Define to 1 if you have the declaration of `clock_gettime', and to 0 if you
don't. */
#undef HAVE_DECL_CLOCK_GETTIME
/* Define to 1 if you have the declaration of `dirfd', and to 0 if you don't.
*/
#undef HAVE_DECL_DIRFD
/* Define to 1 if you have the declaration of `nanosleep', and to 0 if you
don't. */
#undef HAVE_DECL_NANOSLEEP
/* Define to 1 if you have the declaration of `realpath', and to 0 if you
don't. */
#undef HAVE_DECL_REALPATH
/* Define to 1 if you have the declaration of `round', and to 0 if you don't.
*/
#undef HAVE_DECL_ROUND
/* Define to 1 if you have the declaration of `setlinebuf', and to 0 if you
don't. */
#undef HAVE_DECL_SETLINEBUF
/* Define to 1 if you have the declaration of `strdup', and to 0 if you don't.
*/
#undef HAVE_DECL_STRDUP
/* Define to 1 if you have the declaration of `strlcat', and to 0 if you
don't. */
#undef HAVE_DECL_STRLCAT
/* Define to 1 if you have the declaration of `strlcpy', and to 0 if you
don't. */
#undef HAVE_DECL_STRLCPY
/* Define to 1 if you have the declaration of `strndup', and to 0 if you
don't. */
#undef HAVE_DECL_STRNDUP
/* Define to 1 if you have the declaration of `strnlen', and to 0 if you
don't. */
#undef HAVE_DECL_STRNLEN
/* Define to 1 if you have the declaration of `unsetenv', and to 0 if you
don't. */
#undef HAVE_DECL_UNSETENV
/* Define to 1 if you have the header file. */
#undef HAVE_DEPOT_H
/* Define to 1 if you have the header file, and it defines `DIR'.
*/
#undef HAVE_DIRENT_H
/* Define to 1 if you have the `dirfd' function. */
#undef HAVE_DIRFD
/* Define to 1 if you have the header file. */
#undef HAVE_DLFCN_H
/* Define to 1 if you have the `door' function. */
#undef HAVE_DOOR
/* Define to 1 if you have the `drand48' function. */
#undef HAVE_DRAND48
/* Define to 1 if you have the header file. */
#undef HAVE_DUSTAT_H
/* Define to 1 if you have the header file. */
#undef HAVE_FCNTL_H
/* Define to 1 if you have the `fpathconf' function. */
#undef HAVE_FPATHCONF
/* Define to 1 if you have the `getaddrinfo' function. */
#undef HAVE_GETADDRINFO
/* Define to 1 if you have the `getcwd' function. */
#undef HAVE_GETCWD
/* Define to 1 if you have the `gethostname' function. */
#undef HAVE_GETHOSTNAME
/* Define to 1 if you have the `getloadavg' function. */
#undef HAVE_GETLOADAVG
/* Define to 1 if you have the `getnetgrent' function. */
#undef HAVE_GETNETGRENT
/* Define to 1 if you have the `getzoneid' function. */
#undef HAVE_GETZONEID
/* Define to 1 if you have the `getzonenamebyid' function. */
#undef HAVE_GETZONENAMEBYID
/* Define to 1 if you have the header file. */
#undef HAVE_INTTYPES_H
/* Define to 1 if you have the `jail_get' function. */
#undef HAVE_JAIL_GET
/* Whether to use lchown(3) to change ownerships */
#undef HAVE_LCHOWN
/* Define to 1 if you have the `acl' library (-lacl). */
#undef HAVE_LIBACL
/* Define to 1 if you have the `crypto' library (-lcrypto). */
#undef HAVE_LIBCRYPTO
/* Define to 1 if you have the `db' library (-ldb). */
#undef HAVE_LIBDB
/* Define to 1 if you have the `dgc' library (-ldgc). */
#undef HAVE_LIBDGC
/* Define to 1 if you have the `kstat' library (-lkstat). */
#undef HAVE_LIBKSTAT
/* Define to 1 if you have the `m' library (-lm). */
#undef HAVE_LIBM
/* Define to 1 if you have the `mysqlclient' library (-lmysqlclient). */
#undef HAVE_LIBMYSQLCLIENT
/* Define to 1 if you have the `nsl' library (-lnsl). */
#undef HAVE_LIBNSL
/* Define to 1 if you have the `nss_nis' library (-lnss_nis). */
#undef HAVE_LIBNSS_NIS
/* Define to 1 if you have the `pcre' library (-lpcre). */
#undef HAVE_LIBPCRE
/* Define to 1 if you have the `pq' library (-lpq). */
#undef HAVE_LIBPQ
/* Define to 1 if you have the header file. */
#undef HAVE_LIBPQ_FE_H
/* Define to 1 if you have the `pthread' library (-lpthread). */
#undef HAVE_LIBPTHREAD
/* Define to 1 if you have the `pthreads' library (-lpthreads). */
#undef HAVE_LIBPTHREADS
/* Define to 1 if you have the `PW' library (-lPW). */
#undef HAVE_LIBPW
/* Define to 1 if you have the `qdbm' library (-lqdbm). */
#undef HAVE_LIBQDBM
/* Define to 1 if you have the `rt' library (-lrt). */
#undef HAVE_LIBRT
/* Define to 1 if you have the `socket' library (-lsocket). */
#undef HAVE_LIBSOCKET
/* Define to 1 if you have the `sqlite3' library (-lsqlite3). */
#undef HAVE_LIBSQLITE3
/* Define to 1 if you have the `thread' library (-lthread). */
#undef HAVE_LIBTHREAD
/* Define to 1 if you have the `tokyocabinet' library (-ltokyocabinet). */
#undef HAVE_LIBTOKYOCABINET
/* Define to 1 if you have the header file. */
#undef HAVE_MACH_MACH_H
/* Define to 1 if you have the header file. */
#undef HAVE_MALLOC_H
/* Define to 1 if you have the header file. */
#undef HAVE_MEMORY_H
/* Define to 1 if you have the `mkfifo' function. */
#undef HAVE_MKFIFO
/* Define to 1 if you have the header file. */
#undef HAVE_MYSQL_H
/* Define to 1 if you have the `nanosleep' function. */
#undef HAVE_NANOSLEEP
/* Define to 1 if you have the header file, and it defines `DIR'. */
#undef HAVE_NDIR_H
/* Define to 1 if you have the header file. */
#undef HAVE_NLIST_H
/* Define to 1 if you have the header file. */
#undef HAVE_OPENSSL_OPENSSLV_H
/* The old route entry structure in newer BSDs */
#undef HAVE_ORTENTRY
/* Define to 1 if you have the header file. */
#undef HAVE_PCRE_H
/* Define to 1 if you have the header file. */
#undef HAVE_PCRE_PCRE_H
/* Define to 1 if you have the `pstat_getdynamic' function. */
#undef HAVE_PSTAT_GETDYNAMIC
/* Define if you have POSIX threads libraries and header files. */
#undef HAVE_PTHREAD
/* Whether the thread library has setstacksize */
#undef HAVE_PTHREAD_ATTR_SETSTACKSIZE
/* Define to 1 if you have the header file. */
#undef HAVE_PTHREAD_H
/* Whether the thread library has setmask */
#undef HAVE_PTHREAD_SIGMASK
/* Define to 1 if you have the `putenv' function. */
#undef HAVE_PUTENV
/* Define to 1 if you have the `realpath' function. */
#undef HAVE_REALPATH
/* Define to 1 if you have the `round' function. */
#undef HAVE_ROUND
/* Do we have any route entry structure? */
#undef HAVE_RTENTRY
/* Define to 1 if you have the header file. */
#undef HAVE_SCHED_H
/* Define to 1 if you have the `setegid' function. */
#undef HAVE_SETEGID
/* Define to 1 if you have the `seteuid' function. */
#undef HAVE_SETEUID
/* Define to 1 if you have the `setlinebuf' function. */
#undef HAVE_SETLINEBUF
/* Define to 1 if you have the `setlocale' function. */
#undef HAVE_SETLOCALE
/* Define to 1 if you have the `setregid' function. */
#undef HAVE_SETREGID
/* Define to 1 if you have the `setreuid' function. */
#undef HAVE_SETREUID
/* Define to 1 if you have the `setsid' function. */
#undef HAVE_SETSID
/* Define to 1 if you have the `snprintf' function. */
#undef HAVE_SNPRINTF
/* Define to 1 if you have the header file. */
#undef HAVE_SQLITE3_H
/* Define to 1 if you have the `srand48' function. */
#undef HAVE_SRAND48
/* Define to 1 if you have the `statfs' function. */
#undef HAVE_STATFS
/* Define to 1 if you have the `statvfs' function. */
#undef HAVE_STATVFS
/* Define to 1 if stdbool.h conforms to C99. */
#undef HAVE_STDBOOL_H
/* Define to 1 if you have the header file. */
#undef HAVE_STDINT_H
/* Define to 1 if you have the header file. */
#undef HAVE_STDLIB_H
/* Define to 1 if you have the `strdup' function. */
#undef HAVE_STRDUP
/* Define to 1 if you have the `strerror' function. */
#undef HAVE_STRERROR
/* Define to 1 if you have the header file. */
#undef HAVE_STRINGS_H
/* Define to 1 if you have the header file. */
#undef HAVE_STRING_H
/* Define to 1 if you have the `strlcat' function. */
#undef HAVE_STRLCAT
/* Define to 1 if you have the `strlcpy' function. */
#undef HAVE_STRLCPY
/* Define to 1 if you have the `strndup' function. */
#undef HAVE_STRNDUP
/* Define to 1 if you have the `strnlen' function. */
#undef HAVE_STRNLEN
/* Define to 1 if you have the `strrchr' function. */
#undef HAVE_STRRCHR
/* Define to 1 if you have the `strsep' function. */
#undef HAVE_STRSEP
/* Define to 1 if you have the `strstr' function. */
#undef HAVE_STRSTR
/* Define to 1 if `n_un.n_name' is a member of `struct nlist'. */
#undef HAVE_STRUCT_NLIST_N_UN_N_NAME
/* Define to 1 if `sa_len' is a member of `struct sockaddr'. */
#undef HAVE_STRUCT_SOCKADDR_SA_LEN
/* Define to 1 if you have the `sysconf' function. */
#undef HAVE_SYSCONF
/* Define to 1 if you have the `sysinfo' function. */
#undef HAVE_SYSINFO
/* Define to 1 if you have the header file. */
#undef HAVE_SYS_ACL_H
/* Define to 1 if you have the header file, and it defines `DIR'.
*/
#undef HAVE_SYS_DIR_H
/* Define to 1 if you have the header file. */
#undef HAVE_SYS_FILESYS_H
/* Define to 1 if you have the header file. */
#undef HAVE_SYS_LOADAVG_H
/* Define to 1 if you have the header file. */
#undef HAVE_SYS_MALLOC_H
/* Define to 1 if you have the header file. */
#undef HAVE_SYS_MOUNT_H
/* Define to 1 if you have the header file, and it defines `DIR'.
*/
#undef HAVE_SYS_NDIR_H
/* Define to 1 if you have the header file. */
#undef HAVE_SYS_PARAM_H
/* Define to 1 if you have the header file. */
#undef HAVE_SYS_SOCKIO_H
/* Define to 1 if you have the header file. */
#undef HAVE_SYS_STATFS_H
/* Define to 1 if you have the header file. */
#undef HAVE_SYS_STATVFS_H
/* Define to 1 if you have the header file. */
#undef HAVE_SYS_STAT_H
/* Define to 1 if you have the header file. */
#undef HAVE_SYS_SYSTEMINFO_H
/* Define to 1 if you have the header file. */
#undef HAVE_SYS_TIME_H
/* Define to 1 if you have the header file. */
#undef HAVE_SYS_TYPES_H
/* Define to 1 if you have the header file. */
#undef HAVE_SYS_UIO_H
/* Define to 1 if you have the header file. */
#undef HAVE_SYS_VFS_H
/* Define to 1 if you have that is POSIX.1 compatible. */
#undef HAVE_SYS_WAIT_H
/* Define to 1 if you have the header file. */
#undef HAVE_TCHDB_H
/* Define to 1 if you have the header file. */
#undef HAVE_TCUTIL_H
/* Define to 1 if you have the header file. */
#undef HAVE_THREAD_H
/* Define to 1 if you have the header file. */
#undef HAVE_TIME_H
/* Define to 1 if you have the `uname' function. */
#undef HAVE_UNAME
/* Define to 1 if you have the header file. */
#undef HAVE_UNISTD_H
/* Define to 1 if you have the `unsetenv' function. */
#undef HAVE_UNSETENV
/* Define to 1 if you have the header file. */
#undef HAVE_UTIME_H
/* Define to 1 if you have the header file. */
#undef HAVE_VFS_H
/* Define to 1 if you have the `waitpid' function. */
#undef HAVE_WAITPID
/* Define to 1 if you have the header file. */
#undef HAVE_WINSOCK2_H
/* Define to 1 if you have the header file. */
#undef HAVE_ZONE_H
/* Define to 1 if the system has the type `_Bool'. */
#undef HAVE__BOOL
/* HP/UX build */
#undef HPuUX
/* IRIX build */
#undef IRIX
/* Linux build */
#undef LINUX
/* Define to the sub-directory in which libtool stores uninstalled libraries.
*/
#undef LT_OBJDIR
/* Native NT build */
#undef MINGW
/* NetBSD build */
#undef NETBSD
/* NewsOS build */
#undef NEWS_OS
/* NeXTSTEP build */
#undef NEXTSTEP
/* Define to 1 if your `struct nlist' has an `n_un' member. Obsolete, depend
on `HAVE_STRUCT_NLIST_N_UN_N_NAME */
#undef NLIST_NAME_UNION
/* NT build */
#undef NT
/* OpenBSD build */
#undef OPENBSD
/* OSF/1 build */
#undef OSF
/* Name of package */
#undef PACKAGE
/* Define to the address where bug reports for this package should be sent. */
#undef PACKAGE_BUGREPORT
/* Define to the full name of this package. */
#undef PACKAGE_NAME
/* Define to the full name and version of this package. */
#undef PACKAGE_STRING
/* Define to the one symbol short name of this package. */
#undef PACKAGE_TARNAME
/* Define to the home page for this package. */
#undef PACKAGE_URL
/* Define to the version of this package. */
#undef PACKAGE_VERSION
/* Define to necessary symbol if this constant uses a non-standard name on
your system. */
#undef PTHREAD_CREATE_JOINABLE
/* Define if QDBM is available. */
#undef QDB
/* Whether to use the local regex functions */
#undef REGEX_MALLOC
/* SCO build */
#undef SCO
/* Solaris build */
#undef SOLARIS
/* Define if SQLite 3 is available. */
#undef SQLITE3
/* Define to 1 if you have the ANSI C header files. */
#undef STDC_HEADERS
/* SunOS 3.x build */
#undef SUN3
/* SunOS 4.x build */
#undef SUN4
/* Define to 1 on System V Release 4. */
#undef SVR4
/* Define if Tokyo Cabinet is available. */
#undef TCDB
/* Define to 1 if you can safely include both and . */
#undef TIME_WITH_SYS_TIME
/* Ultrix build */
#undef ULTRIX
/* Define to 1 for Encore UMAX. */
#undef UMAX
/* Define to 1 for Encore UMAX 4.3 that has instead of
. */
#undef UMAX4_3
/* Unixware build */
#undef UNIXWARE
/* Define if BerkeleyDB is available. */
#undef USE_BERKELEYDB
/* Version number of package */
#undef VERSION
/* Define if you want to use SELinux */
#undef WITH_SELINUX
/* lock and log directories */
#undef WORKDIR
/* Define if XEN cpuid-based HVM detection is available. */
#undef XEN_CPUID_SUPPORT
/* Define to 1 if `lex' declares `yytext' as a `char *' by default, not a
`char[]'. */
#undef YYTEXT_POINTER
/* Number of bits in a file offset, on hosts where this is settable. */
#undef _FILE_OFFSET_BITS
/* Define for large files, on AIX-style hosts. */
#undef _LARGE_FILES
/* SVR4 header stuff */
#undef _POSIX_C_SOURCE
/* Use POSIX pthread semantics on Solaris */
#undef _POSIX_PTHREAD_SEMANTICS
/* Solaris 2.6-related stuff */
#undef __BIT_TYPES_DEFINED__
/* SVR4 header stuff */
#undef __EXTENSIONS__
/* Define to empty if `const' does not conform to ANSI C. */
#undef const
/* Define to `int' if doesn't define. */
#undef gid_t
/* Define to `int' if does not define. */
#undef mode_t
/* Define to `long int' if does not define. */
#undef off_t
/* Define to `int' if does not define. */
#undef pid_t
/* Define to `unsigned int' if does not define. */
#undef size_t
/* Define to `int' if doesn't define. */
#undef uid_t
cfengine-3.2.4/src/full-write.c 0000644 0001750 0001750 00000003533 11715232734 013255 0000000 0000000 /*
Copyright (C) Cfengine AS
This file is part of Cfengine 3 - written and maintained by Cfengine 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 Commerical Open Source License
(COSL) may apply to this file if you as a licensee so wish it. See
included file COSL.txt.
*/
#ifdef HAVE_CONFIG_H
# include
#endif
#include "cf.defs.h"
#include
/* Forward declaration copied from prototypes.h to avoid compile-time warning */
int cf_full_write (int desc, char *ptr, size_t len);
#ifdef HAVE_UNISTD_H
#include
#endif
#include
#ifndef STDC_HEADERS
extern int errno;
#endif
/* Write LEN bytes at PTR to descriptor DESC, retrying if interrupted.
Return LEN upon success, write's (negative) error code otherwise. */
int cf_full_write (desc,ptr,len)
int desc;
char *ptr;
size_t len;
{ int total_written;
total_written = 0;
while (len > 0)
{
int written = write(desc,ptr,len);
if (written < 0)
{
if (errno == EINTR)
{
continue;
}
return written;
}
total_written += written;
ptr += written;
len -= written;
}
return total_written;
}
cfengine-3.2.4/src/mod_report.c 0000644 0001750 0001750 00000005666 11715232734 013346 0000000 0000000 /*
Copyright (C) Cfengine AS
This file is part of Cfengine 3 - written and maintained by Cfengine 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 Commerical Open Source License
(COSL) may apply to this file if you as a licensee so wish it. See
included file COSL.txt.
*/
/*****************************************************************************/
/* */
/* File: mod_report.c */
/* */
/*****************************************************************************/
#define CF3_MOD_REPORT
#include "cf3.defs.h"
#include "cf3.extern.h"
struct BodySyntax CF_PRINTFILE_BODY[] =
{
{"file_to_print",cf_str,CF_ABSPATHRANGE,"Path name to the file that is to be sent to standard output"},
{"number_of_lines",cf_int,CF_VALRANGE,"Integer maximum number of lines to print from selected file"},
{NULL,cf_notype,NULL,NULL}
};
/***************************************************************/
/* This is the primary set of constraints for a file object */
struct BodySyntax CF_REPORT_BODIES[] =
{
{"friend_pattern",cf_str,"","Regular expression to keep selected hosts from the friends report list"},
{"intermittency",cf_real,"0,1","Real number threshold [0,1] of intermittency about current peers, report above"},
{"lastseen",cf_int,CF_VALRANGE,"Integer time threshold in hours since current peers were last seen, report absence"},
{"printfile",cf_body,CF_PRINTFILE_BODY,"Quote part of a file to standard output"},
{"report_to_file",cf_str,CF_ABSPATHRANGE,"The path and filename to which output should be appended"},
{"showstate",cf_slist,"","List of services about which status reports should be reported to standard output"},
{NULL,cf_notype,NULL}
};
/***************************************************************/
/* This is the point of entry from mod_common.c */
/***************************************************************/
struct SubTypeSyntax CF_REPORT_SUBTYPES[] =
{
/* Body lists belonging to "reports:" type in Agent */
{"agent","reports",CF_REPORT_BODIES},
{NULL,NULL,NULL},
};
cfengine-3.2.4/src/cf3lex.c 0000644 0001750 0001750 00000151052 11715233327 012346 0000000 0000000
#line 3 "cf3lex.c"
#define YY_INT_ALIGNED short int
/* A lexical scanner generated by flex */
#define FLEX_SCANNER
#define YY_FLEX_MAJOR_VERSION 2
#define YY_FLEX_MINOR_VERSION 5
#define YY_FLEX_SUBMINOR_VERSION 35
#if YY_FLEX_SUBMINOR_VERSION > 0
#define FLEX_BETA
#endif
/* First, we deal with platform-specific or compiler-specific issues. */
/* begin standard C headers. */
#include
#include
#include
#include
/* end standard C headers. */
/* flex integer type definitions */
#ifndef FLEXINT_H
#define FLEXINT_H
/* C99 systems have . Non-C99 systems may or may not. */
#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h,
* if you want the limit (max/min) macros for int types.
*/
#ifndef __STDC_LIMIT_MACROS
#define __STDC_LIMIT_MACROS 1
#endif
#include
typedef int8_t flex_int8_t;
typedef uint8_t flex_uint8_t;
typedef int16_t flex_int16_t;
typedef uint16_t flex_uint16_t;
typedef int32_t flex_int32_t;
typedef uint32_t flex_uint32_t;
#else
typedef signed char flex_int8_t;
typedef short int flex_int16_t;
typedef int flex_int32_t;
typedef unsigned char flex_uint8_t;
typedef unsigned short int flex_uint16_t;
typedef unsigned int flex_uint32_t;
/* Limits of integral types. */
#ifndef INT8_MIN
#define INT8_MIN (-128)
#endif
#ifndef INT16_MIN
#define INT16_MIN (-32767-1)
#endif
#ifndef INT32_MIN
#define INT32_MIN (-2147483647-1)
#endif
#ifndef INT8_MAX
#define INT8_MAX (127)
#endif
#ifndef INT16_MAX
#define INT16_MAX (32767)
#endif
#ifndef INT32_MAX
#define INT32_MAX (2147483647)
#endif
#ifndef UINT8_MAX
#define UINT8_MAX (255U)
#endif
#ifndef UINT16_MAX
#define UINT16_MAX (65535U)
#endif
#ifndef UINT32_MAX
#define UINT32_MAX (4294967295U)
#endif
#endif /* ! C99 */
#endif /* ! FLEXINT_H */
#ifdef __cplusplus
/* The "const" storage-class-modifier is valid. */
#define YY_USE_CONST
#else /* ! __cplusplus */
/* C99 requires __STDC__ to be defined as 1. */
#if defined (__STDC__)
#define YY_USE_CONST
#endif /* defined (__STDC__) */
#endif /* ! __cplusplus */
#ifdef YY_USE_CONST
#define yyconst const
#else
#define yyconst
#endif
/* Returned upon end-of-file. */
#define YY_NULL 0
/* Promotes a possibly negative, possibly signed char to an unsigned
* integer for use as an array index. If the signed char is negative,
* we want to instead treat it as an 8-bit unsigned char, hence the
* double cast.
*/
#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c)
/* Enter a start condition. This macro really ought to take a parameter,
* but we do it the disgusting crufty way forced on us by the ()-less
* definition of BEGIN.
*/
#define BEGIN (yy_start) = 1 + 2 *
/* Translate the current start state into a value that can be later handed
* to BEGIN to return to the state. The YYSTATE alias is for lex
* compatibility.
*/
#define YY_START (((yy_start) - 1) / 2)
#define YYSTATE YY_START
/* Action number for EOF rule of a given start state. */
#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
/* Special action meaning "start processing a new file". */
#define YY_NEW_FILE yyrestart(yyin )
#define YY_END_OF_BUFFER_CHAR 0
/* Size of default input buffer. */
#ifndef YY_BUF_SIZE
#ifdef __ia64__
/* On IA-64, the buffer size is 16k, not 8k.
* Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case.
* Ditto for the __ia64__ case accordingly.
*/
#define YY_BUF_SIZE 32768
#else
#define YY_BUF_SIZE 16384
#endif /* __ia64__ */
#endif
/* The state buf must be large enough to hold one state per character in the main buffer.
*/
#define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type))
#ifndef YY_TYPEDEF_YY_BUFFER_STATE
#define YY_TYPEDEF_YY_BUFFER_STATE
typedef struct yy_buffer_state *YY_BUFFER_STATE;
#endif
extern int yyleng;
extern FILE *yyin, *yyout;
#define EOB_ACT_CONTINUE_SCAN 0
#define EOB_ACT_END_OF_FILE 1
#define EOB_ACT_LAST_MATCH 2
#define YY_LESS_LINENO(n)
/* Return all but the first "n" matched characters back to the input stream. */
#define yyless(n) \
do \
{ \
/* Undo effects of setting up yytext. */ \
int yyless_macro_arg = (n); \
YY_LESS_LINENO(yyless_macro_arg);\
*yy_cp = (yy_hold_char); \
YY_RESTORE_YY_MORE_OFFSET \
(yy_c_buf_p) = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \
YY_DO_BEFORE_ACTION; /* set up yytext again */ \
} \
while ( 0 )
#define unput(c) yyunput( c, (yytext_ptr) )
#ifndef YY_TYPEDEF_YY_SIZE_T
#define YY_TYPEDEF_YY_SIZE_T
typedef size_t yy_size_t;
#endif
#ifndef YY_STRUCT_YY_BUFFER_STATE
#define YY_STRUCT_YY_BUFFER_STATE
struct yy_buffer_state
{
FILE *yy_input_file;
char *yy_ch_buf; /* input buffer */
char *yy_buf_pos; /* current position in input buffer */
/* Size of input buffer in bytes, not including room for EOB
* characters.
*/
yy_size_t yy_buf_size;
/* Number of characters read into yy_ch_buf, not including EOB
* characters.
*/
int yy_n_chars;
/* Whether we "own" the buffer - i.e., we know we created it,
* and can realloc() it to grow it, and should free() it to
* delete it.
*/
int yy_is_our_buffer;
/* Whether this is an "interactive" input source; if so, and
* if we're using stdio for input, then we want to use getc()
* instead of fread(), to make sure we stop fetching input after
* each newline.
*/
int yy_is_interactive;
/* Whether we're considered to be at the beginning of a line.
* If so, '^' rules will be active on the next match, otherwise
* not.
*/
int yy_at_bol;
int yy_bs_lineno; /**< The line count. */
int yy_bs_column; /**< The column count. */
/* Whether to try to fill the input buffer when we reach the
* end of it.
*/
int yy_fill_buffer;
int yy_buffer_status;
#define YY_BUFFER_NEW 0
#define YY_BUFFER_NORMAL 1
/* When an EOF's been seen but there's still some text to process
* then we mark the buffer as YY_EOF_PENDING, to indicate that we
* shouldn't try reading from the input source any more. We might
* still have a bunch of tokens to match, though, because of
* possible backing-up.
*
* When we actually see the EOF, we change the status to "new"
* (via yyrestart()), so that the user can continue scanning by
* just pointing yyin at a new input file.
*/
#define YY_BUFFER_EOF_PENDING 2
};
#endif /* !YY_STRUCT_YY_BUFFER_STATE */
/* Stack of input buffers. */
static size_t yy_buffer_stack_top = 0; /**< index of top of stack. */
static size_t yy_buffer_stack_max = 0; /**< capacity of stack. */
static YY_BUFFER_STATE * yy_buffer_stack = 0; /**< Stack as an array. */
/* We provide macros for accessing buffer states in case in the
* future we want to put the buffer states in a more general
* "scanner state".
*
* Returns the top of the stack, or NULL.
*/
#define YY_CURRENT_BUFFER ( (yy_buffer_stack) \
? (yy_buffer_stack)[(yy_buffer_stack_top)] \
: NULL)
/* Same as previous macro, but useful when we know that the buffer stack is not
* NULL or when we need an lvalue. For internal use only.
*/
#define YY_CURRENT_BUFFER_LVALUE (yy_buffer_stack)[(yy_buffer_stack_top)]
/* yy_hold_char holds the character lost when yytext is formed. */
static char yy_hold_char;
static int yy_n_chars; /* number of characters read into yy_ch_buf */
int yyleng;
/* Points to current character in buffer. */
static char *yy_c_buf_p = (char *) 0;
static int yy_init = 0; /* whether we need to initialize */
static int yy_start = 0; /* start state number */
/* Flag which is used to allow yywrap()'s to do buffer switches
* instead of setting up a fresh yyin. A bit of a hack ...
*/
static int yy_did_buffer_switch_on_eof;
void yyrestart (FILE *input_file );
void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer );
YY_BUFFER_STATE yy_create_buffer (FILE *file,int size );
void yy_delete_buffer (YY_BUFFER_STATE b );
void yy_flush_buffer (YY_BUFFER_STATE b );
void yypush_buffer_state (YY_BUFFER_STATE new_buffer );
void yypop_buffer_state (void );
static void yyensure_buffer_stack (void );
static void yy_load_buffer_state (void );
static void yy_init_buffer (YY_BUFFER_STATE b,FILE *file );
#define YY_FLUSH_BUFFER yy_flush_buffer(YY_CURRENT_BUFFER )
YY_BUFFER_STATE yy_scan_buffer (char *base,yy_size_t size );
YY_BUFFER_STATE yy_scan_string (yyconst char *yy_str );
YY_BUFFER_STATE yy_scan_bytes (yyconst char *bytes,int len );
void *yyalloc (yy_size_t );
void *yyrealloc (void *,yy_size_t );
void yyfree (void * );
#define yy_new_buffer yy_create_buffer
#define yy_set_interactive(is_interactive) \
{ \
if ( ! YY_CURRENT_BUFFER ){ \
yyensure_buffer_stack (); \
YY_CURRENT_BUFFER_LVALUE = \
yy_create_buffer(yyin,YY_BUF_SIZE ); \
} \
YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \
}
#define yy_set_bol(at_bol) \
{ \
if ( ! YY_CURRENT_BUFFER ){\
yyensure_buffer_stack (); \
YY_CURRENT_BUFFER_LVALUE = \
yy_create_buffer(yyin,YY_BUF_SIZE ); \
} \
YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \
}
#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol)
/* Begin user sect3 */
#define yywrap(n) 1
#define YY_SKIP_YYWRAP
typedef unsigned char YY_CHAR;
FILE *yyin = (FILE *) 0, *yyout = (FILE *) 0;
typedef int yy_state_type;
extern int yylineno;
int yylineno = 1;
extern char *yytext;
#define yytext_ptr yytext
static yy_state_type yy_get_previous_state (void );
static yy_state_type yy_try_NUL_trans (yy_state_type current_state );
static int yy_get_next_buffer (void );
static void yy_fatal_error (yyconst char msg[] );
/* Done after the current pattern has been matched and before the
* corresponding action - sets up yytext.
*/
#define YY_DO_BEFORE_ACTION \
(yytext_ptr) = yy_bp; \
yyleng = (size_t) (yy_cp - yy_bp); \
(yy_hold_char) = *yy_cp; \
*yy_cp = '\0'; \
(yy_c_buf_p) = yy_cp;
#define YY_NUM_RULES 14
#define YY_END_OF_BUFFER 15
/* This struct is not used in this scanner,
but its presence is necessary. */
struct yy_trans_info
{
flex_int32_t yy_verify;
flex_int32_t yy_nxt;
};
static yyconst flex_int16_t yy_accept[50] =
{ 0,
0, 0, 15, 13, 11, 1, 13, 13, 13, 12,
13, 13, 13, 4, 13, 4, 13, 4, 11, 1,
0, 0, 0, 9, 0, 12, 0, 0, 0, 0,
6, 4, 5, 8, 4, 0, 4, 4, 7, 0,
0, 4, 4, 10, 3, 4, 4, 2, 0
} ;
static yyconst flex_int32_t yy_ec[256] =
{ 0,
1, 1, 1, 1, 1, 1, 1, 1, 2, 3,
1, 1, 4, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 2, 5, 6, 7, 8, 1, 5, 9, 10,
11, 1, 1, 1, 12, 13, 1, 14, 14, 14,
14, 14, 14, 14, 14, 14, 14, 15, 1, 1,
16, 17, 1, 8, 18, 18, 18, 18, 18, 18,
18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
1, 19, 1, 1, 18, 20, 18, 21, 18, 22,
23, 18, 18, 18, 18, 18, 18, 24, 18, 25,
26, 18, 18, 18, 18, 18, 27, 18, 18, 18,
28, 18, 29, 5, 30, 1, 1, 14, 14, 14,
14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
14, 14, 14, 14, 14
} ;
static yyconst flex_int32_t yy_meta[31] =
{ 0,
1, 1, 2, 1, 3, 1, 1, 1, 1, 3,
3, 1, 4, 4, 3, 1, 1, 4, 1, 1,
4, 4, 4, 4, 4, 4, 4, 4, 1, 1
} ;
static yyconst flex_int16_t yy_base[59] =
{ 0,
0, 0, 70, 142, 65, 142, 63, 50, 25, 0,
22, 24, 47, 47, 44, 58, 39, 69, 54, 142,
40, 39, 28, 142, 0, 0, 0, 0, 26, 0,
142, 93, 142, 38, 104, 30, 27, 23, 142, 35,
12, 13, 18, 142, 0, 15, 15, 0, 142, 117,
121, 125, 129, 131, 133, 137, 33, 32
} ;
static yyconst flex_int16_t yy_def[59] =
{ 0,
49, 1, 49, 49, 49, 49, 49, 50, 51, 52,
49, 53, 49, 54, 49, 55, 56, 49, 49, 49,
50, 49, 51, 49, 51, 52, 57, 58, 53, 53,
49, 54, 49, 49, 55, 56, 35, 35, 49, 57,
58, 35, 35, 49, 35, 35, 35, 35, 0, 49,
49, 49, 49, 49, 49, 49, 49, 49
} ;
static yyconst flex_int16_t yy_nxt[173] =
{ 0,
4, 5, 6, 7, 8, 9, 10, 11, 12, 8,
8, 13, 8, 14, 4, 15, 4, 16, 4, 17,
18, 16, 16, 16, 16, 16, 16, 16, 4, 4,
24, 27, 24, 24, 24, 41, 40, 48, 47, 46,
45, 44, 30, 25, 30, 44, 25, 43, 42, 24,
28, 21, 39, 39, 22, 19, 21, 21, 24, 21,
33, 22, 21, 31, 22, 20, 19, 21, 21, 49,
21, 32, 34, 21, 49, 49, 49, 49, 21, 21,
49, 21, 32, 34, 49, 49, 35, 49, 49, 35,
35, 35, 35, 35, 37, 38, 35, 21, 49, 49,
49, 49, 21, 21, 49, 21, 49, 22, 21, 49,
49, 49, 49, 21, 21, 49, 21, 32, 34, 21,
21, 23, 23, 23, 23, 26, 49, 26, 26, 29,
29, 29, 29, 32, 32, 35, 35, 36, 36, 36,
36, 3, 49, 49, 49, 49, 49, 49, 49, 49,
49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
49, 49
} ;
static yyconst flex_int16_t yy_chk[173] =
{ 0,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
9, 11, 12, 23, 29, 58, 57, 47, 46, 43,
42, 41, 12, 9, 29, 40, 23, 38, 37, 36,
11, 14, 34, 22, 21, 19, 14, 14, 17, 14,
15, 14, 16, 13, 8, 7, 5, 16, 16, 3,
16, 16, 16, 18, 0, 0, 0, 0, 18, 18,
0, 18, 18, 18, 0, 0, 18, 0, 0, 18,
18, 18, 18, 18, 18, 18, 18, 32, 0, 0,
0, 0, 32, 32, 0, 32, 0, 32, 35, 0,
0, 0, 0, 35, 35, 0, 35, 35, 35, 50,
50, 51, 51, 51, 51, 52, 0, 52, 52, 53,
53, 53, 53, 54, 54, 55, 55, 56, 56, 56,
56, 49, 49, 49, 49, 49, 49, 49, 49, 49,
49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
49, 49
} ;
static yy_state_type yy_last_accepting_state;
static char *yy_last_accepting_cpos;
extern int yy_flex_debug;
int yy_flex_debug = 0;
/* The intent behind this definition is that it'll catch
* any uses of REJECT which flex missed.
*/
#define REJECT reject_used_but_not_detected
#define yymore() yymore_used_but_not_detected
#define YY_MORE_ADJ 0
#define YY_RESTORE_YY_MORE_OFFSET
char *yytext;
#line 1 "cf3lex.l"
#line 2 "cf3lex.l"
/*
Copyright (C) Cfengine AS
This file is part of Cfengine 3 - written and maintained by Cfengine 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 Commerical Open Source License
(COSL) may apply to this file if you as a licensee so wish it. See
included file COSL.txt.
*/
/*******************************************************************/
/* */
/* LEXER for cfengine 3 */
/* */
/*******************************************************************/
#include "cf3.defs.h"
#include "cf3.extern.h"
#include "cf3parse.h"
// Do not use lex - flex only
/*
* Three types of quoted strings:
*
* - string in double quotes, starts with double quote, runs until another
* double quote, \" masks the double quote.
* - string in single quotes, starts with single quote, runs until another
* single quote, \' masks the single quote.
* - string in backquotes, starts with backquote, runs until another backquote.
*
* The same rule formatted for the better readability:
*
* := \" \" | \' \' | ` `
* = *
* = \\ | [^"\\]
* = *
* = \\ | [^'\\]
* = *
* = [^`]
* = . | \n
*
*/
#line 571 "cf3lex.c"
#define INITIAL 0
#ifndef YY_NO_UNISTD_H
/* Special case for "unistd.h", since it is non-ANSI. We include it way
* down here because we want the user's section 1 to have been scanned first.
* The user has a chance to override it with an option.
*/
#include
#endif
#ifndef YY_EXTRA_TYPE
#define YY_EXTRA_TYPE void *
#endif
static int yy_init_globals (void );
/* Accessor methods to globals.
These are made visible to non-reentrant scanners for convenience. */
int yylex_destroy (void );
int yyget_debug (void );
void yyset_debug (int debug_flag );
YY_EXTRA_TYPE yyget_extra (void );
void yyset_extra (YY_EXTRA_TYPE user_defined );
FILE *yyget_in (void );
void yyset_in (FILE * in_str );
FILE *yyget_out (void );
void yyset_out (FILE * out_str );
int yyget_leng (void );
char *yyget_text (void );
int yyget_lineno (void );
void yyset_lineno (int line_number );
/* Macros after this point can all be overridden by user definitions in
* section 1.
*/
#ifndef YY_SKIP_YYWRAP
#ifdef __cplusplus
extern "C" int yywrap (void );
#else
extern int yywrap (void );
#endif
#endif
static void yyunput (int c,char *buf_ptr );
#ifndef yytext_ptr
static void yy_flex_strncpy (char *,yyconst char *,int );
#endif
#ifdef YY_NEED_STRLEN
static int yy_flex_strlen (yyconst char * );
#endif
#ifndef YY_NO_INPUT
#ifdef __cplusplus
static int yyinput (void );
#else
static int input (void );
#endif
#endif
/* Amount of stuff to slurp up with each read. */
#ifndef YY_READ_BUF_SIZE
#ifdef __ia64__
/* On IA-64, the buffer size is 16k, not 8k */
#define YY_READ_BUF_SIZE 16384
#else
#define YY_READ_BUF_SIZE 8192
#endif /* __ia64__ */
#endif
/* Copy whatever the last rule matched to the standard output. */
#ifndef ECHO
/* This used to be an fputs(), but since the string might contain NUL's,
* we now use fwrite().
*/
#define ECHO do { if (fwrite( yytext, yyleng, 1, yyout )) {} } while (0)
#endif
/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL,
* is returned in "result".
*/
#ifndef YY_INPUT
#define YY_INPUT(buf,result,max_size) \
if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \
{ \
int c = '*'; \
size_t n; \
for ( n = 0; n < max_size && \
(c = getc( yyin )) != EOF && c != '\n'; ++n ) \
buf[n] = (char) c; \
if ( c == '\n' ) \
buf[n++] = (char) c; \
if ( c == EOF && ferror( yyin ) ) \
YY_FATAL_ERROR( "input in flex scanner failed" ); \
result = n; \
} \
else \
{ \
errno=0; \
while ( (result = fread(buf, 1, max_size, yyin))==0 && ferror(yyin)) \
{ \
if( errno != EINTR) \
{ \
YY_FATAL_ERROR( "input in flex scanner failed" ); \
break; \
} \
errno=0; \
clearerr(yyin); \
} \
}\
\
#endif
/* No semi-colon after return; correct usage is to write "yyterminate();" -
* we don't want an extra ';' after the "return" because that will cause
* some compilers to complain about unreachable statements.
*/
#ifndef yyterminate
#define yyterminate() return YY_NULL
#endif
/* Number of entries by which start-condition stack grows. */
#ifndef YY_START_STACK_INCR
#define YY_START_STACK_INCR 25
#endif
/* Report a fatal error. */
#ifndef YY_FATAL_ERROR
#define YY_FATAL_ERROR(msg) yy_fatal_error( msg )
#endif
/* end tables serialization structures and prototypes */
/* Default declaration of generated scanner - a define so the user can
* easily add parameters.
*/
#ifndef YY_DECL
#define YY_DECL_IS_OURS 1
extern int yylex (void);
#define YY_DECL int yylex (void)
#endif /* !YY_DECL */
/* Code executed at the beginning of each rule, after yytext and yyleng
* have been set up.
*/
#ifndef YY_USER_ACTION
#define YY_USER_ACTION
#endif
/* Code executed at the end of each rule. */
#ifndef YY_BREAK
#define YY_BREAK break;
#endif
#define YY_RULE_SETUP \
YY_USER_ACTION
/** The main scanner function which does all the work.
*/
YY_DECL
{
register yy_state_type yy_current_state;
register char *yy_cp, *yy_bp;
register int yy_act;
#line 87 "cf3lex.l"
#line 761 "cf3lex.c"
if ( !(yy_init) )
{
(yy_init) = 1;
#ifdef YY_USER_INIT
YY_USER_INIT;
#endif
if ( ! (yy_start) )
(yy_start) = 1; /* first start state */
if ( ! yyin )
yyin = stdin;
if ( ! yyout )
yyout = stdout;
if ( ! YY_CURRENT_BUFFER ) {
yyensure_buffer_stack ();
YY_CURRENT_BUFFER_LVALUE =
yy_create_buffer(yyin,YY_BUF_SIZE );
}
yy_load_buffer_state( );
}
while ( 1 ) /* loops until end-of-file is reached */
{
yy_cp = (yy_c_buf_p);
/* Support of yytext. */
*yy_cp = (yy_hold_char);
/* yy_bp points to the position in yy_ch_buf of the start of
* the current run.
*/
yy_bp = yy_cp;
yy_current_state = (yy_start);
yy_match:
do
{
register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)];
if ( yy_accept[yy_current_state] )
{
(yy_last_accepting_state) = yy_current_state;
(yy_last_accepting_cpos) = yy_cp;
}
while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
{
yy_current_state = (int) yy_def[yy_current_state];
if ( yy_current_state >= 50 )
yy_c = yy_meta[(unsigned int) yy_c];
}
yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
++yy_cp;
}
while ( yy_base[yy_current_state] != 142 );
yy_find_action:
yy_act = yy_accept[yy_current_state];
if ( yy_act == 0 )
{ /* have to back up */
yy_cp = (yy_last_accepting_cpos);
yy_current_state = (yy_last_accepting_state);
yy_act = yy_accept[yy_current_state];
}
YY_DO_BEFORE_ACTION;
do_action: /* This label is used only to access EOF actions. */
switch ( yy_act )
{ /* beginning of action switch */
case 0: /* must back up */
/* undo the effects of YY_DO_BEFORE_ACTION */
*yy_cp = (yy_hold_char);
yy_cp = (yy_last_accepting_cpos);
yy_current_state = (yy_last_accepting_state);
goto yy_find_action;
case 1:
/* rule 1 can match eol */
YY_RULE_SETUP
#line 89 "cf3lex.l"
{
P.line_no++;
P.line_pos = 0;
}
YY_BREAK
case 2:
YY_RULE_SETUP
#line 94 "cf3lex.l"
{
/* Note this has to come before "id" since it is a subset of id */
if (P.currentclasses != NULL)
{
free(P.currentclasses);
P.currentclasses = NULL;
}
P.line_pos += strlen(yytext);
return BUNDLE;
}
YY_BREAK
case 3:
YY_RULE_SETUP
#line 106 "cf3lex.l"
{
/* Note this has to come before "id" since it is a subset of id */
if (P.currentclasses != NULL)
{
free(P.currentclasses);
P.currentclasses = NULL;
}
P.line_pos += strlen(yytext);
return BODY;
}
YY_BREAK
case 4:
YY_RULE_SETUP
#line 118 "cf3lex.l"
{
P.line_pos += strlen(yytext);
if (strlen(yytext) > CF_MAXVARSIZE-1)
{
yyerror("identifier too long");
}
strncpy(P.currentid,yytext,CF_MAXVARSIZE);
return ID;
}
YY_BREAK
case 5:
YY_RULE_SETUP
#line 129 "cf3lex.l"
{
P.line_pos += strlen(yytext);
return ASSIGN;
}
YY_BREAK
case 6:
YY_RULE_SETUP
#line 134 "cf3lex.l"
{
P.line_pos += strlen(yytext);
return ARROW;
}
YY_BREAK
case 7:
YY_RULE_SETUP
#line 139 "cf3lex.l"
{
P.line_pos += strlen(yytext);
if (P.currentclasses != NULL)
{
free(P.currentclasses);
}
yytext[strlen(yytext)-2] = '\0';
ValidateClassSyntax(yytext);
P.currentclasses = strdup(yytext);
return CLASS;
}
YY_BREAK
case 8:
YY_RULE_SETUP
#line 153 "cf3lex.l"
{
P.line_pos += strlen(yytext);
yytext[strlen(yytext)-1] = '\0';
strncpy(P.currenttype,yytext,CF_MAXVARSIZE);
if (P.currentclasses != NULL)
{
free(P.currentclasses);
P.currentclasses = NULL;
}
return CATEGORY;
}
YY_BREAK
case 9:
/* rule 9 can match eol */
YY_RULE_SETUP
#line 167 "cf3lex.l"
{
char *tmp = NULL;
int less = 0;
P.line_pos += strlen(yytext);
if ((tmp = malloc(strlen(yytext)+1)) == NULL)
{
FatalError("Malloc failure in parsing");
}
if ((less = DeEscapeQuotedString(yytext,tmp)) > 0)
{
yyless(less);
}
if (P.currentstring)
{
free(P.currentstring);
}
P.currentstring = strdup(tmp);
if (THIS_AGENT_TYPE == cf_common)
{
IsCf3VarString(tmp);
}
free(tmp);
return QSTRING;
}
YY_BREAK
case 10:
YY_RULE_SETUP
#line 200 "cf3lex.l"
{
P.line_pos += strlen(yytext);
P.currentstring = strdup(yytext);
return NAKEDVAR;
}
YY_BREAK
case 11:
YY_RULE_SETUP
#line 207 "cf3lex.l"
{
P.line_pos += strlen(yytext);
}
YY_BREAK
case 12:
YY_RULE_SETUP
#line 211 "cf3lex.l"
{
}
YY_BREAK
case 13:
YY_RULE_SETUP
#line 215 "cf3lex.l"
{
P.line_pos++;
return yytext[0];
}
YY_BREAK
case 14:
YY_RULE_SETUP
#line 221 "cf3lex.l"
ECHO;
YY_BREAK
#line 1017 "cf3lex.c"
case YY_STATE_EOF(INITIAL):
yyterminate();
case YY_END_OF_BUFFER:
{
/* Amount of text matched not including the EOB char. */
int yy_amount_of_matched_text = (int) (yy_cp - (yytext_ptr)) - 1;
/* Undo the effects of YY_DO_BEFORE_ACTION. */
*yy_cp = (yy_hold_char);
YY_RESTORE_YY_MORE_OFFSET
if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW )
{
/* We're scanning a new file or input source. It's
* possible that this happened because the user
* just pointed yyin at a new source and called
* yylex(). If so, then we have to assure
* consistency between YY_CURRENT_BUFFER and our
* globals. Here is the right place to do so, because
* this is the first action (other than possibly a
* back-up) that will match for the new input source.
*/
(yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin;
YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL;
}
/* Note that here we test for yy_c_buf_p "<=" to the position
* of the first EOB in the buffer, since yy_c_buf_p will
* already have been incremented past the NUL character
* (since all states make transitions on EOB to the
* end-of-buffer state). Contrast this with the test
* in input().
*/
if ( (yy_c_buf_p) <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] )
{ /* This was really a NUL. */
yy_state_type yy_next_state;
(yy_c_buf_p) = (yytext_ptr) + yy_amount_of_matched_text;
yy_current_state = yy_get_previous_state( );
/* Okay, we're now positioned to make the NUL
* transition. We couldn't have
* yy_get_previous_state() go ahead and do it
* for us because it doesn't know how to deal
* with the possibility of jamming (and we don't
* want to build jamming into it because then it
* will run more slowly).
*/
yy_next_state = yy_try_NUL_trans( yy_current_state );
yy_bp = (yytext_ptr) + YY_MORE_ADJ;
if ( yy_next_state )
{
/* Consume the NUL. */
yy_cp = ++(yy_c_buf_p);
yy_current_state = yy_next_state;
goto yy_match;
}
else
{
yy_cp = (yy_c_buf_p);
goto yy_find_action;
}
}
else switch ( yy_get_next_buffer( ) )
{
case EOB_ACT_END_OF_FILE:
{
(yy_did_buffer_switch_on_eof) = 0;
if ( yywrap( ) )
{
/* Note: because we've taken care in
* yy_get_next_buffer() to have set up
* yytext, we can now set up
* yy_c_buf_p so that if some total
* hoser (like flex itself) wants to
* call the scanner after we return the
* YY_NULL, it'll still work - another
* YY_NULL will get returned.
*/
(yy_c_buf_p) = (yytext_ptr) + YY_MORE_ADJ;
yy_act = YY_STATE_EOF(YY_START);
goto do_action;
}
else
{
if ( ! (yy_did_buffer_switch_on_eof) )
YY_NEW_FILE;
}
break;
}
case EOB_ACT_CONTINUE_SCAN:
(yy_c_buf_p) =
(yytext_ptr) + yy_amount_of_matched_text;
yy_current_state = yy_get_previous_state( );
yy_cp = (yy_c_buf_p);
yy_bp = (yytext_ptr) + YY_MORE_ADJ;
goto yy_match;
case EOB_ACT_LAST_MATCH:
(yy_c_buf_p) =
&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)];
yy_current_state = yy_get_previous_state( );
yy_cp = (yy_c_buf_p);
yy_bp = (yytext_ptr) + YY_MORE_ADJ;
goto yy_find_action;
}
break;
}
default:
YY_FATAL_ERROR(
"fatal flex scanner internal error--no action found" );
} /* end of action switch */
} /* end of scanning one token */
} /* end of yylex */
/* yy_get_next_buffer - try to read in a new buffer
*
* Returns a code representing an action:
* EOB_ACT_LAST_MATCH -
* EOB_ACT_CONTINUE_SCAN - continue scanning from current position
* EOB_ACT_END_OF_FILE - end of file
*/
static int yy_get_next_buffer (void)
{
register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf;
register char *source = (yytext_ptr);
register int number_to_move, i;
int ret_val;
if ( (yy_c_buf_p) > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] )
YY_FATAL_ERROR(
"fatal flex scanner internal error--end of buffer missed" );
if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 )
{ /* Don't try to fill the buffer, so this is an EOF. */
if ( (yy_c_buf_p) - (yytext_ptr) - YY_MORE_ADJ == 1 )
{
/* We matched a single character, the EOB, so
* treat this as a final EOF.
*/
return EOB_ACT_END_OF_FILE;
}
else
{
/* We matched some text prior to the EOB, first
* process it.
*/
return EOB_ACT_LAST_MATCH;
}
}
/* Try to read more data. */
/* First move last chars to start of buffer. */
number_to_move = (int) ((yy_c_buf_p) - (yytext_ptr)) - 1;
for ( i = 0; i < number_to_move; ++i )
*(dest++) = *(source++);
if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING )
/* don't do the read, it's not guaranteed to return an EOF,
* just force an EOF
*/
YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars) = 0;
else
{
int num_to_read =
YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1;
while ( num_to_read <= 0 )
{ /* Not enough room in the buffer - grow it. */
/* just a shorter name for the current buffer */
YY_BUFFER_STATE b = YY_CURRENT_BUFFER;
int yy_c_buf_p_offset =
(int) ((yy_c_buf_p) - b->yy_ch_buf);
if ( b->yy_is_our_buffer )
{
int new_size = b->yy_buf_size * 2;
if ( new_size <= 0 )
b->yy_buf_size += b->yy_buf_size / 8;
else
b->yy_buf_size *= 2;
b->yy_ch_buf = (char *)
/* Include room in for 2 EOB chars. */
yyrealloc((void *) b->yy_ch_buf,b->yy_buf_size + 2 );
}
else
/* Can't grow it, we don't own it. */
b->yy_ch_buf = 0;
if ( ! b->yy_ch_buf )
YY_FATAL_ERROR(
"fatal error - scanner input buffer overflow" );
(yy_c_buf_p) = &b->yy_ch_buf[yy_c_buf_p_offset];
num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size -
number_to_move - 1;
}
if ( num_to_read > YY_READ_BUF_SIZE )
num_to_read = YY_READ_BUF_SIZE;
/* Read in more data. */
YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]),
(yy_n_chars), (size_t) num_to_read );
YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
}
if ( (yy_n_chars) == 0 )
{
if ( number_to_move == YY_MORE_ADJ )
{
ret_val = EOB_ACT_END_OF_FILE;
yyrestart(yyin );
}
else
{
ret_val = EOB_ACT_LAST_MATCH;
YY_CURRENT_BUFFER_LVALUE->yy_buffer_status =
YY_BUFFER_EOF_PENDING;
}
}
else
ret_val = EOB_ACT_CONTINUE_SCAN;
if ((yy_size_t) ((yy_n_chars) + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) {
/* Extend the array by 50%, plus the number we really need. */
yy_size_t new_size = (yy_n_chars) + number_to_move + ((yy_n_chars) >> 1);
YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) yyrealloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size );
if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" );
}
(yy_n_chars) += number_to_move;
YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] = YY_END_OF_BUFFER_CHAR;
YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] = YY_END_OF_BUFFER_CHAR;
(yytext_ptr) = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0];
return ret_val;
}
/* yy_get_previous_state - get the state just before the EOB char was reached */
static yy_state_type yy_get_previous_state (void)
{
register yy_state_type yy_current_state;
register char *yy_cp;
yy_current_state = (yy_start);
for ( yy_cp = (yytext_ptr) + YY_MORE_ADJ; yy_cp < (yy_c_buf_p); ++yy_cp )
{
register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1);
if ( yy_accept[yy_current_state] )
{
(yy_last_accepting_state) = yy_current_state;
(yy_last_accepting_cpos) = yy_cp;
}
while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
{
yy_current_state = (int) yy_def[yy_current_state];
if ( yy_current_state >= 50 )
yy_c = yy_meta[(unsigned int) yy_c];
}
yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
}
return yy_current_state;
}
/* yy_try_NUL_trans - try to make a transition on the NUL character
*
* synopsis
* next_state = yy_try_NUL_trans( current_state );
*/
static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state )
{
register int yy_is_jam;
register char *yy_cp = (yy_c_buf_p);
register YY_CHAR yy_c = 1;
if ( yy_accept[yy_current_state] )
{
(yy_last_accepting_state) = yy_current_state;
(yy_last_accepting_cpos) = yy_cp;
}
while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
{
yy_current_state = (int) yy_def[yy_current_state];
if ( yy_current_state >= 50 )
yy_c = yy_meta[(unsigned int) yy_c];
}
yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
yy_is_jam = (yy_current_state == 49);
return yy_is_jam ? 0 : yy_current_state;
}
static void yyunput (int c, register char * yy_bp )
{
register char *yy_cp;
yy_cp = (yy_c_buf_p);
/* undo effects of setting up yytext */
*yy_cp = (yy_hold_char);
if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 )
{ /* need to shift things up to make room */
/* +2 for EOB chars. */
register int number_to_move = (yy_n_chars) + 2;
register char *dest = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[
YY_CURRENT_BUFFER_LVALUE->yy_buf_size + 2];
register char *source =
&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move];
while ( source > YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
*--dest = *--source;
yy_cp += (int) (dest - source);
yy_bp += (int) (dest - source);
YY_CURRENT_BUFFER_LVALUE->yy_n_chars =
(yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_buf_size;
if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 )
YY_FATAL_ERROR( "flex scanner push-back overflow" );
}
*--yy_cp = (char) c;
(yytext_ptr) = yy_bp;
(yy_hold_char) = *yy_cp;
(yy_c_buf_p) = yy_cp;
}
#ifndef YY_NO_INPUT
#ifdef __cplusplus
static int yyinput (void)
#else
static int input (void)
#endif
{
int c;
*(yy_c_buf_p) = (yy_hold_char);
if ( *(yy_c_buf_p) == YY_END_OF_BUFFER_CHAR )
{
/* yy_c_buf_p now points to the character we want to return.
* If this occurs *before* the EOB characters, then it's a
* valid NUL; if not, then we've hit the end of the buffer.
*/
if ( (yy_c_buf_p) < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] )
/* This was really a NUL. */
*(yy_c_buf_p) = '\0';
else
{ /* need more input */
int offset = (yy_c_buf_p) - (yytext_ptr);
++(yy_c_buf_p);
switch ( yy_get_next_buffer( ) )
{
case EOB_ACT_LAST_MATCH:
/* This happens because yy_g_n_b()
* sees that we've accumulated a
* token and flags that we need to
* try matching the token before
* proceeding. But for input(),
* there's no matching to consider.
* So convert the EOB_ACT_LAST_MATCH
* to EOB_ACT_END_OF_FILE.
*/
/* Reset buffer status. */
yyrestart(yyin );
/*FALLTHROUGH*/
case EOB_ACT_END_OF_FILE:
{
if ( yywrap( ) )
return EOF;
if ( ! (yy_did_buffer_switch_on_eof) )
YY_NEW_FILE;
#ifdef __cplusplus
return yyinput();
#else
return input();
#endif
}
case EOB_ACT_CONTINUE_SCAN:
(yy_c_buf_p) = (yytext_ptr) + offset;
break;
}
}
}
c = *(unsigned char *) (yy_c_buf_p); /* cast for 8-bit char's */
*(yy_c_buf_p) = '\0'; /* preserve yytext */
(yy_hold_char) = *++(yy_c_buf_p);
return c;
}
#endif /* ifndef YY_NO_INPUT */
/** Immediately switch to a different input stream.
* @param input_file A readable stream.
*
* @note This function does not reset the start condition to @c INITIAL .
*/
void yyrestart (FILE * input_file )
{
if ( ! YY_CURRENT_BUFFER ){
yyensure_buffer_stack ();
YY_CURRENT_BUFFER_LVALUE =
yy_create_buffer(yyin,YY_BUF_SIZE );
}
yy_init_buffer(YY_CURRENT_BUFFER,input_file );
yy_load_buffer_state( );
}
/** Switch to a different input buffer.
* @param new_buffer The new input buffer.
*
*/
void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer )
{
/* TODO. We should be able to replace this entire function body
* with
* yypop_buffer_state();
* yypush_buffer_state(new_buffer);
*/
yyensure_buffer_stack ();
if ( YY_CURRENT_BUFFER == new_buffer )
return;
if ( YY_CURRENT_BUFFER )
{
/* Flush out information for old buffer. */
*(yy_c_buf_p) = (yy_hold_char);
YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p);
YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
}
YY_CURRENT_BUFFER_LVALUE = new_buffer;
yy_load_buffer_state( );
/* We don't actually know whether we did this switch during
* EOF (yywrap()) processing, but the only time this flag
* is looked at is after yywrap() is called, so it's safe
* to go ahead and always set it.
*/
(yy_did_buffer_switch_on_eof) = 1;
}
static void yy_load_buffer_state (void)
{
(yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
(yytext_ptr) = (yy_c_buf_p) = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos;
yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file;
(yy_hold_char) = *(yy_c_buf_p);
}
/** Allocate and initialize an input buffer state.
* @param file A readable stream.
* @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE.
*
* @return the allocated buffer state.
*/
YY_BUFFER_STATE yy_create_buffer (FILE * file, int size )
{
YY_BUFFER_STATE b;
b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state ) );
if ( ! b )
YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
b->yy_buf_size = size;
/* yy_ch_buf has to be 2 characters longer than the size given because
* we need to put in 2 end-of-buffer characters.
*/
b->yy_ch_buf = (char *) yyalloc(b->yy_buf_size + 2 );
if ( ! b->yy_ch_buf )
YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
b->yy_is_our_buffer = 1;
yy_init_buffer(b,file );
return b;
}
/** Destroy the buffer.
* @param b a buffer created with yy_create_buffer()
*
*/
void yy_delete_buffer (YY_BUFFER_STATE b )
{
if ( ! b )
return;
if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */
YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0;
if ( b->yy_is_our_buffer )
yyfree((void *) b->yy_ch_buf );
yyfree((void *) b );
}
#ifndef __cplusplus
extern int isatty (int );
#endif /* __cplusplus */
/* Initializes or reinitializes a buffer.
* This function is sometimes called more than once on the same buffer,
* such as during a yyrestart() or at EOF.
*/
static void yy_init_buffer (YY_BUFFER_STATE b, FILE * file )
{
int oerrno = errno;
yy_flush_buffer(b );
b->yy_input_file = file;
b->yy_fill_buffer = 1;
/* If b is the current buffer, then yy_init_buffer was _probably_
* called from yyrestart() or through yy_get_next_buffer.
* In that case, we don't want to reset the lineno or column.
*/
if (b != YY_CURRENT_BUFFER){
b->yy_bs_lineno = 1;
b->yy_bs_column = 0;
}
b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0;
errno = oerrno;
}
/** Discard all buffered characters. On the next scan, YY_INPUT will be called.
* @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER.
*
*/
void yy_flush_buffer (YY_BUFFER_STATE b )
{
if ( ! b )
return;
b->yy_n_chars = 0;
/* We always need two end-of-buffer characters. The first causes
* a transition to the end-of-buffer state. The second causes
* a jam in that state.
*/
b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR;
b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR;
b->yy_buf_pos = &b->yy_ch_buf[0];
b->yy_at_bol = 1;
b->yy_buffer_status = YY_BUFFER_NEW;
if ( b == YY_CURRENT_BUFFER )
yy_load_buffer_state( );
}
/** Pushes the new state onto the stack. The new state becomes
* the current state. This function will allocate the stack
* if necessary.
* @param new_buffer The new state.
*
*/
void yypush_buffer_state (YY_BUFFER_STATE new_buffer )
{
if (new_buffer == NULL)
return;
yyensure_buffer_stack();
/* This block is copied from yy_switch_to_buffer. */
if ( YY_CURRENT_BUFFER )
{
/* Flush out information for old buffer. */
*(yy_c_buf_p) = (yy_hold_char);
YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p);
YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
}
/* Only push if top exists. Otherwise, replace top. */
if (YY_CURRENT_BUFFER)
(yy_buffer_stack_top)++;
YY_CURRENT_BUFFER_LVALUE = new_buffer;
/* copied from yy_switch_to_buffer. */
yy_load_buffer_state( );
(yy_did_buffer_switch_on_eof) = 1;
}
/** Removes and deletes the top of the stack, if present.
* The next element becomes the new top.
*
*/
void yypop_buffer_state (void)
{
if (!YY_CURRENT_BUFFER)
return;
yy_delete_buffer(YY_CURRENT_BUFFER );
YY_CURRENT_BUFFER_LVALUE = NULL;
if ((yy_buffer_stack_top) > 0)
--(yy_buffer_stack_top);
if (YY_CURRENT_BUFFER) {
yy_load_buffer_state( );
(yy_did_buffer_switch_on_eof) = 1;
}
}
/* Allocates the stack if it does not exist.
* Guarantees space for at least one push.
*/
static void yyensure_buffer_stack (void)
{
int num_to_alloc;
if (!(yy_buffer_stack)) {
/* First allocation is just for 2 elements, since we don't know if this
* scanner will even need a stack. We use 2 instead of 1 to avoid an
* immediate realloc on the next call.
*/
num_to_alloc = 1;
(yy_buffer_stack) = (struct yy_buffer_state**)yyalloc
(num_to_alloc * sizeof(struct yy_buffer_state*)
);
if ( ! (yy_buffer_stack) )
YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" );
memset((yy_buffer_stack), 0, num_to_alloc * sizeof(struct yy_buffer_state*));
(yy_buffer_stack_max) = num_to_alloc;
(yy_buffer_stack_top) = 0;
return;
}
if ((yy_buffer_stack_top) >= ((yy_buffer_stack_max)) - 1){
/* Increase the buffer to prepare for a possible push. */
int grow_size = 8 /* arbitrary grow size */;
num_to_alloc = (yy_buffer_stack_max) + grow_size;
(yy_buffer_stack) = (struct yy_buffer_state**)yyrealloc
((yy_buffer_stack),
num_to_alloc * sizeof(struct yy_buffer_state*)
);
if ( ! (yy_buffer_stack) )
YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" );
/* zero only the new slots.*/
memset((yy_buffer_stack) + (yy_buffer_stack_max), 0, grow_size * sizeof(struct yy_buffer_state*));
(yy_buffer_stack_max) = num_to_alloc;
}
}
/** Setup the input buffer state to scan directly from a user-specified character buffer.
* @param base the character buffer
* @param size the size in bytes of the character buffer
*
* @return the newly allocated buffer state object.
*/
YY_BUFFER_STATE yy_scan_buffer (char * base, yy_size_t size )
{
YY_BUFFER_STATE b;
if ( size < 2 ||
base[size-2] != YY_END_OF_BUFFER_CHAR ||
base[size-1] != YY_END_OF_BUFFER_CHAR )
/* They forgot to leave room for the EOB's. */
return 0;
b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state ) );
if ( ! b )
YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" );
b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */
b->yy_buf_pos = b->yy_ch_buf = base;
b->yy_is_our_buffer = 0;
b->yy_input_file = 0;
b->yy_n_chars = b->yy_buf_size;
b->yy_is_interactive = 0;
b->yy_at_bol = 1;
b->yy_fill_buffer = 0;
b->yy_buffer_status = YY_BUFFER_NEW;
yy_switch_to_buffer(b );
return b;
}
/** Setup the input buffer state to scan a string. The next call to yylex() will
* scan from a @e copy of @a str.
* @param yystr a NUL-terminated string to scan
*
* @return the newly allocated buffer state object.
* @note If you want to scan bytes that may contain NUL values, then use
* yy_scan_bytes() instead.
*/
YY_BUFFER_STATE yy_scan_string (yyconst char * yystr )
{
return yy_scan_bytes(yystr,strlen(yystr) );
}
/** Setup the input buffer state to scan the given bytes. The next call to yylex() will
* scan from a @e copy of @a bytes.
* @param yybytes the byte buffer to scan
* @param _yybytes_len the number of bytes in the buffer pointed to by @a bytes.
*
* @return the newly allocated buffer state object.
*/
YY_BUFFER_STATE yy_scan_bytes (yyconst char * yybytes, int _yybytes_len )
{
YY_BUFFER_STATE b;
char *buf;
yy_size_t n;
int i;
/* Get memory for full buffer, including space for trailing EOB's. */
n = _yybytes_len + 2;
buf = (char *) yyalloc(n );
if ( ! buf )
YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" );
for ( i = 0; i < _yybytes_len; ++i )
buf[i] = yybytes[i];
buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR;
b = yy_scan_buffer(buf,n );
if ( ! b )
YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" );
/* It's okay to grow etc. this buffer, and we should throw it
* away when we're done.
*/
b->yy_is_our_buffer = 1;
return b;
}
#ifndef YY_EXIT_FAILURE
#define YY_EXIT_FAILURE 2
#endif
static void yy_fatal_error (yyconst char* msg )
{
(void) fprintf( stderr, "%s\n", msg );
exit( YY_EXIT_FAILURE );
}
/* Redefine yyless() so it works in section 3 code. */
#undef yyless
#define yyless(n) \
do \
{ \
/* Undo effects of setting up yytext. */ \
int yyless_macro_arg = (n); \
YY_LESS_LINENO(yyless_macro_arg);\
yytext[yyleng] = (yy_hold_char); \
(yy_c_buf_p) = yytext + yyless_macro_arg; \
(yy_hold_char) = *(yy_c_buf_p); \
*(yy_c_buf_p) = '\0'; \
yyleng = yyless_macro_arg; \
} \
while ( 0 )
/* Accessor methods (get/set functions) to struct members. */
/** Get the current line number.
*
*/
int yyget_lineno (void)
{
return yylineno;
}
/** Get the input stream.
*
*/
FILE *yyget_in (void)
{
return yyin;
}
/** Get the output stream.
*
*/
FILE *yyget_out (void)
{
return yyout;
}
/** Get the length of the current token.
*
*/
int yyget_leng (void)
{
return yyleng;
}
/** Get the current token.
*
*/
char *yyget_text (void)
{
return yytext;
}
/** Set the current line number.
* @param line_number
*
*/
void yyset_lineno (int line_number )
{
yylineno = line_number;
}
/** Set the input stream. This does not discard the current
* input buffer.
* @param in_str A readable stream.
*
* @see yy_switch_to_buffer
*/
void yyset_in (FILE * in_str )
{
yyin = in_str ;
}
void yyset_out (FILE * out_str )
{
yyout = out_str ;
}
int yyget_debug (void)
{
return yy_flex_debug;
}
void yyset_debug (int bdebug )
{
yy_flex_debug = bdebug ;
}
static int yy_init_globals (void)
{
/* Initialization is the same as for the non-reentrant scanner.
* This function is called from yylex_destroy(), so don't allocate here.
*/
(yy_buffer_stack) = 0;
(yy_buffer_stack_top) = 0;
(yy_buffer_stack_max) = 0;
(yy_c_buf_p) = (char *) 0;
(yy_init) = 0;
(yy_start) = 0;
/* Defined in main.c */
#ifdef YY_STDINIT
yyin = stdin;
yyout = stdout;
#else
yyin = (FILE *) 0;
yyout = (FILE *) 0;
#endif
/* For future reference: Set errno on error, since we are called by
* yylex_init()
*/
return 0;
}
/* yylex_destroy is for both reentrant and non-reentrant scanners. */
int yylex_destroy (void)
{
/* Pop the buffer stack, destroying each element. */
while(YY_CURRENT_BUFFER){
yy_delete_buffer(YY_CURRENT_BUFFER );
YY_CURRENT_BUFFER_LVALUE = NULL;
yypop_buffer_state();
}
/* Destroy the stack itself. */
yyfree((yy_buffer_stack) );
(yy_buffer_stack) = NULL;
/* Reset the globals. This is important in a non-reentrant scanner so the next time
* yylex() is called, initialization will occur. */
yy_init_globals( );
return 0;
}
/*
* Internal utility routines.
*/
#ifndef yytext_ptr
static void yy_flex_strncpy (char* s1, yyconst char * s2, int n )
{
register int i;
for ( i = 0; i < n; ++i )
s1[i] = s2[i];
}
#endif
#ifdef YY_NEED_STRLEN
static int yy_flex_strlen (yyconst char * s )
{
register int n;
for ( n = 0; s[n]; ++n )
;
return n;
}
#endif
void *yyalloc (yy_size_t size )
{
return (void *) malloc( size );
}
void *yyrealloc (void * ptr, yy_size_t size )
{
/* The cast to (char *) in the following accommodates both
* implementations that use char* generic pointers, and those
* that use void* generic pointers. It works with the latter
* because both ANSI C and C++ allow castless assignment from
* any pointer type to void*, and deal with argument conversions
* as though doing an assignment.
*/
return (void *) realloc( (char *) ptr, size );
}
void yyfree (void * ptr )
{
free( (char *) ptr ); /* see yyrealloc() for (char *) cast */
}
#define YYTABLES_NAME "yytables"
#line 221 "cf3lex.l"
/* EOF */
cfengine-3.2.4/src/monitor.c 0000644 0001750 0001750 00000015645 11715232734 012661 0000000 0000000 /*
Copyright (C) Cfengine AS
This file is part of Cfengine 3 - written and maintained by Cfengine 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 Commerical Open Source License
(COSL) may apply to this file if you as a licensee so wish it. See
included file COSL.txt.
*/
/*****************************************************************************/
/* */
/* File: monitor.c */
/* */
/*****************************************************************************/
#include "cf3.defs.h"
#include "cf3.extern.h"
/*****************************************************************************/
/* Globals */
/*****************************************************************************/
extern int NO_FORK;
extern struct BodySyntax CFM_CONTROLBODY[];
/*******************************************************************/
/* Command line options */
/*******************************************************************/
const char *ID = "The monitoring agent is a machine-learning, sampling\n"
"daemon which learns the normal state of the current\n"
"host and classifies new observations in terms of the\n"
"patterns formed by previous ones. The data are made\n"
"available to and read by cf-agent for classification\n"
"of responses to anomalous states.";
const struct option OPTIONS[14] =
{
{ "help",no_argument,0,'h' },
{ "debug",optional_argument,0,'d' },
{ "verbose",no_argument,0,'v' },
{ "dry-run",no_argument,0,'n'},
{ "version",no_argument,0,'V' },
{ "no-lock",no_argument,0,'K'},
{ "file",required_argument,0,'f'},
{ "inform",no_argument,0,'I'},
{ "diagnostic",no_argument,0,'x'},
{ "no-fork",no_argument,0,'F'},
{ "histograms",no_argument,0,'H'},
{ "tcpdump",no_argument,0,'T'},
{ NULL,0,0,'\0' }
};
const char *HINTS[14] =
{
"Print the help message",
"Set debugging level 0,1,2,3",
"Output verbose information about the behaviour of the agent",
"All talk and no action mode - make no changes, only inform of promises not kept",
"Output the version of the software",
"Ignore system lock",
"Specify an alternative input file than the default",
"Print basic information about changes made to the system, i.e. promises repaired",
"Activate internal diagnostics (developers only)",
"Run process in foreground, not as a daemon",
"Ignored for backward compatibility",
"Interface with tcpdump if available to collect data about network",
NULL
};
/*****************************************************************************/
int main(int argc,char *argv[])
{
CheckOpts(argc,argv);
GenericInitialize(argc,argv,"monitor");
ThisAgentInit();
KeepPromises();
StartServer(argc,argv);
return 0;
}
/*******************************************************************/
void CheckOpts(int argc,char **argv)
{
extern char *optarg;
int optindex = 0;
int c;
while ((c=getopt_long(argc,argv,"d:vnIf:VSxHTKMF",OPTIONS,&optindex)) != EOF)
{
switch ((char) c)
{
case 'f':
strncpy(VINPUTFILE,optarg,CF_BUFSIZE-1);
VINPUTFILE[CF_BUFSIZE-1] = '\0';
MINUSF = true;
break;
case 'd':
NewClass("opt_debug");
switch ((optarg==NULL) ? '3' : *optarg)
{
case '1':
D1 = true;
DEBUG = true;
break;
case '2':
D2 = true;
DEBUG = true;
break;
default:
DEBUG = true;
break;
}
NO_FORK = true;
break;
case 'K': IGNORELOCK = true;
break;
case 'I': INFORM = true;
break;
case 'v': VERBOSE = true;
NO_FORK = true;
break;
case 'F': NO_FORK = true;
break;
case 'H': /* Keep accepting this option for compatibility -- no longer used */
break;
case 'T': MonNetworkSnifferEnable(true);
break;
case 'V': PrintVersionBanner("cf-monitord");
exit(0);
case 'h': Syntax("cf-monitord - cfengine's monitoring agent",OPTIONS,HINTS,ID);
exit(0);
case 'M': ManPage("cf-monitord - cfengine's monitoring agent",OPTIONS,HINTS,ID);
exit(0);
case 'x': SelfDiagnostic();
exit(0);
default: Syntax("cf-monitord - cfengine's monitoring agent",OPTIONS,HINTS,ID);
exit(1);
}
}
Debug("Set debugging\n");
}
/*****************************************************************************/
void KeepPromises(void)
{
struct Constraint *cp;
char rettype;
void *retval;
for (cp = ControlBodyConstraints(cf_monitor); cp != NULL; cp=cp->next)
{
if (IsExcluded(cp->classes))
{
continue;
}
if (GetVariable("control_monitor",cp->lval,&retval,&rettype) == cf_notype)
{
CfOut(cf_error,"","Unknown lval %s in monitor control body",cp->lval);
continue;
}
if (strcmp(cp->lval,CFM_CONTROLBODY[cfm_histograms].lval) == 0)
{
/* Keep accepting this option for backward compatibility. */
}
if (strcmp(cp->lval,CFM_CONTROLBODY[cfm_tcpdump].lval) == 0)
{
MonNetworkSnifferEnable(GetBoolean(retval));
}
if (strcmp(cp->lval,CFM_CONTROLBODY[cfm_forgetrate].lval) == 0)
{
sscanf(retval,"%lf",&FORGETRATE);
Debug("forget rate = %f\n",FORGETRATE);
}
}
}
/*****************************************************************************/
/* Level 1 */
/*****************************************************************************/
void ThisAgentInit(void)
{
umask(077);
sprintf(VPREFIX, "cf-monitord");
LOGGING = true; /* Do output to syslog */
SetReferenceTime(false);
SetStartTime(false);
signal(SIGINT,HandleSignals);
signal(SIGTERM,HandleSignals);
signal(SIGHUP,SIG_IGN);
signal(SIGPIPE,SIG_IGN);
signal(SIGCHLD,SIG_IGN);
signal(SIGUSR1,HandleSignals);
signal(SIGUSR2,HandleSignals);
FORGETRATE = 0.6;
MonInitialize();
}
cfengine-3.2.4/src/agent.c 0000644 0001750 0001750 00000104514 11715232734 012262 0000000 0000000 /*
Copyright (C) Cfengine AS
This file is part of Cfengine 3 - written and maintained by Cfengine 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 Commerical Open Source License
(COSL) may apply to this file if you as a licensee so wish it. See
included file COSL.txt.
*/
/*****************************************************************************/
/* */
/* File: agent.c */
/* */
/*****************************************************************************/
#include "cf3.defs.h"
#include "cf3.extern.h"
/*******************************************************************/
/* Agent specific variables */
/*******************************************************************/
enum typesequence
{
kp_vars,
kp_classes,
kp_outputs,
kp_interfaces,
kp_files,
kp_packages,
kp_environments,
kp_methods,
kp_processes,
kp_services,
kp_commands,
kp_storage,
kp_databases,
kp_reports,
kp_none
};
char *TYPESEQUENCE[] =
{
"vars",
"classes", /* Maelstrom order 2 */
"outputs",
"interfaces",
"files",
"packages",
"environments",
"methods",
"processes",
"services",
"commands",
"storage",
"databases",
"reports",
NULL
};
int main (int argc,char *argv[]);
void CheckAgentAccess(struct Rlist *list);
void KeepAgentPromise(struct Promise *pp);
int NewTypeContext(enum typesequence type);
void DeleteTypeContext(enum typesequence type);
void ClassBanner(enum typesequence type);
void ParallelFindAndVerifyFilesPromises(struct Promise *pp);
static bool VerifyBootstrap(void);
extern struct BodySyntax CFA_CONTROLBODY[];
extern struct Rlist *SERVERLIST;
/*******************************************************************/
/* Command line options */
/*******************************************************************/
const char *ID = "The main Cfengine agent is the instigator of change\n"
"in the system. In that sense it is the most important\n"
"part of the Cfengine suite.\n";
const struct option OPTIONS[15] =
{
{ "bootstrap",no_argument,0,'B' },
{ "bundlesequence",required_argument,0,'b' },
{ "debug",optional_argument,0,'d' },
{ "define",required_argument,0,'D' },
{ "diagnostic",optional_argument,0,'x'},
{ "dry-run",no_argument,0,'n'},
{ "file",required_argument,0,'f'},
{ "help",no_argument,0,'h' },
{ "inform",no_argument,0,'I'},
{ "negate",required_argument,0,'N' },
{ "no-lock",no_argument,0,'K'},
{ "policy-server",required_argument,0,'s' },
{ "verbose",no_argument,0,'v' },
{ "version",no_argument,0,'V' },
{ NULL,0,0,'\0' }
};
const char *HINTS[15] =
{
"Bootstrap/repair a cfengine configuration from failsafe file in the WORKDIR else in current directory",
"Set or override bundlesequence from command line",
"Set debugging level 0,1,2",
"Define a list of comma separated classes to be defined at the start of execution",
"Do internal diagnostic (developers only) level in optional argument",
"All talk and no action mode - make no changes, only inform of promises not kept",
"Specify an alternative input file than the default",
"Print the help message",
"Print basic information about changes made to the system, i.e. promises repaired",
"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",
"Define the server name or IP address of the a policy server (for use with bootstrap)",
"Output verbose information about the behaviour of the agent",
"Output the version of the software",
NULL
};
/*******************************************************************/
int main(int argc,char *argv[])
{
int ret = 0;
CheckOpts(argc,argv);
GenericInitialize(argc,argv,"agent");
ThisAgentInit();
KeepPromises();
NoteClassUsage(VHEAP);
#ifdef HAVE_NOVA
Nova_NoteVarUsageDB();
#endif
PurgeLocks();
if(BOOTSTRAP && !VerifyBootstrap())
{
ret = 1;
}
GenericDeInitialize();
return ret;
}
/*******************************************************************/
/* Level 1 */
/*******************************************************************/
void CheckOpts(int argc,char **argv)
{ extern char *optarg;
char arg[CF_BUFSIZE],*sp;
int optindex = 0;
int c,alpha = false,v6 = false;
/* Because of the MacOS linker we have to call this from each agent
individually before Generic Initialize */
POLICY_SERVER[0] = '\0';
while ((c=getopt_long(argc,argv,"rd:vnKIf:D:N:Vs:x:MBb:",OPTIONS,&optindex)) != EOF)
{
switch ((char) c)
{
case 'f':
if (optarg == NULL)
{
FatalError(" -f used but no argument");
}
if (optarg && strlen(optarg) < 5)
{
snprintf(arg,CF_MAXVARSIZE," -f used but argument \"%s\" incorrect",optarg);
FatalError(arg);
}
strncpy(VINPUTFILE,optarg,CF_BUFSIZE-1);
MINUSF = true;
break;
case 'b':
if (optarg)
{
CBUNDLESEQUENCE = SplitStringAsRList(optarg,',');
CBUNDLESEQUENCE_STR = optarg;
}
break;
case 'd':
NewClass("opt_debug");
switch ((optarg==NULL) ? '3' : *optarg)
{
case '1':
D1 = true;
DEBUG = true;
break;
case '2':
D2 = true;
DEBUG = true;
break;
default:
DEBUG = true;
break;
}
break;
case 'B':
BOOTSTRAP = true;
MINUSF = true;
IGNORELOCK = true;
NewClass("bootstrap_mode");
break;
case 's':
// temporary assure that network functions are working
OpenNetwork();
strncpy(POLICY_SERVER,Hostname2IPString(optarg),CF_BUFSIZE-1);
CloseNetwork();
for (sp = POLICY_SERVER; *sp != '\0'; sp++)
{
if (isalpha(*sp))
{
alpha = true;
}
if (ispunct(*sp) && *sp != ':' && *sp != '.')
{
alpha = true;
}
if (*sp == ':')
{
v6 = true;
}
}
if (alpha && !v6)
{
FatalError("Error specifying policy server. The policy server's IP address could not be looked up. Please use the IP address instead if there is no error.");
}
break;
case 'K':
IGNORELOCK = true;
break;
case 'D': NewClassesFromString(optarg);
break;
case 'N': NegateClassesFromString(optarg,&VNEGHEAP);
break;
case 'I': INFORM = true;
break;
case 'v': VERBOSE = true;
break;
case 'n': DONTDO = true;
IGNORELOCK = true;
NewClass("opt_dry_run");
break;
case 'V':
PrintVersionBanner("cf-agent");
exit(0);
case 'h':
Syntax("cf-agent - cfengine's change agent",OPTIONS,HINTS,ID);
exit(0);
case 'M':
ManPage("cf-agent - cfengine's change agent",OPTIONS,HINTS,ID);
exit(0);
case 'x':
AgentDiagnostic(optarg);
exit(0);
case 'r':
SHOWREPORTS = true;
break;
default: Syntax("cf-agent - cfengine's change agent",OPTIONS,HINTS,ID);
exit(1);
}
}
if (argv[optind] != NULL)
{
CfOut(cf_error,"","Unexpected argument with no preceding option: %s\n",argv[optind]);
FatalError("Aborted");
}
Debug("Set debugging\n");
}
/*******************************************************************/
void ThisAgentInit()
{ FILE *fp;
char filename[CF_BUFSIZE];
#ifdef HAVE_SETSID
CfOut(cf_verbose,""," -> Immunizing against parental death");
setsid();
#endif
signal(SIGINT,HandleSignals);
signal(SIGTERM,HandleSignals);
signal(SIGHUP,SIG_IGN);
signal(SIGPIPE,SIG_IGN);
signal(SIGUSR1,HandleSignals);
signal(SIGUSR2,HandleSignals);
CFA_MAXTHREADS = 30;
EDITFILESIZE = 100000;
/*
do not set signal(SIGCHLD,SIG_IGN) in agent near
popen() - or else pclose will fail to return
status which we need for setting returns
*/
snprintf(filename,CF_BUFSIZE,"%s/cfagent.%s.log",CFWORKDIR,VSYSNAME.nodename);
MapName(filename);
if ((fp = fopen(filename,"a")) != NULL)
{
fclose(fp);
}
}
/*******************************************************************/
void KeepPromises()
{ double efficiency;
BeginAudit();
KeepControlPromises();
KeepPromiseBundles();
EndAudit();
// TOPICS counts the number of currently defined promises
// OCCUR counts the number of objects touched while verifying config
efficiency = 100.0*CF_OCCUR/(double)(CF_OCCUR+CF_TOPICS);
NoteEfficiency(efficiency);
CfOut(cf_verbose,""," -> Checked %d objects with %d promises, efficiency %.2lf",CF_OCCUR,CF_TOPICS,efficiency);
}
/*******************************************************************/
/* Level 2 */
/*******************************************************************/
void KeepControlPromises()
{ struct Constraint *cp;
char rettype;
void *retval;
struct Rlist *rp;
for (cp = ControlBodyConstraints(cf_agent); cp != NULL; cp=cp->next)
{
if (IsExcluded(cp->classes))
{
continue;
}
if (GetVariable("control_common",cp->lval,&retval,&rettype) != cf_notype)
{
/* Already handled in generic_agent */
continue;
}
if (GetVariable("control_agent",cp->lval,&retval,&rettype) == cf_notype)
{
CfOut(cf_error,"","Unknown lval %s in agent control body",cp->lval);
continue;
}
if (strcmp(cp->lval,CFA_CONTROLBODY[cfa_maxconnections].lval) == 0)
{
CFA_MAXTHREADS = (int)Str2Int(retval);
CfOut(cf_verbose,"","SET maxconnections = %d\n",CFA_MAXTHREADS);
continue;
}
if (strcmp(cp->lval,CFA_CONTROLBODY[cfa_checksum_alert_time].lval) == 0)
{
CF_PERSISTENCE = (int)Str2Int(retval);
CfOut(cf_verbose,"","SET checksum_alert_time = %d\n",CF_PERSISTENCE);
continue;
}
if (strcmp(cp->lval,CFA_CONTROLBODY[cfa_agentfacility].lval) == 0)
{
SetFacility(retval);
continue;
}
if (strcmp(cp->lval,CFA_CONTROLBODY[cfa_agentaccess].lval) == 0)
{
ACCESSLIST = (struct Rlist *) retval;
CheckAgentAccess(ACCESSLIST);
continue;
}
if (strcmp(cp->lval,CFA_CONTROLBODY[cfa_refresh_processes].lval) == 0)
{
struct Rlist *rp;
if (VERBOSE)
{
printf("%s> SET refresh_processes when starting: ",VPREFIX);
for (rp = (struct Rlist *) retval; rp != NULL; rp = rp->next)
{
printf(" %s",(char *)rp->item);
PrependItem(&PROCESSREFRESH,rp->item,NULL);
}
printf("\n");
}
continue;
}
if (strcmp(cp->lval,CFA_CONTROLBODY[cfa_abortclasses].lval) == 0)
{
struct Rlist *rp;
CfOut(cf_verbose,"","SET Abort classes from ...\n");
for (rp = (struct Rlist *) retval; rp != NULL; rp = rp->next)
{
char name[CF_MAXVARSIZE] = "";
strncpy(name, rp->item, CF_MAXVARSIZE - 1);
CanonifyNameInPlace(name);
if (!IsItemIn(ABORTHEAP,name))
{
AppendItem(&ABORTHEAP,name,cp->classes);
}
}
continue;
}
if (strcmp(cp->lval,CFA_CONTROLBODY[cfa_abortbundleclasses].lval) == 0)
{
struct Rlist *rp;
CfOut(cf_verbose,"","SET Abort bundle classes from ...\n");
for (rp = (struct Rlist *) retval; rp != NULL; rp = rp->next)
{
char name[CF_MAXVARSIZE] = "";
strncpy(name, rp->item, CF_MAXVARSIZE - 1);
CanonifyNameInPlace(name);
if (!IsItemIn(ABORTBUNDLEHEAP,name))
{
AppendItem(&ABORTBUNDLEHEAP,name,cp->classes);
}
}
continue;
}
if (strcmp(cp->lval,CFA_CONTROLBODY[cfa_addclasses].lval) == 0)
{
struct Rlist *rp;
CfOut(cf_verbose,"","-> Add classes ...\n");
for (rp = (struct Rlist *) retval; rp != NULL; rp = rp->next)
{
CfOut(cf_verbose,""," -> ... %s\n",rp->item);
NewClass(rp->item);
}
continue;
}
if (strcmp(cp->lval,CFA_CONTROLBODY[cfa_auditing].lval) == 0)
{
AUDIT = GetBoolean(retval);
CfOut(cf_verbose,"","SET auditing = %d\n",AUDIT);
continue;
}
if (strcmp(cp->lval,CFA_CONTROLBODY[cfa_alwaysvalidate].lval) == 0)
{
ALWAYS_VALIDATE = GetBoolean(retval);
CfOut(cf_verbose,"","SET alwaysvalidate = %d\n",ALWAYS_VALIDATE);
continue;
}
if (strcmp(cp->lval,CFA_CONTROLBODY[cfa_secureinput].lval) == 0)
{
CFPARANOID = GetBoolean(retval);
CfOut(cf_verbose,"","SET secure input = %d\n",CFPARANOID);
continue;
}
if (strcmp(cp->lval,CFA_CONTROLBODY[cfa_binarypaddingchar].lval) == 0)
{
PADCHAR = *(char *)retval;
CfOut(cf_verbose,"","SET binarypaddingchar = %c\n",PADCHAR);
continue;
}
if (strcmp(cp->lval,CFA_CONTROLBODY[cfa_bindtointerface].lval) == 0)
{
strncpy(BINDINTERFACE,retval,CF_BUFSIZE-1);
CfOut(cf_verbose,"","SET bindtointerface = %s\n",BINDINTERFACE);
continue;
}
if (strcmp(cp->lval,CFA_CONTROLBODY[cfa_hashupdates].lval) == 0)
{
CHECKSUMUPDATES = GetBoolean(retval);
CfOut(cf_verbose,"","SET ChecksumUpdates %d\n",CHECKSUMUPDATES);
continue;
}
if (strcmp(cp->lval,CFA_CONTROLBODY[cfa_exclamation].lval) == 0)
{
EXCLAIM = GetBoolean(retval);
CfOut(cf_verbose,"","SET exclamation %d\n",EXCLAIM);
continue;
}
if (strcmp(cp->lval,CFA_CONTROLBODY[cfa_childlibpath].lval) == 0)
{
char output[CF_BUFSIZE];
snprintf(output,CF_BUFSIZE,"LD_LIBRARY_PATH=%s",(char *)retval);
if (putenv(strdup(output)) == 0)
{
CfOut(cf_verbose,"","Setting %s\n",output);
}
continue;
}
if (strcmp(cp->lval,CFA_CONTROLBODY[cfa_defaultcopytype].lval) == 0)
{
DEFAULT_COPYTYPE = (char *)retval;
CfOut(cf_verbose,"","SET defaultcopytype = %c\n",DEFAULT_COPYTYPE);
continue;
}
if (strcmp(cp->lval,CFA_CONTROLBODY[cfa_fsinglecopy].lval) == 0)
{
SINGLE_COPY_LIST = (struct Rlist *)retval;
CfOut(cf_verbose,"","SET file single copy list\n");
continue;
}
if (strcmp(cp->lval,CFA_CONTROLBODY[cfa_fautodefine].lval) == 0)
{
AUTO_DEFINE_LIST = (struct Rlist *)retval;
CfOut(cf_verbose,"","SET file auto define list\n");
continue;
}
if (strcmp(cp->lval,CFA_CONTROLBODY[cfa_dryrun].lval) == 0)
{
DONTDO = GetBoolean(retval);
CfOut(cf_verbose,"","SET dryrun = %c\n",DONTDO);
continue;
}
if (strcmp(cp->lval,CFA_CONTROLBODY[cfa_inform].lval) == 0)
{
INFORM = GetBoolean(retval);
CfOut(cf_verbose,"","SET inform = %c\n",INFORM);
continue;
}
if (strcmp(cp->lval,CFA_CONTROLBODY[cfa_verbose].lval) == 0)
{
VERBOSE = GetBoolean(retval);
CfOut(cf_verbose,"","SET inform = %c\n",VERBOSE);
continue;
}
if (strcmp(cp->lval,CFA_CONTROLBODY[cfa_repository].lval) == 0)
{
VREPOSITORY = strdup(retval);
CfOut(cf_verbose,"","SET repository = %s\n",VREPOSITORY);
continue;
}
if (strcmp(cp->lval,CFA_CONTROLBODY[cfa_skipidentify].lval) == 0)
{
SKIPIDENTIFY = GetBoolean(retval);
CfOut(cf_verbose,"","SET skipidentify = %d\n",SKIPIDENTIFY);
continue;
}
if (strcmp(cp->lval,CFA_CONTROLBODY[cfa_suspiciousnames].lval) == 0)
{
for (rp = (struct Rlist *) retval; rp != NULL; rp = rp->next)
{
PrependItem(&SUSPICIOUSLIST,rp->item,NULL);
CfOut(cf_verbose,"", "-> Concidering %s as suspicious file", rp->item);
}
continue;
}
if (strcmp(cp->lval,CFA_CONTROLBODY[cfa_repchar].lval) == 0)
{
REPOSCHAR = *(char *)retval;
CfOut(cf_verbose,"","SET repchar = %c\n",REPOSCHAR);
continue;
}
if (strcmp(cp->lval,CFA_CONTROLBODY[cfa_mountfilesystems].lval) == 0)
{
CF_MOUNTALL = GetBoolean(retval);
CfOut(cf_verbose,"","SET mountfilesystems = %d\n",CF_MOUNTALL);
continue;
}
if (strcmp(cp->lval,CFA_CONTROLBODY[cfa_editfilesize].lval) == 0)
{
EDITFILESIZE = Str2Int(retval);
CfOut(cf_verbose,"","SET EDITFILESIZE = %d\n",EDITFILESIZE);
continue;
}
if (strcmp(cp->lval,CFA_CONTROLBODY[cfa_ifelapsed].lval) == 0)
{
VIFELAPSED = Str2Int(retval);
CfOut(cf_verbose,"","SET ifelapsed = %d\n",VIFELAPSED);
continue;
}
if (strcmp(cp->lval,CFA_CONTROLBODY[cfa_expireafter].lval) == 0)
{
VEXPIREAFTER = Str2Int(retval);
CfOut(cf_verbose,"","SET ifelapsed = %d\n",VEXPIREAFTER);
continue;
}
if (strcmp(cp->lval,CFA_CONTROLBODY[cfa_timeout].lval) == 0)
{
CONNTIMEOUT = Str2Int(retval);
CfOut(cf_verbose,"","SET timeout = %d\n",CONNTIMEOUT);
continue;
}
if (strcmp(cp->lval,CFA_CONTROLBODY[cfa_max_children].lval) == 0)
{
CFA_BACKGROUND_LIMIT = Str2Int(retval);
CfOut(cf_verbose,"","SET MAX_CHILDREN = %d\n",CFA_BACKGROUND_LIMIT);
if (CFA_BACKGROUND_LIMIT > 10)
{
CfOut(cf_error,"","Silly value for max_children in agent control promise (%d > 10)",CFA_BACKGROUND_LIMIT);
CFA_BACKGROUND_LIMIT = 1;
}
continue;
}
if (strcmp(cp->lval,CFA_CONTROLBODY[cfa_syslog].lval) == 0)
{
LOGGING = GetBoolean(retval);
CfOut(cf_verbose,"","SET syslog = %d\n",LOGGING);
continue;
}
if (strcmp(cp->lval,CFA_CONTROLBODY[cfa_environment].lval) == 0)
{
struct Rlist *rp;
CfOut(cf_verbose,"","SET environment variables from ...\n");
for (rp = (struct Rlist *) retval; rp != NULL; rp = rp->next)
{
if (putenv(rp->item) != 0)
{
CfOut(cf_error, "putenv", "Failed to set environment variable %s", rp->item);
}
}
continue;
}
}
if (GetVariable("control_common",CFG_CONTROLBODY[cfg_lastseenexpireafter].lval,&retval,&rettype) != cf_notype)
{
LASTSEENEXPIREAFTER = Str2Int(retval);
}
if (GetVariable("control_common",CFG_CONTROLBODY[cfg_fips_mode].lval,&retval,&rettype) != cf_notype)
{
FIPS_MODE = GetBoolean(retval);
CfOut(cf_verbose,"","SET FIPS_MODE = %d\n",FIPS_MODE);
}
if (GetVariable("control_common",CFG_CONTROLBODY[cfg_syslog_port].lval,&retval,&rettype) != cf_notype)
{
SYSLOGPORT = (unsigned short)Str2Int(retval);
CfOut(cf_verbose,"","SET syslog_port to %d",SYSLOGPORT);
}
if (GetVariable("control_common",CFG_CONTROLBODY[cfg_syslog_host].lval,&retval,&rettype) != cf_notype)
{
strncpy(SYSLOGHOST,Hostname2IPString(retval),CF_MAXVARSIZE-1);
CfOut(cf_verbose,"","SET syslog_host to %s",SYSLOGHOST);
}
#ifdef HAVE_NOVA
Nova_Initialize();
#endif
}
/*********************************************************************/
void KeepPromiseBundles()
{ struct Bundle *bp;
struct Rlist *rp,*params;
struct FnCall *fp;
char rettype,*name;
void *retval;
int ok = true;
if (CBUNDLESEQUENCE)
{
CfOut(cf_inform,""," >> Using command line specified bundlesequence");
retval = CBUNDLESEQUENCE;
rettype = CF_LIST;
}
else if (GetVariable("control_common","bundlesequence",&retval,&rettype) == cf_notype)
{
CfOut(cf_error,""," !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
CfOut(cf_error,""," !! No bundlesequence in the common control body");
CfOut(cf_error,""," !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
exit(1);
}
if (rettype != CF_LIST)
{
FatalError("Promised bundlesequence was not a list");
}
for (rp = (struct Rlist *)retval; rp != NULL; rp=rp->next)
{
switch (rp->type)
{
case CF_SCALAR:
name = (char *)rp->item;
params = NULL;
if (strcmp(name,CF_NULL_VALUE) == 0)
{
continue;
}
break;
case CF_FNCALL:
fp = (struct FnCall *)rp->item;
name = (char *)fp->name;
params = (struct Rlist *)fp->args;
break;
default:
name = NULL;
params = NULL;
CfOut(cf_error,"","Illegal item found in bundlesequence: ");
ShowRval(stdout,rp->item,rp->type);
printf(" = %c\n",rp->type);
ok = false;
break;
}
if (!IGNORE_MISSING_BUNDLES)
{
if (!(GetBundle(name,"agent")||(GetBundle(name,"common"))))
{
CfOut(cf_error,"","Bundle \"%s\" listed in the bundlesequence was not found\n",name);
ok = false;
}
}
}
if (!ok)
{
FatalError("Errors in agent bundles");
}
if (VERBOSE || DEBUG)
{
printf("%s> -> Bundlesequence => ",VPREFIX);
ShowRval(stdout,retval,rettype);
printf("\n");
}
/* If all is okay, go ahead and evaluate */
for (rp = (struct Rlist *)retval; rp != NULL; rp=rp->next)
{
switch (rp->type)
{
case CF_FNCALL:
fp = (struct FnCall *)rp->item;
name = (char *)fp->name;
params = (struct Rlist *)fp->args;
break;
default:
name = (char *)rp->item;
params = NULL;
break;
}
if ((bp = GetBundle(name,"agent")) || (bp = GetBundle(name,"common")))
{
SetBundleOutputs(bp->name);
AugmentScope(bp->name,bp->args,params);
BannerBundle(bp,params);
THIS_BUNDLE = bp->name;
DeletePrivateClassContext(); // Each time we change bundle
ScheduleAgentOperations(bp);
ResetBundleOutputs(bp->name);
}
}
}
/*********************************************************************/
/* Level 3 */
/*********************************************************************/
int ScheduleAgentOperations(struct Bundle *bp)
{ struct SubType *sp;
struct Promise *pp;
enum typesequence type;
int pass;
if (PROCESSREFRESH == NULL || (PROCESSREFRESH && IsRegexItemIn(PROCESSREFRESH,bp->name)))
{
DeleteItemList(PROCESSTABLE);
PROCESSTABLE = NULL;
}
for (pass = 1; pass < CF_DONEPASSES; pass++)
{
for (type = 0; TYPESEQUENCE[type] != NULL; type++)
{
ClassBanner(type);
if ((sp = GetSubTypeForBundle(TYPESEQUENCE[type],bp)) == NULL)
{
continue;
}
BannerSubType(bp->name,sp->name,pass);
SetScope(bp->name);
if (!NewTypeContext(type))
{
continue;
}
for (pp = sp->promiselist; pp != NULL; pp=pp->next)
{
SaveClassEnvironment();
ExpandPromise(cf_agent,bp->name,pp,KeepAgentPromise);
if (Abort())
{
NoteClassUsage(VADDCLASSES);
DeleteTypeContext(type);
return false;
}
}
DeleteTypeContext(type);
}
}
NoteClassUsage(VADDCLASSES);
return true;
}
/*********************************************************************/
void CheckAgentAccess(struct Rlist *list)
#ifdef MINGW
{
}
#else /* NOT MINGW */
{
struct Rlist *rp,*rp2;
struct stat sb;
uid_t uid;
int access = false;
uid = getuid();
for (rp = list; rp != NULL; rp = rp->next)
{
if (Str2Uid(rp->item,NULL,NULL) == uid)
{
return;
}
}
if (VINPUTLIST != NULL)
{
for (rp = VINPUTLIST; rp != NULL; rp=rp->next)
{
cfstat(rp->item,&sb);
if (ACCESSLIST)
{
for (rp2 = ACCESSLIST; rp2 != NULL; rp2 = rp2->next)
{
if (Str2Uid(rp2->item,NULL,NULL) == sb.st_uid)
{
access = true;
break;
}
}
if (!access)
{
CfOut(cf_error,"","File %s is not owned by an authorized user (security exception)",rp->item);
exit(1);
}
}
else if (CFPARANOID && IsPrivileged())
{
if (sb.st_uid != getuid())
{
CfOut(cf_error,"","File %s is not owned by uid %d (security exception)",rp->item,getuid());
exit(1);
}
}
}
}
FatalError("You are denied access to run this policy");
}
#endif /* NOT MINGW */
/*********************************************************************/
void KeepAgentPromise(struct Promise *pp)
{ char *sp = NULL;
struct timespec start = BeginMeasure();
if (!IsDefinedClass(pp->classes))
{
CfOut(cf_verbose,"","\n");
CfOut(cf_verbose,"",". . . . . . . . . . . . . . . . . . . . . . . . . . . . \n");
CfOut(cf_verbose,"","Skipping whole next promise (%s), as context %s is not relevant\n",pp->promiser,pp->classes);
CfOut(cf_verbose,"",". . . . . . . . . . . . . . . . . . . . . . . . . . . . \n");
return;
}
if (pp->done)
{
return;
}
if (VarClassExcluded(pp,&sp))
{
CfOut(cf_verbose,"","\n");
CfOut(cf_verbose,"",". . . . . . . . . . . . . . . . . . . . . . . . . . . . \n");
CfOut(cf_verbose,"","Skipping whole next promise (%s), as var-context %s is not relevant\n",pp->promiser,sp);
CfOut(cf_verbose,"",". . . . . . . . . . . . . . . . . . . . . . . . . . . . \n");
return;
}
// Record promises examined for efficiency calc
CF_TOPICS++;
if (strcmp("vars",pp->agentsubtype) == 0)
{
ConvergeVarHashPromise(pp->bundle,pp,true);
return;
}
if (strcmp("classes",pp->agentsubtype) == 0)
{
KeepClassContextPromise(pp);
return;
}
if (strcmp("outputs",pp->agentsubtype) == 0)
{
VerifyOutputsPromise(pp);
return;
}
SetPromiseOutputs(pp);
if (strcmp("interfaces",pp->agentsubtype) == 0)
{
VerifyInterfacesPromise(pp);
return;
}
if (strcmp("processes",pp->agentsubtype) == 0)
{
VerifyProcessesPromise(pp);
return;
}
if (strcmp("storage",pp->agentsubtype) == 0)
{
FindAndVerifyStoragePromises(pp);
EndMeasurePromise(start,pp);
return;
}
if (strcmp("packages",pp->agentsubtype) == 0)
{
VerifyPackagesPromise(pp);
EndMeasurePromise(start,pp);
return;
}
if (strcmp("files",pp->agentsubtype) == 0)
{
if (GetBooleanConstraint("background",pp))
{
ParallelFindAndVerifyFilesPromises(pp);
}
else
{
FindAndVerifyFilesPromises(pp);
}
EndMeasurePromise(start,pp);
return;
}
if (strcmp("commands",pp->agentsubtype) == 0)
{
VerifyExecPromise(pp);
EndMeasurePromise(start,pp);
return;
}
if (strcmp("databases",pp->agentsubtype) == 0)
{
VerifyDatabasePromises(pp);
EndMeasurePromise(start,pp);
return;
}
if (strcmp("methods",pp->agentsubtype) == 0)
{
VerifyMethodsPromise(pp);
EndMeasurePromise(start,pp);
return;
}
if (strcmp("services",pp->agentsubtype) == 0)
{
VerifyServicesPromise(pp);
EndMeasurePromise(start,pp);
return;
}
if (strcmp("environments",pp->agentsubtype) == 0)
{
VerifyEnvironmentsPromise(pp);
EndMeasurePromise(start,pp);
return;
}
if (strcmp("reports",pp->agentsubtype) == 0)
{
VerifyReportPromise(pp);
return;
}
}
/*********************************************************************/
/* Type context */
/*********************************************************************/
int NewTypeContext(enum typesequence type)
{
// get maxconnections
switch(type)
{
case kp_environments:
#ifdef HAVE_NOVA
Nova_NewEnvironmentsContext();
#endif
break;
case kp_files:
SERVERLIST = NULL;
break;
case kp_processes:
if (!LoadProcessTable(&PROCESSTABLE))
{
CfOut(cf_error,"","Unable to read the process table - cannot keep process promises\n","");
return false;
}
break;
case kp_storage:
#ifndef MINGW // TODO: Run if implemented on Windows
if (MOUNTEDFSLIST != NULL)
{
DeleteMountInfo(MOUNTEDFSLIST);
MOUNTEDFSLIST = NULL;
}
#endif /* NOT MINGW */
break;
}
return true;
}
/*********************************************************************/
void DeleteTypeContext(enum typesequence type)
{ struct Rlist *rp;
struct ServerItem *svp;
struct Attributes a = {{0}};
switch(type)
{
case kp_classes:
HashVariables(THIS_BUNDLE);
break;
case kp_environments:
#ifdef HAVE_NOVA
Nova_DeleteEnvironmentsContext();
#endif
break;
case kp_files:
/* Cleanup shared connection array for non-threaded remote copies */
for (rp = SERVERLIST; rp != NULL; rp = rp->next)
{
svp = (struct ServerItem *)rp->item;
if (svp == NULL)
{
continue;
}
ServerDisconnection(svp->conn);
if (svp->server)
{
free(svp->server);
}
rp->item = NULL;
}
DeleteRlist(SERVERLIST);
SERVERLIST = NULL;
break;
case kp_processes:
break;
case kp_storage:
#ifndef MINGW
CfOut(cf_verbose,""," -> Number of changes observed in %s is %d\n",VFSTAB[VSYSTEMHARDCLASS],FSTAB_EDITS);
if (FSTAB_EDITS && FSTABLIST && !DONTDO)
{
if (FSTABLIST)
{
SaveItemListAsFile(FSTABLIST,VFSTAB[VSYSTEMHARDCLASS],a,NULL);
DeleteItemList(FSTABLIST);
FSTABLIST = NULL;
}
FSTAB_EDITS = 0;
}
if (!DONTDO && CF_MOUNTALL)
{
CfOut(cf_verbose,"","");
CfOut(cf_verbose,""," -> Mounting all filesystems\n");
MountAll();
CfOut(cf_verbose,"","");
}
#endif /* NOT MINGW */
break;
case kp_packages:
if (!DONTDO)
{
ExecuteScheduledPackages();
}
CleanScheduledPackages();
break;
}
}
/**************************************************************/
void ClassBanner(enum typesequence type)
{ struct Item *ip;
int i;
if (type != kp_interfaces) /* Just parsed all local classes */
{
return;
}
CfOut(cf_verbose,"","\n");
CfOut(cf_verbose,""," + Private classes augmented:\n");
for (i = 0; i < CF_ALPHABETSIZE; i++)
{
for (ip = VADDCLASSES.list[i]; ip != NULL; ip=ip->next)
{
CfOut(cf_verbose,""," + %s\n",ip->name);
}
}
CfOut(cf_verbose,"","\n");
CfOut(cf_verbose,""," - Private classes diminished:\n");
for (ip = VNEGHEAP; ip != NULL; ip=ip->next)
{
CfOut(cf_verbose,""," - %s\n",ip->name);
}
CfOut(cf_verbose,"","\n");
Debug(" ? Public class context:\n");
for (i = 0; i < CF_ALPHABETSIZE; i++)
{
for (ip = VHEAP.list[i]; ip != NULL; ip=ip->next)
{
Debug(" ? %s\n",ip->name);
}
}
CfOut(cf_verbose,"","\n");
}
/**************************************************************/
/* Thread context */
/**************************************************************/
void ParallelFindAndVerifyFilesPromises(struct Promise *pp)
{ pid_t child = 1;
int background = GetBooleanConstraint("background",pp);
#ifdef MINGW
if (background)
{
CfOut(cf_verbose, "", "Background processing of files promises is not supported on Windows");
}
FindAndVerifyFilesPromises(pp);
#else /* NOT MINGW */
if (background && (CFA_BACKGROUND < CFA_BACKGROUND_LIMIT))
{
CFA_BACKGROUND++;
CfOut(cf_verbose,"","Spawning new process...\n");
child = fork();
if (child == 0)
{
ALARM_PID = -1;
AM_BACKGROUND_PROCESS = true;
}
else
{
AM_BACKGROUND_PROCESS = false;
}
}
else if (CFA_BACKGROUND >= CFA_BACKGROUND_LIMIT)
{
CfOut(cf_verbose,""," !> Promised parallel execution promised but exceeded the max number of promised background tasks, so serializing");
}
if (child == 0 || !background)
{
FindAndVerifyFilesPromises(pp);
}
#endif /* NOT MINGW */
}
/**************************************************************/
static bool VerifyBootstrap(void)
{
struct stat sb;
char filePath[CF_MAXVARSIZE];
if(EMPTY(POLICY_SERVER))
{
CfOut(cf_error, "", "!! Bootstrapping failed, no policy server is specified");
return false;
}
// we should at least have gotten promises.cf from the policy hub
snprintf(filePath, sizeof(filePath), "%s/inputs/promises.cf", CFWORKDIR);
MapName(filePath);
if(cfstat(filePath, &sb) == -1)
{
CfOut(cf_error, "", "!! Bootstrapping failed, no input file at %s after bootstrap", filePath);
return false;
}
// embedded failsafe.cf (bootstrap.c) contains a promise to start cf-execd (executed while running this cf-agent)
DeleteItemList(PROCESSTABLE);
PROCESSTABLE = NULL;
LoadProcessTable(&PROCESSTABLE);
if(!IsProcessNameRunning(".*cf-execd.*"))
{
CfOut(cf_error, "", "!! Bootstrapping failed, cf-execd is not running");
return false;
}
CfOut(cf_cmdout, "", "-> Bootstrap to %s completed successfully", POLICY_SERVER);
return true;
}
cfengine-3.2.4/src/classes.c 0000644 0001750 0001750 00000053425 11715232734 012625 0000000 0000000 /*
Copyright (C) Cfengine AS
This file is part of Cfengine 3 - written and maintained by Cfengine 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 Commerical Open Source License
(COSL) may apply to this file if you as a licensee so wish it. See
included file COSL.txt.
*/
/*******************************************************************/
/* */
/* GLOBAL class default variables for cfengine */
/* These variables are what needs to be modified if you add or */
/* modify class definitions... remember also to change clsattr */
/* and search for the os types in cfengine.c (mount stuff) */
/* */
/*******************************************************************/
#include "cf3.defs.h"
#include "cf3.extern.h"
/*********************************************************************/
/* See also "enum classes" in cf.defs.h */
char *CLASSTEXT[] = /* If you change here change enum classes too! */
{
"",
"",
"sun4",
"ultrix",
"hpux",
"aix",
"linux",
"solaris",
"osf",
"digital",
"sun3",
"irix4",
"irix",
"irix64",
"freebsd",
"solarisx86",
"bsd4_3",
"newsos",
"netbsd",
"aos",
"bsdos",
"nextstep",
"cray",
"gnu",
"windows",
"unix_sv",
"openbsd",
"sco",
"darwin",
"ux4800",
"qnx",
"dragonfly",
"windows",
"vmware",
"unused1",
"unused2",
"unused3",
NULL
};
/*********************************************************************/
/* remember to change cf.defs.h !! */
char *CLASSATTRIBUTES[CF_CLASSATTR][CF_ATTRDIM] =
{
{"-","-","-"}, /* as appear here are matched. The */
{"-","-","-"}, /* fields are sysname and machine */
{"sunos",".*","4.*"}, /* sun 4 */
{"ultrix","risc","4.*"}, /* ultrix */
{"hp-ux",".*",".*"}, /* hpux */
{"aix",".*",".*"}, /* aix */
{"linux",".*",".*"}, /* linux */
{"sunos","sun4.*","5.*"}, /* solaris */
{"osf1","alpha",".*"}, /* osf1 */
{"osf1","alpha","4.*"}, /* digital */
{"sunos","sun3","4.*"}, /* sun3 */
{"irix4","ip.*","4.*"}, /* irix4 */
{"irix", "ip.*",".*"}, /* irix */
{"irix64","ip.*",".*"}, /* irix64 */
{"freebsd",".*",".*"}, /* freebsd */
{"sunos","i86pc","5.*"}, /* solarisx86 */
{"bsd",".*",".*"}, /* bsd 4.3 */
{"newsos",".*",".*"}, /* newsos4 */
{"netbsd",".*",".*"}, /* NetBSD */
{"aos",".*",".*"}, /* AOS */
{"bsd/os",".*",".*"}, /* BSDI */
{"nextstep",".*",".*"}, /* nextstep */
{"sn.*","cray*",".*"}, /* cray */
{"gnu.*",".*",".*"}, /* gnu */
{"cygwin_nt.*",".*",".*"}, /* NT (cygwin) */
{"unix_sv",".*",".*"}, /* Unixware */
{"openbsd",".*",".*"}, /* OpenBSD */
{"sco_sv",".*",".*"}, /* SCO */
{"darwin",".*",".*"}, /* Darwin, aka MacOS X */
{"ux4800",".*",".*"}, /* UX/4800 */
{"qnx",".*",".*"}, /* qnx */
{"dragonfly",".*",".*"}, /* dragonfly */
{"windows_nt.*",".*",".*"}, /* NT (native) */
{"vmkernel",".*",".*"}, /* VMWARE / ESX */
{"unused1","blah","blah"},
{"unused2","blah","blah"},
{"unused3","blah","blah"},
{NULL,NULL,NULL}
};
/*********************************************************************/
char *VPSCOMM[CF_CLASSATTR] =
{
"",
"",
"/bin/ps", /* sun 4 */
"/bin/ps", /* ultrix */
"/bin/ps", /* hpux */
"/bin/ps", /* aix */
"/bin/ps", /* linux */
"/bin/ps", /* solaris */
"/bin/ps", /* osf1 */
"/bin/ps", /* digital */
"/bin/ps", /* sun3 */
"/bin/ps", /* irix4 */
"/bin/ps", /* irix */
"/bin/ps", /* irix64 */
"/bin/ps", /* freebsd */
"/bin/ps", /* solarisx86 */
"/bin/ps", /* bsd 4.3 */
"/bin/ps", /* newos4 */
"/bin/ps", /* netbsd */
"/bin/ps", /* AOS */
"/bin/ps", /* BSDI */
"/bin/ps", /* nextstep */
"/bin/ps", /* cray */
"/bin/ps", /* gnu */
"/bin/ps", /* NT - cygnus */
"/bin/ps", /* unixware */
"/bin/ps", /* openbsd */
"/bin/ps", /* sco */
"/bin/ps", /* darwin */
"/bin/ps", /* ux4800 */
"/bin/ps", /* qnx */
"/bin/ps", /* dragonfly */
"mingw-invalid", /* mingw */
"/bin/ps", /* vmware */
"/bin/ps",
"/bin/ps",
"/bin/ps",
NULL
};
/*********************************************************************/
// linux after rhel 3: ps -eo user,pid,ppid,pgid,%cpu,%mem,vsize,ni,rss,stat,nlwp,stime,time,args
// solaris: ps -eo user,pid,ppid,pgid,pcpu,pmem,vsz,pri,rss,nlwp,stime,time,args
char *VPSOPTS[CF_CLASSATTR] =
{
"",
"",
"auxw", /* sun4 */
"auxw", /* ultrix */
"-ef", /* hpux */
"-eo user,pid,ppid,pgid,pcpu,pmem,vsz,ni,stat,stime,time,args", /* aix */
"-eo user,pid,ppid,pgid,pcpu,pmem,vsz,pri,rss,nlwp,stime,time,args", /* linux */
"-eo user,pid,ppid,pgid,pcpu,pmem,vsz,pri,rss,nlwp,stime,time,args", /* solaris */
"-ef", /* osf1 */
"auxw", /* digital */
"auxw", /* sun3 */
"-ef", /* irix4 */
"-ef", /* irix */
"-ef", /* irix64 */
"auxw", /* freebsd */
"-eo user,pid,ppid,pgid,pcpu,pmem,vsz,pri,rss,nlwp,stime,time,args", /* solarisx86 */
"-ax", /* bsd 4.3 */
"auxw", /* newsos4 */
"auxw", /* netbsd */
"auxw", /* AOS */
"auxw", /* BSDI */
"auxw", /* nextstep */
"-elyf", /* cray */
"auxw", /* gnu */
"-aW", /* NT */
"-ef", /* Unixware */
"auxw", /* openbsd */
"-ef", /* sco */
"auxw", /* darwin */
"-ef", /* ux4800 */
"-elyf", /* qnx */
"auxw", /* dragonfly */
"mingw-invalid", /* mingw */
"?", /* vmware*/
"-",
"-",
"-",
NULL
};
/*********************************************************************/
char *VMOUNTCOMM[CF_CLASSATTR] =
{
"", /* see cf.defs.h */
"",
"/etc/mount -va", /* sun4 */
"/etc/mount -va", /* ultrix */
"/sbin/mount -ea", /* hpux */
/*"/etc/mount -t nfs",*/ /* aix */
"/usr/sbin/mount -t nfs", /* aix */
"/bin/mount -va", /* linux */
"/usr/sbin/mount -a", /* solaris */
"/usr/sbin/mount -va", /* osf1 */
"/usr/sbin/mount -va", /* digital */
"/etc/mount -va", /* sun3 */
"/sbin/mount -va", /* irix4 */
"/sbin/mount -va", /* irix */
"/sbin/mount -va", /* irix64 */
"/sbin/mount -va", /* freebsd */
"/usr/sbin/mount -a", /* solarisx86 */
"/etc/mount -a", /* bsd 4.3 */
"/etc/mount -a", /* newsos4 */
"/sbin/mount -a", /* netbsd */
"/etc/mount -a", /* AOS */
"/sbin/mount -a", /* BSDI */
"/usr/etc/mount -a", /* nextstep */
"/etc/mount -va", /* cray */
"/bin/mount -va", /* gnu */
"/bin/sh /etc/fstab", /* NT - possible security issue */
"/sbin/mountall", /* Unixware */
"/sbin/mount", /* openbsd */
"/etc/mountall", /* sco */
"/sbin/mount -va", /* darwin */
"/sbin/mount -v", /* ux4800 */
"/bin/mount -v", /* qnx */
"/sbin/mount -va", /* dragonfly */
"mingw-invalid", /* mingw */
"/bin/mount -a", /* vmware */
"unused-blah",
"unused-blah",
"unused-blah",
NULL
};
/*********************************************************************/
char *VUNMOUNTCOMM[CF_CLASSATTR] =
{
"", /* see cf.defs.h */
"",
"/etc/umount", /* sun4 */
"/etc/umount", /* ultrix */
"/sbin/umount", /* hpux */
"/usr/sbin/umount", /* aix */
"/bin/umount", /* linux */
"/etc/umount", /* solaris */
"/usr/sbin/umount", /* osf1 */
"/usr/sbin/umount", /* digital */
"/etc/umount", /* sun3 */
"/sbin/umount", /* irix4 */
"/sbin/umount", /* irix */
"/sbin/umount", /* irix64 */
"/sbin/umount", /* freebsd */
"/etc/umount", /* solarisx86 */
"/etc/umount", /* bsd4.3 */
"/etc/umount", /* newsos4 */
"/sbin/umount", /* netbsd */
"/etc/umount", /* AOS */
"/sbin/umount", /* BSDI */
"/usr/etc/umount", /* nextstep */
"/etc/umount", /* cray */
"/sbin/umount", /* gnu */
"/bin/umount", /* NT */
"/sbin/umount", /* Unixware */
"/sbin/umount", /* openbsd */
"/etc/umount", /* sco */
"/sbin/umount", /* darwin */
"/sbin/umount", /* ux4800 */
"/bin/umount", /* qnx */
"/sbin/umount", /* dragonfly */
"mingw-invalid", /* mingw */
"/bin/umount", /* vmware */
"unused-blah",
"unused-blah",
"unused-blah",
NULL
};
/*********************************************************************/
char *VMOUNTOPTS[CF_CLASSATTR] =
{
"", /* see cf.defs.h */
"",
"bg,hard,intr", /* sun4 */
"bg,hard,intr", /* ultrix */
"bg,hard,intr", /* hpux */
"bg,hard,intr", /* aix */
"defaults", /* linux */
"bg,hard,intr", /* solaris */
"bg,hard,intr", /* osf1 */
"bg,hard,intr", /* digital */
"bg,hard,intr", /* sun3 */
"bg,hard,intr", /* irix4 */
"bg,hard,intr", /* irix */
"bg,hard,intr", /* irix64 */
"bg,intr", /* freebsd */
"bg,hard,intr", /* solarisx86 */
"bg,hard,intr", /* bsd4.3 */
"bg,hard,intr", /* newsos4 */
"-i,-b", /* netbsd */
"bg,hard,intr", /* AOS */
"bg,intr", /* BSDI */
"bg,hard,intr", /* nextstep */
"bg,hard,intr", /* cray */
"defaults", /* gnu */
"", /* NT */
"bg,hard,intr", /* Unixware */
"-i,-b", /* openbsd */
"bg,hard,intr", /* sco */
"-i,-b", /* darwin */
"bg,hard,intr", /* ux4800 */
"bg,hard,intr", /* qnx */
"bg,intr", /* dragonfly */
"mingw-invalid", /* mingw */
"defaults", /* vmstate */
"unused-blah",
"unused-blah",
"unused-blah",
NULL
};
/*********************************************************************/
char *VRESOLVCONF[CF_CLASSATTR] =
{
"-",
"-", /* see cf.defs.h */
"/etc/resolv.conf", /* sun4 */
"/etc/resolv.conf", /* ultrix */
"/etc/resolv.conf", /* hpux */
"/etc/resolv.conf", /* aix */
"/etc/resolv.conf", /* linux */
"/etc/resolv.conf", /* solaris */
"/etc/resolv.conf", /* osf1 */
"/etc/resolv.conf", /* digital */
"/etc/resolv.conf", /* sun3 */
"/usr/etc/resolv.conf", /* irix4 */
"/etc/resolv.conf", /* irix */
"/etc/resolv.conf", /* irix64 */
"/etc/resolv.conf", /* freebsd */
"/etc/resolv.conf", /* solarisx86 */
"/etc/resolv.conf", /* bsd4.3 */
"/etc/resolv.conf", /* newsos4 */
"/etc/resolv.conf", /* netbsd */
"/etc/resolv.conf", /* AOS */
"/etc/resolv.conf", /* BSDI */
"/etc/resolv.conf", /* nextstep */
"/etc/resolv.conf", /* cray */
"/etc/resolv.conf", /* gnu */
"/etc/resolv.conf", /* NT */
"/etc/resolv.conf", /* Unixware */
"/etc/resolv.conf", /* openbsd */
"/etc/resolv.conf", /* sco */
"/etc/resolv.conf", /* darwin */
"/etc/resolv.conf", /* ux4800 */
"/etc/resolv.conf", /* qnx */
"/etc/resolv.conf", /* dragonfly */
"", /* mingw */
"/etc/resolv.conf", /* vmware */
"unused-blah",
"unused-blah",
"unused-blah",
NULL
};
/*********************************************************************/
char *VFSTAB[CF_CLASSATTR] =
{
"-",
"-", /* see cf.defs.h */
"/etc/fstab", /* sun4 */
"/etc/fstab", /* ultrix */
"/etc/fstab", /* hpux */
"/etc/filesystems", /* aix */
"/etc/fstab", /* linux */
"/etc/vfstab", /* solaris */
"/etc/fstab", /* osf1 */
"/etc/fstab", /* digital */
"/etc/fstab", /* sun3 */
"/etc/fstab", /* irix4 */
"/etc/fstab", /* irix */
"/etc/fstab", /* irix64 */
"/etc/fstab", /* freebsd */
"/etc/vfstab", /* solarisx86 */
"/etc/fstab", /* bsd4.3 */
"/etc/fstab", /* newsos4 */
"/etc/fstab", /* netbsd */
"/etc/fstab", /* AOS */
"/etc/fstab", /* BSDI */
"/etc/fstab", /* nextstep */
"/etc/fstab", /* cray */
"/etc/fstab", /* gnu */
"/etc/fstab", /* NT */
"/etc/vfstab", /* Unixware */
"/etc/fstab", /* openbsd */
"/etc/default/filesys", /* sco */
"/etc/fstab", /* darwin */
"/etc/vfstab", /* ux4800 */
"/etc/fstab", /* qnx */
"/etc/fstab", /* dragonfly */
"", /* mingw */
"/etc/fstab", /* vmware */
"unused-blah",
"unused-blah",
"unused-blah",
NULL
};
/*********************************************************************/
char *VMAILDIR[CF_CLASSATTR] =
{
"-",
"-", /* see cf.defs.h */
"/var/spool/mail", /* sun4 */
"/usr/spool/mail", /* ultrix */
"/var/mail", /* hpux */
"/var/spool/mail", /* aix */
"/var/spool/mail", /* linux */
"/var/mail", /* solaris */
"/usr/spool/mail", /* osf1 */
"/usr/spool/mail", /* digital */
"/var/spool/mail", /* sun3 */
"/usr/mail", /* irix4 */
"/usr/mail", /* irix */
"/usr/var/mail", /* irix64 */
"/var/mail", /* freebsd */
"/var/mail", /* solarisx86 */
"/usr/spool/mail", /* bsd4.3 */
"/usr/spool/mail", /* newsos4 */
"/var/mail", /* netbsd */
"/usr/spool/mail", /* AOS */
"/var/mail", /* BSDI */
"/usr/spool/mail", /* nextstep */
"/usr/mail", /* cray */
"/var/spool/mail", /* gnu */
"N/A", /* NT */
"/var/mail", /* Unixware */
"/var/mail", /* openbsd */
"/var/spool/mail", /* sco */
"/var/mail", /* darwin */
"/var/mail", /* ux4800 */
"/var/spool/mail", /* qnx */
"/var/mail", /* dragonfly */
"", /* mingw */
"/var/spool/mail", /* vmware */
"unused-blah",
"unused-blah",
"unused-blah",
NULL
};
/*********************************************************************/
char *VNETSTAT[CF_CLASSATTR] =
{
"-",
"-",
"/usr/ucb/netstat -rn", /* sun4 */
"/usr/ucb/netstat -rn", /* ultrix */
"/usr/bin/netstat -rn", /* hpux */
"/usr/bin/netstat -rn", /* aix */
"/bin/netstat -rn", /* linux */
"/usr/bin/netstat -rn", /* solaris */
"/usr/sbin/netstat -rn", /* osf1 */
"/usr/sbin/netstat -rn", /* digital */
"/usr/ucb/netstat -rn", /* sun3 */
"/usr/etc/netstat -rn", /* irix4 */
"/usr/etc/netstat -rn", /* irix */
"/usr/etc/netstat -rn", /* irix64 */
"/usr/bin/netstat -rn", /* freebsd */
"/bin/netstat -rn", /* solarisx86 */
"/usr/ucb/netstat -rn", /* bsd4.3 */
"/usr/ucb/netstat -rn", /* newsos4 */
"/usr/bin/netstat -rn", /* netbsd */
"/usr/ucb/netstat -rn", /* AOS */
"/usr/sbin/netstat -rn", /* BSDI */
"/usr/ucb/netstat -rn", /* nextstep */
"/usr/ucb/netstat -rn", /* cray */
"/bin/netstat -rn", /* gnu */
"/cygdrive/c/WINNT/System32/netstat", /* NT */
"/usr/bin/netstat -rn", /* Unixware */
"/usr/bin/netstat -rn", /* openbsd */
"/usr/bin/netstat -rn", /* sco */
"/usr/sbin/netstat -rn", /* darwin */
"/usr/bin/netstat -rn", /* ux4800 */
"/usr/bin/netstat -rn", /* qnx */
"/usr/bin/netstat -rn", /* dragonfly */
"mingw-invalid", /* mingw */
"/usr/bin/netstat", /* vmware */
"unused-blah",
"unused-blah",
"unused-blah",
NULL
};
/*********************************************************************/
char *VEXPORTS[CF_CLASSATTR] =
{
"-",
"-",
"/etc/exports", /* sun4 */
"/etc/exports", /* ultrix */
"/etc/exports", /* hpux */
"/etc/exports", /* aix */
"/etc/exports", /* linux */
"/etc/dfs/dfstab", /* solaris */
"/etc/exports", /* osf1 */
"/etc/exports", /* digital */
"/etc/exports", /* sun3 */
"/etc/exports", /* irix4 */
"/etc/exports", /* irix */
"/etc/exports", /* irix64 */
"/etc/exports", /* freebsd */
"/etc/dfs/dfstab", /* solarisx86 */
"/etc/exports", /* bsd4.3 */
"/etc/exports", /* newsos4 */
"/etc/exports", /* netbsd */
"/etc/exports", /* AOS */
"/etc/exports", /* BSDI */
"/etc/exports", /* nextstep */
"/etc/exports", /* cray */
"/etc/exports", /* gnu */
"/etc/exports", /* NT */
"/etc/dfs/dfstab", /* Unixware */
"/etc/exports", /* openbsd */
"/etc/dfs/dfstab", /* sco */
"/etc/exports", /* darwin */
"/etc/exports", /* ux4800 */
"/etc/exports", /* qnx */
"/etc/exports", /* dragonfly */
"", /* mingw */
"none", /* vmware */
"unused-blah",
"unused-blah",
"unused-blah",
NULL
};
/*********************************************************************/
char *VROUTE[CF_CLASSATTR] =
{
"-",
"-",
"-", /* sun4 */
"-", /* ultrix */
"-", /* hpux */
"-", /* aix */
"/sbin/route", /* linux */
"/usr/sbin/route",/* solaris */
"-", /* osf1 */
"-", /* digital */
"-", /* sun3 */
"-", /* irix4 */
"-", /* irix */
"-", /* irix64 */
"/sbin/route", /* freebsd */
"/usr/sbin/route",/* solarisx86 */
"-", /* bsd4.3 */
"-", /* newsos4 */
"-", /* netbsd */
"-", /* AOS */
"-", /* BSDI */
"-", /* nextstep */
"-", /* cray */
"-", /* gnu */
"-", /* NT */
"-", /* Unixware */
"/sbin/route", /* openbsd */
"-", /* sco */
"/sbin/route", /* darwin */
"-", /* ux4800 */
"-", /* qnx */
"/sbin/route", /* dragonfly */
"-", /* mingw */
"-", /* vmware */
"unused-blah",
"unused-blah",
"unused-blah",
NULL
};
/*********************************************************************/
char *VROUTEADDFMT[CF_CLASSATTR] =
{
"-",
"-",
"-", /* sun4 */
"-", /* ultrix */
"-", /* hpux */
"-", /* aix */
"add %s gw %s", /* linux */
"add %s %s", /* solaris */
"-", /* osf1 */
"-", /* digital */
"-", /* sun3 */
"-", /* irix4 */
"-", /* irix */
"-", /* irix64 */
"add %s %s", /* freebsd */
"add %s %s", /* solarisx86 */
"-", /* bsd4.3 */
"-", /* newsos4 */
"-", /* netbsd */
"-", /* AOS */
"-", /* BSDI */
"-", /* nextstep */
"-", /* cray */
"-", /* gnu */
"-", /* NT */
"-", /* Unixware */
"add %s %s", /* openbsd */
"-", /* sco */
"add %s %s", /* darwin */
"-", /* ux4800 */
"-", /* qnx */
"add %s %s", /* dragonfly */
"-", /* mingw */
"-", /* vmware */
"unused-blah",
"unused-blah",
"unused-blah",
NULL
};
/*********************************************************************/
char *VROUTEDELFMT[CF_CLASSATTR] =
{
"-",
"-",
"-", /* sun4 */
"-", /* ultrix */
"-", /* hpux */
"-", /* aix */
"del %s", /* linux */
"delete %s", /* solaris */
"-", /* osf1 */
"-", /* digital */
"-", /* sun3 */
"-", /* irix4 */
"-", /* irix */
"-", /* irix64 */
"delete %s", /* freebsd */
"delete %s", /* solarisx86 */
"-", /* bsd4.3 */
"-", /* newsos4 */
"-", /* netbsd */
"-", /* AOS */
"-", /* BSDI */
"-", /* nextstep */
"-", /* cray */
"-", /* gnu */
"-", /* NT */
"-", /* Unixware */
"delete %s", /* openbsd */
"-", /* sco */
"delete %s", /* darwin */
"-", /* ux4800 */
"-", /* qnx */
"delete %s", /* dragonfly */
"-", /* mingw */
"-", /* vmware */
"unused-blah",
"unused-blah",
"unused-blah",
NULL
};
cfengine-3.2.4/src/Makefile.am 0000644 0001750 0001750 00000030007 11715232734 013047 0000000 0000000 AM_CFLAGS = $(GCC_CFLAG) $(NOVA_CFLAGS) $(CONSTELLATION_CFLAGS) @CFLAGS@
AM_YFLAGS = -d
LEXLIB = @LEXLIB@
LDADD = libpromises.la
BUILT_SOURCES = cf3parse.h
lib_LTLIBRARIES = libpromises.la
libpromises_la_LDFLAGS = -version-info 1:0:0 -no-undefined
libpromises_la_LIBADD = ../pub/libcfpub.la $(NOVA_LDADD) $(CONSTELLATION_LDADD)
libpromises_la_CFLAGS = $(AM_CFLAGS)
# Separate out a library
libpromises_la_SOURCES = \
cf3parse.y \
cf3lex.l \
alloc.c \
patches.c \
attributes.c \
install.c \
generic_agent.c \
dbm_api.c \
dbm_berkeley.c \
dbm_quick.c \
dbm_tokyocab.c \
dbm_sqlite3.c \
dir.c \
dtypes.c \
classes.c \
env_context.c \
string_expressions.c \
logic_expressions.c \
files_interfaces.c \
files_properties.c \
files_select.c \
files_operators.c \
files_repository.c \
files_copy.c \
files_editline.c \
files_edit.c \
files_links.c \
files_hashes.c \
files_names.c \
chflags.c \
modes.c \
exec_tools.c \
nfs.c \
item-lib.c \
alphalist.c \
cf_sql.c \
client_protocol.c \
client_code.c \
communication.c \
net.c \
sockaddr.c \
recursion.c \
processes_select.c \
fncall.c \
cf3globals.c \
reporting.c \
evalfunction.c \
sysinfo.c \
conversion.c \
scope.c \
assoc.c \
comparray.c \
vars.c \
args.c \
hashes.c \
crypto.c \
sort.c \
keyring.c \
full-write.c \
expand.c \
matching.c \
selfdiagnostic.c \
instrumentation.c \
granules.c \
timeout.c \
promises.c \
ontology.c \
constraints.c \
iteration.c \
rlist.c \
syntax.c \
logging.c \
signals.c \
transaction.c \
cfstream.c \
pipes.c \
html.c \
interfaces.c \
storage_tools.c \
verify_reports.c \
verify_processes.c \
enterprise_stubs.c \
bootstrap.c \
mod_defaults.c \
mod_common.c \
mod_access.c \
mod_exec.c \
mod_methods.c \
mod_interfaces.c \
mod_packages.c \
mod_files.c \
mod_report.c \
mod_storage.c \
mod_knowledge.c \
mod_measurement.c \
mod_databases.c \
mod_services.c \
mod_process.c \
mod_environ.c \
mod_outputs.c \
unix.c
# Automake need to be guided due to symlinking
libpromises_la_DEPENDENCIES = ../pub/libcfpub.la $(NOVA_LDADD) $(CONSTELLATION_LDADD)
sbin_PROGRAMS = cf-know cf-promises cf-agent cf-monitord cf-serverd cf-execd cf-runagent cf-key cf-report
if HAVE_NOVA
sbin_PROGRAMS += cf-hub
endif
cf_promises_SOURCES = \
cfpromises.c
cf_key_SOURCES = \
cfkey.c
cf_report_SOURCES = \
cfreport.c
cf_agent_SOURCES = \
agent.c \
verify_files.c \
verify_storage.c \
verify_exec.c \
verify_methods.c \
verify_interfaces.c \
verify_packages.c \
verify_databases.c \
verify_services.c \
verify_environments.c \
agentdiagnostic.c
cf_serverd_SOURCES = \
server.c \
server_transform.c
cf_monitord_SOURCES = \
verify_measurements.c \
env_monitor.c \
mon_cpu.c \
mon_disk.c \
mon_entropy.c \
mon_load.c \
mon_network_sniffer.c \
mon_network.c \
mon_processes.c \
mon_temp.c \
monitor.c
cf_monitord_LDADD = libpromises.la
if HAVE_NOVA
cf_monitord_LDADD += ../nova/src/libcfmonitord.la
endif
cf_execd_SOURCES = \
exec.c
if HAVE_NOVA
cf_hub_SOURCES =
cf_hub_LDADD = \
../nova/src/libcfhub.la libpromises.la
endif
cf_runagent_SOURCES = \
runagent.c
cf_know_SOURCES = \
cfknow.c \
manual.c
EXTRA_DIST = cf3lex.c cf3parse.c
#
# Pickup header files here so Automake knows about them
#
noinst_HEADERS = \
cf.defs.h \
cf.extern.h \
config.h \
prototypes3.h \
cf3.defs.h \
cf3.server.h \
cf3parse.h \
cf3.extern.h \
cf.events.h \
string_expressions.h \
logic_expressions.h \
compiler.h \
monitoring.h \
bool.h
#
# Some basic clean ups
#
MOSTLYCLEANFILES = *~ *.orig *.rej
#
# Get everything removed down to where rebuilding requires:
# "make; make install"
#
CLEANFILES = cf3lex.c cf3parse.c cf3parse.h
#
# Get everything removed down to where rebuilding requires:
# "configure; make; make install"
#
DISTCLEANFILES = cflex.c cfparse.c cfparse.h
#
# Get everything removed down to where rebuilding requires:
# "aclocal; autoconf; autoheader; automake --add-missing"
# "configure; make; make install"
#
MAINTAINERCLEANFILES = Makefile.in conf.h.in stamp-h.in
SUFFIXES= .h
cf3.defs.h:
cd ./../core/src; svn update
ln -fs ../../core/src/cf3.defs.h cf3.defs.h cfengine-3.2.4/src/mon_disk.c 0000644 0001750 0001750 00000005535 11715232734 012772 0000000 0000000 /*
Copyright (C) Cfengine AS
This file is part of Cfengine 3 - written and maintained by Cfengine 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 Commerical Open Source License
(COSL) may apply to this file if you as a licensee so wish it. See
included file COSL.txt.
*/
#include "cf3.defs.h"
#include "cf3.extern.h"
#include "monitoring.h"
/* Globals */
static double LASTQ[CF_OBSERVABLES];
/* Prototypes */
static int GetFileGrowth(const char *filename, enum observables index);
/* Implementation */
void MonDiskGatherData(double *cf_this)
{
char accesslog[CF_BUFSIZE];
char errorlog[CF_BUFSIZE];
char syslog[CF_BUFSIZE];
char messages[CF_BUFSIZE];
CfOut(cf_verbose,"","Gathering disk data\n");
cf_this[ob_diskfree] = GetDiskUsage("/",cfpercent);
CfOut(cf_verbose,"","Disk free = %.0lf%%\n",cf_this[ob_diskfree]);
/* Here would should have some detection based on OS type VSYSTEMHARDCLASS */
switch(VSYSTEMHARDCLASS)
{
default:
strcpy(accesslog,"/var/log/apache2/access_log");
strcpy(errorlog,"/var/log/apache2/error_log");
strcpy(syslog,"/var/log/syslog");
strcpy(messages,"/var/log/messages");
}
cf_this[ob_webaccess] = GetFileGrowth(accesslog,ob_webaccess);
CfOut(cf_verbose,"","Webaccess = %.2lf%%\n",cf_this[ob_webaccess]);
cf_this[ob_weberrors] = GetFileGrowth(errorlog,ob_weberrors);
CfOut(cf_verbose,"","Web error = %.2lf%%\n",cf_this[ob_weberrors]);
cf_this[ob_syslog] = GetFileGrowth(syslog,ob_syslog);
CfOut(cf_verbose,"","Syslog = %.2lf%%\n",cf_this[ob_syslog]);
cf_this[ob_messages] = GetFileGrowth(messages,ob_messages);
CfOut(cf_verbose,"","Messages = %.2lf%%\n",cf_this[ob_messages]);
}
/****************************************************************************/
static int GetFileGrowth(const char *filename, enum observables index)
{
struct stat statbuf;
size_t q;
double dq;
if (cfstat(filename,&statbuf) == -1)
{
return 0;
}
q = statbuf.st_size;
CfOut(cf_verbose,"","GetFileGrowth(%s) = %d\n",filename,q);
dq = (double)q - LASTQ[index];
if (LASTQ[index] == 0)
{
LASTQ[index] = q;
return (int)(q/100+0.5); /* arbitrary spike mitigation */
}
LASTQ[index] = q;
return (int)(dq+0.5);
}
cfengine-3.2.4/src/runagent.c 0000644 0001750 0001750 00000050535 11715232734 013012 0000000 0000000 /*
Copyright (C) Cfengine AS
This file is part of Cfengine 3 - written and maintained by Cfengine 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 Commerical Open Source License
(COSL) may apply to this file if you as a licensee so wish it. See
included file COSL.txt.
*/
/*****************************************************************************/
/* */
/* File: runagent.c */
/* */
/*****************************************************************************/
#include "cf3.defs.h"
#include "cf3.extern.h"
int main (int argc,char *argv[]);
int HailServer(char *host,struct Attributes a,struct Promise *pp);
void ThisAgentInit(void);
int ParseHostname(char *hostname,char *new_hostname);
void SendClassData(struct cfagent_connection *conn);
struct Promise *MakeDefaultRunAgentPromise(void);
void HailExec(struct cfagent_connection *conn,char *peer,char *recvbuffer,char *sendbuffer);
FILE *NewStream(char *name);
void DeleteStream(FILE *fp);
/*******************************************************************/
/* Command line options */
/*******************************************************************/
const char *ID = "The run agent connects to a list of running instances of\n"
"the cf-serverd service. The agent allows a user to\n"
"forego the usual scheduling interval for the agent and\n"
"activate cf-agent on a remote host. Additionally, a user\n"
"can send additional classes to be defined on the remote\n"
"host. Two kinds of classes may be sent: classes to decide\n"
"on which hosts the agent will be started, and classes that\n"
"the user requests the agent should define on execution.\n"
"The latter type is regulated by cf-serverd's role based\n"
"access control.";
const struct option OPTIONS[17] =
{
{ "help",no_argument,0,'h' },
{ "background",optional_argument,0,'b' },
{ "debug",optional_argument,0,'d' },
{ "verbose",no_argument,0,'v' },
{ "dry-run",no_argument,0,'n'},
{ "version",no_argument,0,'V' },
{ "file",required_argument,0,'f'},
{ "define-class",required_argument,0,'D' },
{ "select-class",required_argument,0,'s' },
{ "inform",no_argument,0,'I'},
{ "remote-options",required_argument,0,'o'},
{ "diagnostic",no_argument,0,'x'},
{ "hail",required_argument,0,'H'},
{ "interactive",no_argument,0,'i'},
{ "query",optional_argument,0,'q'},
{ "timeout",required_argument,0,'t'},
{ NULL,0,0,'\0' }
};
const char *HINTS[17] =
{
"Print the help message",
"Parallelize connections (50 by default)",
"Set debugging level 0,1,2,3",
"Output verbose information about the behaviour of the agent",
"All talk and no action mode - make no changes, only inform of promises not kept",
"Output the version of the software",
"Specify an alternative input file than the default",
"Define a list of comma separated classes to be sent to a remote agent",
"Define a list of comma separated classes to be used to select remote agents by constraint",
"Print basic information about changes made to the system, i.e. promises repaired",
"Pass options to a remote server process",
"Activate internal diagnostics (developers only)",
"Hail the following comma-separated lists of hosts, overriding default list",
"Enable interactive mode for key trust",
"Query a server for a knowledge menu",
"Connection timeout, seconds",
NULL
};
extern struct BodySyntax CFR_CONTROLBODY[];
int INTERACTIVE = false;
int OUTPUT_TO_FILE = false;
char OUTPUT_DIRECTORY[CF_BUFSIZE];
int BACKGROUND = false;
int MAXCHILD = 50;
char REMOTE_AGENT_OPTIONS[CF_MAXVARSIZE];
struct Attributes RUNATTR = {{0}};
struct Rlist *HOSTLIST = NULL;
char SENDCLASSES[CF_MAXVARSIZE];
char DEFINECLASSES[CF_MAXVARSIZE];
char MENU[CF_MAXVARSIZE];
/*****************************************************************************/
int main(int argc,char *argv[])
{ struct Rlist *rp;
struct Promise *pp;
int count = 0;
int status;
int pid;
CheckOpts(argc,argv);
GenericInitialize(argc,argv,"runagent");
ThisAgentInit();
KeepControlPromises(); // Set RUNATTR using copy
if (BACKGROUND && INTERACTIVE)
{
CfOut(cf_error,""," !! You cannot specify background mode and interactive mode together");
exit(1);
}
pp = MakeDefaultRunAgentPromise();
/* HvB */
if (HOSTLIST)
{
rp = HOSTLIST;
while ( rp != NULL )
{
#ifdef MINGW
if (BACKGROUND)
{
CfOut(cf_verbose, "", "Windows does not support starting processes in the background - starting in foreground");
BACKGROUND = false;
}
#else
if (BACKGROUND) /* parallel */
{
if (count <= MAXCHILD)
{
if (fork() == 0) /* child process */
{
HailServer(rp->item,RUNATTR,pp);
exit(0);
}
else /* parent process */
{
rp = rp->next;
count++;
}
}
else
{
pid = wait(&status);
Debug("child = %d, child number = %d\n", pid, count);
count--;
}
}
else /* serial */
#endif /* MINGW */
{
HailServer(rp->item,RUNATTR,pp);
rp = rp->next;
}
} /* end while */
} /* end if HOSTLIST */
#ifndef MINGW
if (BACKGROUND)
{
printf("Waiting for child processes to finish\n");
while (count > 1)
{
pid = wait(&status);
CfOut(cf_verbose, "", "Child = %d ended, number = %d\n", pid, count);
count--;
}
}
#endif
return 0;
}
/*******************************************************************/
void CheckOpts(int argc,char **argv)
{ extern char *optarg;
int optindex = 0;
int c;
DEFINECLASSES[0] = '\0';
SENDCLASSES[0] = '\0';
while ((c=getopt_long(argc,argv,"t:q:d:b:vnKhIif:D:VSxo:s:MH:",OPTIONS,&optindex)) != EOF)
{
switch ((char) c)
{
case 'f':
strncpy(VINPUTFILE,optarg,CF_BUFSIZE-1);
VINPUTFILE[CF_BUFSIZE-1] = '\0';
MINUSF = true;
break;
case 'b':
BACKGROUND = true;
if (optarg)
{
MAXCHILD = atoi(optarg);
}
break;
case 'd':
NewClass("opt_debug");
switch ((optarg==NULL) ? '3' : *optarg)
{
case '1':
D1 = true;
DEBUG = true;
break;
case '2':
D2 = true;
DEBUG = true;
break;
default:
DEBUG = true;
break;
}
break;
case 'q':
if (optarg==NULL)
{
strcpy(MENU,"delta");
}
else
{
strncpy(MENU,optarg,CF_MAXVARSIZE);
}
break;
case 'K': IGNORELOCK = true;
break;
case 's': strncpy(SENDCLASSES,optarg,CF_MAXVARSIZE);
if (strlen(optarg) > CF_MAXVARSIZE)
{
FatalError("Argument too long\n");
}
break;
case 'D': strncpy(DEFINECLASSES,optarg,CF_MAXVARSIZE);
if (strlen(optarg) > CF_MAXVARSIZE)
{
FatalError("Argument too long\n");
}
break;
case 'H':
HOSTLIST = SplitStringAsRList(optarg,',');
break;
case 'o':
strncpy(REMOTE_AGENT_OPTIONS,optarg,CF_MAXVARSIZE);
break;
case 'I': INFORM = true;
break;
case 'i': INTERACTIVE = true;
break;
case 'v': VERBOSE = true;
break;
case 'n': DONTDO = true;
IGNORELOCK = true;
NewClass("opt_dry_run");
break;
case 't':
CONNTIMEOUT = atoi(optarg);
break;
case 'V': PrintVersionBanner("cf-runagent");
exit(0);
case 'h': Syntax("cf-runagent - Run agent",OPTIONS,HINTS,ID);
exit(0);
case 'M': ManPage("cf-runagent - Run agent",OPTIONS,HINTS,ID);
exit(0);
case 'x': SelfDiagnostic();
exit(0);
default: Syntax("cf-runagent - Run agent",OPTIONS,HINTS,ID);
exit(1);
}
}
Debug("Set debugging\n");
}
/*******************************************************************/
void ThisAgentInit()
{
umask(077);
if (strstr(REMOTE_AGENT_OPTIONS,"--file")||strstr(REMOTE_AGENT_OPTIONS,"-f"))
{
CfOut(cf_error,"","The specified remote options include a useless --file option. The remote server has promised to ignore this, thus it is disallowed.\n");
exit(1);
}
}
/********************************************************************/
int HailServer(char *host,struct Attributes a,struct Promise *pp)
{ struct cfagent_connection *conn;
char sendbuffer[CF_BUFSIZE],recvbuffer[CF_BUFSIZE],peer[CF_MAXVARSIZE],ipv4[CF_MAXVARSIZE],digest[CF_MAXVARSIZE],user[CF_SMALLBUF];
long gotkey;
char reply[8];
struct Item *queries;
a.copy.portnumber = (short)ParseHostname(host,peer);
snprintf(ipv4,CF_MAXVARSIZE,"%s",Hostname2IPString(peer));
IPString2KeyDigest(ipv4,digest);
GetCurrentUserName(user,CF_SMALLBUF);
if (INTERACTIVE)
{
CfOut(cf_verbose,""," -> Using interactive key trust...\n");
gotkey = (long)HavePublicKey(user,peer,digest);
if (!gotkey)
{
gotkey = (long)HavePublicKey(user,ipv4,digest);
}
if (!gotkey)
{
printf("WARNING - You do not have a public key from host %s = %s\n",host,ipv4);
printf(" Do you want to accept one on trust? (yes/no)\n\n--> ");
while (true)
{
fgets(reply,8,stdin);
Chop(reply);
if (strcmp(reply,"yes")==0)
{
printf(" -> Will trust the key...\n");
a.copy.trustkey = true;
break;
}
else if (strcmp(reply,"no")==0)
{
printf(" -> Will not trust the key...\n");
a.copy.trustkey = false;
break;
}
else
{
printf(" !! Please reply yes or no...(%s)\n",reply);
}
}
}
}
/* Continue */
#ifdef MINGW
CfOut(cf_inform,"","...........................................................................\n");
CfOut(cf_inform,""," * Hailing %s : %u, with options \"%s\" (serial)\n",peer,a.copy.portnumber,REMOTE_AGENT_OPTIONS);
CfOut(cf_inform,"","...........................................................................\n");
#else /* NOT MINGW */
if (BACKGROUND)
{
CfOut(cf_inform,"","Hailing %s : %u, with options \"%s\" (parallel)\n",peer,a.copy.portnumber,REMOTE_AGENT_OPTIONS);
}
else
{
CfOut(cf_inform,"","...........................................................................\n");
CfOut(cf_inform,""," * Hailing %s : %u, with options \"%s\" (serial)\n",peer,a.copy.portnumber,REMOTE_AGENT_OPTIONS);
CfOut(cf_inform,"","...........................................................................\n");
}
#endif /* NOT MINGW */
a.copy.servers = SplitStringAsRList(peer,'*');
if (a.copy.servers == NULL || strcmp(a.copy.servers->item,"localhost") == 0)
{
cfPS(cf_inform,CF_NOP,"",pp,a,"No hosts are registered to connect to");
return false;
}
else
{
conn = NewServerConnection(a,pp);
if (conn == NULL)
{
CfOut(cf_verbose,""," -> No suitable server responded to hail\n");
return false;
}
}
/* Check trust interaction*/
pp->cache = NULL;
if (strlen(MENU) > 0)
{
#ifdef HAVE_NOVA
enum cfd_menu menu = String2Menu(MENU);
switch(menu)
{
case cfd_menu_delta:
Nova_QueryForKnowledgeMap(conn,MENU,time(0) - SECONDS_PER_MINUTE * 10);
break;
case cfd_menu_full:
Nova_QueryForKnowledgeMap(conn,MENU,time(0) - SECONDS_PER_WEEK);
break;
case cfd_menu_relay:
#ifdef HAVE_CONSTELLATION
queries = Constellation_CreateAllQueries();
Constellation_QueryRelay(conn,queries);
DeleteItemList(queries);
#endif
break;
default:
break;
}
#endif /* HAVE_NOVA */
}
else
{
HailExec(conn,peer,recvbuffer,sendbuffer);
}
ServerDisconnection(conn);
DeleteRlist(a.copy.servers);
return true;
}
/********************************************************************/
/* Level 2 */
/********************************************************************/
void KeepControlPromises()
{ struct Constraint *cp;
char rettype;
void *retval;
RUNATTR.copy.trustkey = false;
RUNATTR.copy.encrypt = true;
RUNATTR.copy.force_ipv4 = false;
RUNATTR.copy.portnumber = SHORT_CFENGINEPORT;
/* Keep promised agent behaviour - control bodies */
for (cp = ControlBodyConstraints(cf_runagent); cp != NULL; cp=cp->next)
{
if (IsExcluded(cp->classes))
{
continue;
}
if (GetVariable("control_runagent",cp->lval,&retval,&rettype) == cf_notype)
{
CfOut(cf_error,"","Unknown lval %s in runagent control body",cp->lval);
continue;
}
if (strcmp(cp->lval,CFR_CONTROLBODY[cfr_force_ipv4].lval) == 0)
{
RUNATTR.copy.force_ipv4 = GetBoolean(retval);
CfOut(cf_verbose,"","SET force_ipv4 = %d\n",RUNATTR.copy.force_ipv4);
continue;
}
if (strcmp(cp->lval,CFR_CONTROLBODY[cfr_trustkey].lval) == 0)
{
RUNATTR.copy.trustkey = GetBoolean(retval);
CfOut(cf_verbose,"","SET trustkey = %d\n",RUNATTR.copy.trustkey);
continue;
}
if (strcmp(cp->lval,CFR_CONTROLBODY[cfr_encrypt].lval) == 0)
{
RUNATTR.copy.encrypt = GetBoolean(retval);
CfOut(cf_verbose,"","SET encrypt = %d\n",RUNATTR.copy.encrypt);
continue;
}
if (strcmp(cp->lval,CFR_CONTROLBODY[cfr_portnumber].lval) == 0)
{
RUNATTR.copy.portnumber = (short)Str2Int(retval);
CfOut(cf_verbose,"","SET default portnumber = %u\n",(int)RUNATTR.copy.portnumber);
continue;
}
if (strcmp(cp->lval,CFR_CONTROLBODY[cfr_background].lval) == 0)
{
/*
* Only process this option if are is no -b or -i options specified on
* command line.
*/
if (BACKGROUND || INTERACTIVE)
{
CfOut(cf_error, "", "Warning: 'background_children' setting from 'body runagent control' is overriden by command-line option.");
}
else
{
BACKGROUND = GetBoolean(retval);
}
continue;
}
if (strcmp(cp->lval,CFR_CONTROLBODY[cfr_maxchild].lval) == 0)
{
MAXCHILD = (short)Str2Int(retval);
continue;
}
if (strcmp(cp->lval,CFR_CONTROLBODY[cfr_output_to_file].lval) == 0)
{
OUTPUT_TO_FILE = GetBoolean(retval);
continue;
}
/*
* HvB: add variabele output directory
*/
if (strcmp(cp->lval,CFR_CONTROLBODY[cfr_output_directory].lval) == 0)
{
if ( IsAbsPath(retval) )
{
strncpy(OUTPUT_DIRECTORY,retval,CF_BUFSIZE-1);
CfOut(cf_verbose,"","SET output direcory to = %s\n", OUTPUT_DIRECTORY);
}
continue;
}
if (strcmp(cp->lval,CFR_CONTROLBODY[cfr_timeout].lval) == 0)
{
RUNATTR.copy.timeout = (short)Str2Int(retval);
continue;
}
if (strcmp(cp->lval,CFR_CONTROLBODY[cfr_hosts].lval) == 0)
{
if (HOSTLIST == NULL) // Don't override if command line setting
{
HOSTLIST = retval;
}
continue;
}
}
}
/********************************************************************/
struct Promise *MakeDefaultRunAgentPromise()
{ struct Promise *pp;
/* The default promise here is to hail associates */
if ((pp = (struct Promise *)malloc(sizeof(struct Promise))) == NULL)
{
CfOut(cf_error,"malloc","Unable to allocate Promise");
FatalError("");
}
pp->audit = NULL;
pp->lineno = 0;
pp->bundle = strdup("implicit internal bundle for runagent");
pp->promiser = strdup("runagent");
pp->promisee = NULL;
pp->petype = CF_NOPROMISEE;
pp->classes = NULL;
pp->conlist = NULL;
pp->done = false;
pp->donep = &(pp->done);
pp->ref = NULL;
pp->agentsubtype = NULL;
pp->this_server = NULL;
pp->cache = NULL;
pp->conn = NULL;
pp->inode_cache = NULL;
pp->next = NULL;
return pp;
}
/********************************************************************/
int ParseHostname(char *name,char *hostname)
{ int port = ntohs(SHORT_CFENGINEPORT);
if (strchr(name,':'))
{
sscanf(name,"%250[^:]:%d",hostname,&port);
}
else
{
strncpy(hostname,name,CF_MAXVARSIZE);
}
return(port);
}
/********************************************************************/
void SendClassData(struct cfagent_connection *conn)
{ struct Rlist *classes,*rp;
char sendbuffer[CF_BUFSIZE];
classes = SplitRegexAsRList(SENDCLASSES,"[,: ]",99,false);
for (rp = classes; rp != NULL; rp = rp->next)
{
if (SendTransaction(conn->sd,rp->item,0,CF_DONE) == -1)
{
CfOut(cf_error,"send","Transaction failed");
return;
}
}
snprintf(sendbuffer,CF_MAXVARSIZE,"%s",CFD_TERMINATOR);
if (SendTransaction(conn->sd,sendbuffer,0,CF_DONE) == -1)
{
CfOut(cf_error,"send","Transaction failed");
return;
}
}
/********************************************************************/
void HailExec(struct cfagent_connection *conn,char *peer,char *recvbuffer,char *sendbuffer)
{ FILE *fp = stdout;
char *sp;
int n_read;
if (strlen(DEFINECLASSES))
{
snprintf(sendbuffer,CF_BUFSIZE,"EXEC %s -D%s",REMOTE_AGENT_OPTIONS,DEFINECLASSES);
}
else
{
snprintf(sendbuffer,CF_BUFSIZE,"EXEC %s",REMOTE_AGENT_OPTIONS);
}
if (SendTransaction(conn->sd,sendbuffer,0,CF_DONE) == -1)
{
CfOut(cf_error,"send","Transmission rejected");
ServerDisconnection(conn);
return;
}
fp = NewStream(peer);
SendClassData(conn);
while (true)
{
memset(recvbuffer,0,CF_BUFSIZE);
if ((n_read = ReceiveTransaction(conn->sd,recvbuffer,NULL)) == -1)
{
DestroyServerConnection(conn);
break;
}
if (n_read == 0)
{
break;
}
if (strlen(recvbuffer) == 0)
{
continue;
}
if ((sp = strstr(recvbuffer,CFD_TERMINATOR)) != NULL)
{
CfFile(fp," !!\n\n");
break;
}
if ((sp = strstr(recvbuffer,"BAD:")) != NULL)
{
CfFile(fp," !! %s",recvbuffer+4);
continue;
}
if (strstr(recvbuffer,"too soon"))
{
CfFile(fp," !! %s",recvbuffer);
continue;
}
CfFile(fp," -> %s",recvbuffer);
}
DeleteStream(fp);
}
/********************************************************************/
/* Level */
/********************************************************************/
FILE *NewStream(char *name)
{ FILE *fp;
char filename[CF_BUFSIZE];
if ( OUTPUT_DIRECTORY[0] != '\0')
{
snprintf(filename,CF_BUFSIZE,"%s/%s_runagent.out",OUTPUT_DIRECTORY,name);
}
else
{
snprintf(filename,CF_BUFSIZE,"%s/outputs/%s_runagent.out",CFWORKDIR,name);
}
if (OUTPUT_TO_FILE)
{
printf("Opening file...%s\n",filename);
if ((fp = fopen(filename,"w")) == NULL)
{
CfOut(cf_error,"Unable to open file %s\n",filename);
fp = stdout;
}
}
else
{
fp = stdout;
}
return fp;
}
/********************************************************************/
void DeleteStream(FILE *fp)
{
if (fp != stdout)
{
fclose(fp);
}
}
cfengine-3.2.4/src/vars.c 0000644 0001750 0001750 00000055653 11715232734 012150 0000000 0000000 /*
Copyright (C) Cfengine AS
This file is part of Cfengine 3 - written and maintained by Cfengine 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 Commerical Open Source License
(COSL) may apply to this file if you as a licensee so wish it. See
included file COSL.txt.
*/
/*******************************************************************/
/* */
/* vars.c */
/* */
/*******************************************************************/
#include "cf3.defs.h"
#include "cf3.extern.h"
static void ExtendList(char *scope,char *lval,void *rval,enum cfdatatype dt);
static void IdempNewScalar(char *scope,char *lval,char *rval,enum cfdatatype dt);
static void DeleteAllVariables(char *scope);
static int IsCf3Scalar(char *str);
/*******************************************************************/
void LoadSystemConstants()
{
NewScalar("const","dollar","$",cf_str);
NewScalar("const","n","\n",cf_str);
NewScalar("const","r","\r",cf_str);
NewScalar("const","t","\t",cf_str);
NewScalar("const","endl","\n",cf_str);
/* NewScalar("const","0","\0",cf_str); - this cannot work */
#ifdef HAVE_NOVA
Nova_EnterpriseDiscovery();
#endif
}
/*******************************************************************/
/* Variables */
/*******************************************************************/
void ForceScalar(char *lval,char *rval)
{ char rtype,*retval;
if (THIS_AGENT_TYPE != cf_agent && THIS_AGENT_TYPE != cf_know)
{
return;
}
if (GetVariable("match",lval,(void *)&retval,&rtype) != cf_notype)
{
DeleteVariable("match",lval);
}
NewScalar("match",lval,rval,cf_str);
Debug("Setting local variable \"match.%s\" context; $(%s) = %s\n",lval,lval,rval);
}
/*******************************************************************/
void NewScalar(char *scope,char *lval,char *rval,enum cfdatatype dt)
{ struct Rval rvald;
struct Scope *ptr;
Debug("NewScalar(%s,%s,%s)\n",scope,lval,rval);
ptr = GetScope(scope);
if (ptr == NULL)
{
CfOut(cf_error, "", "!! Attempt to add variable \"%s\" to non-existant scope \"%s\" - ignored", lval, scope);
return;
}
// Newscalar allocates memory through NewAssoc
if (GetVariable(scope,lval,&rvald.item,&rvald.rtype) != cf_notype)
{
DeleteScalar(scope,lval);
}
AddVariableHash(scope,lval,rval,CF_SCALAR,dt,NULL,0);
}
/*******************************************************************/
static void IdempNewScalar(char *scope,char *lval,char *rval,enum cfdatatype dt)
{
struct Rval rvald;
Debug("IdempNewScalar(%s,%s,%s)\n",scope,lval,rval);
if (GetVariable(scope,lval,&rvald.item,&rvald.rtype) != cf_notype)
{
return;
}
AddVariableHash(scope,lval,rval,CF_SCALAR,dt,NULL,0);
}
/*******************************************************************/
void DeleteScalar(char *scope_name, char *lval)
{
struct Scope *scope = GetScope(scope_name);
if (scope == NULL)
{
return;
}
if (HashDeleteElement(scope->hashtable, lval) == false)
{
Debug("Attempt to delete non-existent variable %s in scope %s\n", lval, scope_name);
}
}
/*******************************************************************/
void NewList(char *scope,char *lval,void *rval,enum cfdatatype dt)
{ char *sp1;
struct Rval rvald;
if (GetVariable(scope,lval,&rvald.item,&rvald.rtype) != cf_notype)
{
DeleteVariable(scope,lval);
}
sp1 = strdup(lval);
AddVariableHash(scope,sp1,rval,CF_LIST,dt,NULL,0);
}
/*******************************************************************/
static void ExtendList(char *scope,char *lval,void *rval,enum cfdatatype dt)
{
struct Rval rvald;
struct Rlist *list,*rp;
if (GetVariable(scope,lval,&rvald.item,&rvald.rtype) != cf_notype)
{
list = rvald.item;
switch(rvald.rtype)
{
case CF_SCALAR:
IdempAppendRlist(&list,rval,CF_SCALAR);
break;
case CF_LIST:
for (rp = rval; rp != NULL; rp = rp->next)
{
IdempAppendRlist(&list,rval,CF_SCALAR);
}
break;
case CF_FNCALL:
rp = IdempAppendRScalar(&list,"dummy",CF_SCALAR);
free(rp->item);
rp->item = rval;
rp->type = CF_FNCALL;
break;
default:
CfOut(cf_error,"","Attempt to extend a list with something unknown");
break;
}
}
else
{
NewList(scope,lval,rval,dt);
}
}
/*******************************************************************/
enum cfdatatype GetVariable(const char *scope, const char *lval, void **returnv, char *rtype)
{
struct Scope *ptr = NULL;
char scopeid[CF_MAXVARSIZE],vlval[CF_MAXVARSIZE],sval[CF_MAXVARSIZE];
char expbuf[CF_EXPANDSIZE];
CfAssoc *assoc;
Debug("\nGetVariable(%s,%s) type=(to be determined)\n",scope,lval);
if (lval == NULL)
{
*returnv = (void*)lval;
*rtype = CF_SCALAR;
return cf_notype;
}
if (!IsExpandable(lval))
{
strncpy(sval,lval,CF_MAXVARSIZE-1);
}
else
{
if (ExpandScalar(lval,expbuf))
{
strncpy(sval,expbuf,CF_MAXVARSIZE-1);
}
else
{
*returnv = (void*)lval;
*rtype = CF_SCALAR;
Debug("Couldn't expand array-like variable (%s) due to undefined dependencies\n",lval);
return cf_notype;
}
}
if (IsQualifiedVariable(sval))
{
scopeid[0] = '\0';
sscanf(sval,"%[^.].%s",scopeid,vlval);
Debug("Variable identifier %s is prefixed with scope id %s\n",vlval,scopeid);
ptr = GetScope(scopeid);
}
else
{
strcpy(vlval,sval);
strcpy(scopeid,scope);
}
Debug("Looking for %s.%s\n",scopeid,vlval);
if (ptr == NULL)
{
/* Assume current scope */
strcpy(vlval,lval);
ptr = GetScope(scopeid);
}
if (ptr == NULL)
{
Debug("Scope for variable \"%s.%s\" does not seem to exist\n",scope,lval);
*returnv = (void*)lval;
*rtype = CF_SCALAR;
return cf_notype;
}
Debug("GetVariable(%s,%s): using scope '%s' for variable '%s'\n",scopeid,vlval,ptr->scope,vlval);
assoc = HashLookupElement(ptr->hashtable, vlval);
if (assoc == NULL)
{
Debug("No such variable found %s.%s\n\n",scopeid,lval);
*returnv = (void*)lval;
*rtype = CF_SCALAR;
return cf_notype;
}
Debug("return final variable type=%s, value={\n",CF_DATATYPES[assoc->dtype]);
if (DEBUG)
{
ShowRval(stdout,assoc->rval,assoc->rtype);
}
Debug("}\n");
*returnv = assoc->rval;
*rtype = assoc->rtype;
return assoc->dtype;
}
/*******************************************************************/
void DeleteVariable(char *scope,char *id)
{
struct Scope *ptr = GetScope(scope);
if (ptr == NULL)
{
return;
}
if (HashDeleteElement(ptr->hashtable, id) == false)
{
Debug("No variable matched %s\n",id);
}
}
/*******************************************************************/
int CompareVariable(const char *lval,struct CfAssoc *ap)
{
if (ap == NULL || lval == NULL)
{
return 1;
}
return strcmp(ap->lval,lval);
}
/*******************************************************************/
int CompareVariableValue(void *rval,char rtype,struct CfAssoc *ap)
{
struct Rlist *list, *rp;
if (ap == NULL || rval == NULL)
{
return 1;
}
switch (rtype)
{
case CF_SCALAR:
return strcmp(ap->rval,rval);
case CF_LIST:
list = (struct Rlist *)rval;
for (rp = list; rp != NULL; rp=rp->next)
{
if (!CompareVariableValue(rp->item,rp->type,ap))
{
return -1;
}
}
return 0;
default:
return 0;
}
return strcmp(ap->rval,rval);
}
/*******************************************************************/
int UnresolvedVariables(struct CfAssoc *ap,char rtype)
{
struct Rlist *list, *rp;
if (ap == NULL)
{
return false;
}
switch (rtype)
{
case CF_SCALAR:
return IsCf3VarString(ap->rval);
case CF_LIST:
list = (struct Rlist *)ap->rval;
for (rp = list; rp != NULL; rp=rp->next)
{
if (IsCf3VarString(rp->item))
{
return true;
}
}
return false;
default:
return false;
}
}
/*******************************************************************/
int UnresolvedArgs(struct Rlist *args)
{ struct Rlist *rp;
for (rp = args; rp != NULL; rp = rp->next)
{
if (rp->type != CF_SCALAR)
{
return true;
}
if (IsCf3Scalar(rp->item))
{
return true;
}
}
return false;
}
/*******************************************************************/
static void DeleteAllVariables(char *scope)
{
struct Scope *ptr;
ptr = GetScope(scope);
HashClear(ptr->hashtable);
}
/******************************************************************/
int StringContainsVar(char *s,char *v)
{ char varstr[CF_MAXVARSIZE];
if (s == NULL)
{
return false;
}
snprintf(varstr,CF_MAXVARSIZE-1,"${%s}",v);
if (strstr(s,varstr) != NULL)
{
return true;
}
snprintf(varstr,CF_MAXVARSIZE-1,"$(%s)",v);
if (strstr(s,varstr) != NULL)
{
return true;
}
snprintf(varstr,CF_MAXVARSIZE-1,"@{%s}",v);
if (strstr(s,varstr) != NULL)
{
return true;
}
snprintf(varstr,CF_MAXVARSIZE-1,"@(%s)",v);
if (strstr(s,varstr) != NULL)
{
return true;
}
return false;
}
/*********************************************************************/
int IsCf3VarString(char *str)
{ char *sp;
char left = 'x', right = 'x';
int dollar = false;
int bracks = 0, vars = 0;
Debug1("IsCf3VarString(%s) - syntax verify\n",str);
if (str == NULL)
{
return false;
}
for (sp = str; *sp != '\0' ; sp++) /* check for varitems */
{
switch (*sp)
{
case '$':
case '@':
if (*(sp+1) == '{' || *(sp+1) == '(')
{
dollar = true;
}
break;
case '(':
case '{':
if (dollar)
{
left = *sp;
bracks++;
}
break;
case ')':
case '}':
if (dollar)
{
bracks--;
right = *sp;
}
break;
}
/* Some chars cannot be in variable ids, e.g.
$(/bin/cat file) is legal in bash */
if (bracks > 0)
{
switch (*sp)
{
case '/':
return false;
}
}
if (left == '(' && right == ')' && dollar && (bracks == 0))
{
vars++;
dollar=false;
}
if (left == '{' && right == '}' && dollar && (bracks == 0))
{
vars++;
dollar = false;
}
}
if (dollar && (bracks != 0))
{
char output[CF_BUFSIZE];
snprintf(output,CF_BUFSIZE,"Broken variable syntax or bracket mismatch in string (%s)",str);
yyerror(output);
return false;
}
Debug("Found %d variables in (%s)\n",vars,str);
return vars;
}
/*********************************************************************/
static int IsCf3Scalar(char *str)
{ char *sp;
char left = 'x', right = 'x';
int dollar = false;
int bracks = 0, vars = 0;
Debug1("IsCf3Scalar(%s) - syntax verify\n",str);
if (str == NULL)
{
return false;
}
for (sp = str; *sp != '\0' ; sp++) /* check for varitems */
{
switch (*sp)
{
case '$':
if (*(sp+1) == '{' || *(sp+1) == '(')
{
dollar = true;
}
break;
case '(':
case '{':
if (dollar)
{
left = *sp;
bracks++;
}
break;
case ')':
case '}':
if (dollar)
{
bracks--;
right = *sp;
}
break;
}
/* Some chars cannot be in variable ids, e.g.
$(/bin/cat file) is legal in bash */
if (bracks > 0)
{
switch (*sp)
{
case '/':
return false;
}
}
if (left == '(' && right == ')' && dollar && (bracks == 0))
{
vars++;
dollar=false;
}
if (left == '{' && right == '}' && dollar && (bracks == 0))
{
vars++;
dollar = false;
}
}
if (dollar && (bracks != 0))
{
char output[CF_BUFSIZE];
snprintf(output,CF_BUFSIZE,"Broken scalar variable syntax or bracket mismatch in \"%s\"",str);
yyerror(output);
return false;
}
Debug("Found %d variables in (%s)\n",vars,str);
return vars;
}
/*******************************************************************/
int DefinedVariable(char *name)
{ struct Rval rval;
if (name == NULL)
{
return false;
}
if (GetVariable("this",name,&rval.item,&rval.rtype) == cf_notype)
{
return false;
}
return true;
}
/*******************************************************************/
int BooleanControl(char *scope,char *name)
{ char varbuf[CF_BUFSIZE], rtype;
if (name == NULL)
{
return false;
}
if (GetVariable(scope,name,(void *)varbuf,&rtype) != cf_notype)
{
return GetBoolean(varbuf);
}
return false;
}
/*******************************************************************/
const char *ExtractInnerCf3VarString(const char *str,char *substr)
{ const char *sp;
int bracks = 1;
Debug("ExtractInnerVarString( %s ) - syntax verify\n",str);
if (str == NULL || strlen(str) == 0)
{
return NULL;
}
memset(substr,0,CF_BUFSIZE);
if (*(str+1) != '(' && *(str+1) != '{')
{
return NULL;
}
/* Start this from after the opening $( */
for (sp = str+2; *sp != '\0' ; sp++) /* check for varitems */
{
switch (*sp)
{
case '(':
case '{':
bracks++;
break;
case ')':
case '}':
bracks--;
break;
default:
if (isalnum((int)*sp) || strchr("_[]$.:-", *sp))
{
}
else
{
Debug("Illegal character found: '%c'\n", *sp);
Debug("Illegal character somewhere in variable \"%s\" or nested expansion",str);
}
}
if (bracks == 0)
{
strncpy(substr,str+2,sp-str-2);
Debug("Returning substring value %s\n",substr);
return substr;
}
}
if (bracks != 0)
{
char output[CF_BUFSIZE];
if (strlen(substr) > 0)
{
snprintf(output,CF_BUFSIZE,"Broken variable syntax or bracket mismatch - inner (%s/%s)",str,substr);
yyerror(output);
}
return NULL;
}
return sp-1;
}
/*********************************************************************/
const char *ExtractOuterCf3VarString(const char *str, char *substr)
/* Should only by applied on str[0] == '$' */
{ const char *sp;
int dollar = false;
int bracks = 0, onebrack = false;
int nobracks = true;
Debug("ExtractOuterVarString(\"%s\") - syntax verify\n",str);
memset(substr,0,CF_BUFSIZE);
for (sp = str; *sp != '\0' ; sp++) /* check for varitems */
{
switch (*sp)
{
case '$':
dollar = true;
switch (*(sp+1))
{
case '(':
case '{':
break;
default:
/* Stray dollar not a variable */
return NULL;
}
break;
case '(':
case '{':
bracks++;
onebrack = true;
nobracks = false;
break;
case ')':
case '}':
bracks--;
break;
}
if (dollar && (bracks == 0) && onebrack)
{
strncpy(substr,str,sp-str+1);
Debug("Extracted outer variable |%s|\n",substr);
return substr;
}
}
if (dollar == false)
{
return str; /* This is not a variable*/
}
if (bracks != 0)
{
char output[CF_BUFSIZE];
snprintf(output,CF_BUFSIZE,"Broken variable syntax or bracket mismatch in - outer (%s/%s)",str,substr);
yyerror(output);
return NULL;
}
/* Return pointer to first position in string (shouldn't happen)
as long as we only call this function from the first $ position */
return str;
}
/*********************************************************************/
int IsQualifiedVariable(char *var)
{ int isarraykey = false;
char *sp;
for (sp = var; *sp != '\0'; sp++)
{
if (*sp == '[')
{
isarraykey = true;
}
if (isarraykey)
{
return false;
}
else
{
if (*sp == '.')
{
return true;
}
}
}
return false;
}
/*********************************************************************/
int IsCfList(char *type)
{
char *listTypes[] = { "sl", "il", "rl", "ml", NULL };
int i;
for(i = 0; listTypes[i] != NULL; i++)
{
if(strcmp(type, listTypes[i]) == 0)
{
return true;
}
}
return false;
}
/*******************************************************************/
int AddVariableHash(char *scope,char *lval,void *rval,char rtype,enum cfdatatype dtype,char *fname,int lineno)
{ struct Scope *ptr;
struct Rlist *rp;
struct CfAssoc *assoc;
if (rtype == CF_SCALAR)
{
Debug("AddVariableHash(%s.%s=%s (%s) rtype=%c)\n",scope,lval,rval,CF_DATATYPES[dtype],rtype);
}
else
{
Debug("AddVariableHash(%s.%s=(list) (%s) rtype=%c)\n",scope,lval,CF_DATATYPES[dtype],rtype);
}
if (lval == NULL || scope == NULL)
{
CfOut(cf_error,"","scope.value = %s.%s = %s",scope,lval,rval);
ReportError("Bad variable or scope in a variable assignment");
FatalError("Should not happen - forgotten to register a function call in fncall.c?");
}
if (rval == NULL)
{
Debug("No value to assignment - probably a parameter in an unused bundle/body\n");
return false;
}
if (strlen(lval) > CF_MAXVARSIZE)
{
ReportError("variable lval too long");
return false;
}
/* If we are not expanding a body template, check for recursive singularities */
if (strcmp(scope,"body") != 0)
{
switch (rtype)
{
case CF_SCALAR:
if (StringContainsVar((char *)rval,lval))
{
CfOut(cf_error,"","Scalar variable %s.%s contains itself (non-convergent): %s",scope,lval,(char *)rval);
return false;
}
break;
case CF_LIST:
for (rp = rval; rp != NULL; rp=rp->next)
{
if (StringContainsVar((char *)rp->item,lval))
{
CfOut(cf_error,"","List variable %s contains itself (non-convergent)",lval);
return false;
}
}
break;
}
}
ptr = GetScope(scope);
if (ptr == NULL)
{
return false;
}
// Look for outstanding lists in variable rvals
if (THIS_AGENT_TYPE == cf_common)
{
struct Rlist *listvars = NULL, *scalarvars = NULL;
if (strcmp(CONTEXTID,"this") != 0)
{
ScanRval(CONTEXTID,&scalarvars,&listvars,rval,rtype,NULL);
if (listvars != NULL)
{
CfOut(cf_error,""," !! Redefinition of variable \"%s\" (embedded list in RHS) in context \"%s\"",lval,CONTEXTID);
}
DeleteRlist(scalarvars);
DeleteRlist(listvars);
}
}
assoc = HashLookupElement(ptr->hashtable, lval);
if (assoc)
{
if (CompareVariableValue(rval, rtype, assoc) == 0)
{
/* Identical value, keep as is */
}
else
{
/* Different value, bark and replace */
if (!UnresolvedVariables(assoc, rtype))
{
CfOut(cf_inform,""," !! Duplicate selection of value for variable \"%s\" in scope %s",lval,ptr->scope);
if (fname)
{
CfOut(cf_inform,""," !! Rule from %s at/before line %d\n",fname,lineno);
}
else
{
CfOut(cf_inform,""," !! in bundle parameterization\n",fname,lineno);
}
}
DeleteRvalItem(assoc->rval, assoc->rtype);
assoc->rval = CopyRvalItem(rval, rtype);
assoc->rtype = rtype;
assoc->dtype = dtype;
Debug("Stored \"%s\" in context %s\n",lval,scope);
}
}
else
{
if (!HashInsertElement(ptr->hashtable, lval, rval, rtype, dtype))
{
FatalError("Hash table is full");
}
}
Debug("Added Variable %s in scope %s with value (omitted)\n",lval,scope);
return true;
}
/*******************************************************************/
void DeRefListsInHashtable(char *scope,struct Rlist *namelist,struct Rlist *dereflist)
// Go through scope and for each variable in name-list, replace with a
// value from the deref "lol" (list of lists) clock
{ int len;
struct Scope *ptr;
struct Rlist *rp,*state;
struct CfAssoc *cplist;
HashIterator i;
CfAssoc *assoc;
if ((len = RlistLen(namelist)) != RlistLen(dereflist))
{
CfOut(cf_error,""," !! Name list %d, dereflist %d\n",len, RlistLen(dereflist));
FatalError("Software Error DeRefLists... correlated lists not same length");
}
if (len == 0)
{
return;
}
ptr = GetScope(scope);
i = HashIteratorInit(ptr->hashtable);
while ((assoc = HashIteratorNext(&i)))
{
for (rp = dereflist; rp != NULL; rp = rp->next)
{
cplist = (struct CfAssoc *)rp->item;
if (strcmp(cplist->lval,assoc->lval) == 0)
{
/* Link up temp hash to variable lol */
state = (struct Rlist *)(cplist->rval);
if (rp->state_ptr == NULL || rp->state_ptr->type == CF_FNCALL)
{
/* Unexpanded function, or blank variable must be skipped.*/
return;
}
if (rp->state_ptr)
{
Debug("Rewriting expanded type for %s from %s to %s\n",assoc->lval,CF_DATATYPES[assoc->dtype],rp->state_ptr->item);
// must first free existing rval in scope, then allocate new (should always be string)
DeleteRvalItem(assoc->rval,assoc->rtype);
// avoids double free - borrowing value from lol (freed in DeleteScope())
assoc->rval = strdup(rp->state_ptr->item);
}
switch(assoc->dtype)
{
case cf_slist:
assoc->dtype = cf_str;
assoc->rtype = CF_SCALAR;
break;
case cf_ilist:
assoc->dtype = cf_int;
assoc->rtype = CF_SCALAR;
break;
case cf_rlist:
assoc->dtype = cf_real;
assoc->rtype = CF_SCALAR;
break;
}
Debug(" to %s\n",CF_DATATYPES[assoc->dtype]);
}
}
}
}
cfengine-3.2.4/src/verify_environments.c 0000644 0001750 0001750 00000004172 11715232734 015276 0000000 0000000 /*
Copyright (C) Cfengine AS
This file is part of Cfengine 3 - written and maintained by Cfengine 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 Commerical Open Source License
(COSL) may apply to this file if you as a licensee so wish it. See
included file COSL.txt.
*/
/*****************************************************************************/
/* */
/* File: verify_environments.c */
/* */
/* Created: Mon May 17 08:50:59 2010 */
/* */
/*****************************************************************************/
#include "cf3.defs.h"
#include "cf3.extern.h"
/*****************************************************************************/
void VerifyEnvironmentsPromise(struct Promise *pp)
{
#ifdef HAVE_NOVA
Nova_VerifyEnvironmentsPromise(pp);
#else
CfOut(cf_inform,""," !! Environments promises are not available in the Community Edition of Cfengine");
#endif
}
/*****************************************************************************/
/* Level */
/*****************************************************************************/
cfengine-3.2.4/src/mod_exec.c 0000644 0001750 0001750 00000010266 11715232734 012747 0000000 0000000 /*
Copyright (C) Cfengine AS
This file is part of Cfengine 3 - written and maintained by Cfengine 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 Commerical Open Source License
(COSL) may apply to this file if you as a licensee so wish it. See
included file COSL.txt.
*/
/*****************************************************************************/
/* */
/* File: mod_exec.c */
/* */
/*****************************************************************************/
/*
This file can act as a template for adding functionality to cfengine 3.
All functionality can be added by extending the main array
CF_MOD_SUBTYPES[CF3_MODULES]
and its array dimension, in mod_common, in the manner shown here.
*/
#define CF3_MOD_EXEC
#include "cf3.defs.h"
#include "cf3.extern.h"
/***********************************************************/
/* Read this module file backwards, as dependencies have */
/* to be defined first - these arrays declare pairs of */
/* constraints */
/* */
/* lval => rval */
/* */
/* in the form (lval,type,range) */
/* */
/* If the type is cf_body then the range is a pointer */
/* to another array of pairs, like in a body "sub-routine" */
/* */
/***********************************************************/
/***************************************************************/
struct BodySyntax CF_EXECCONTAIN_BODY[] =
{
{"useshell",cf_opts,CF_BOOL,"true/false embed the command in a shell environment (true)"},
{"umask",cf_opts,"0,77,22,27,72,077,022,027,072","The umask value for the child process"},
{"exec_owner",cf_str,"","The user name or id under which to run the process"},
{"exec_group",cf_str,"","The group name or id under which to run the process"},
{"exec_timeout",cf_int,"1,3600","Timeout in seconds for command completion"},
{"chdir",cf_str,CF_ABSPATHRANGE,"Directory for setting current/base directory for the process"},
{"chroot",cf_str,CF_ABSPATHRANGE,"Directory of root sandbox for process"},
{"preview",cf_opts,CF_BOOL,"true/false preview command when running in dry-run mode (with -n)"},
{"no_output",cf_opts,CF_BOOL,"true/false discard all output from the command"},
{NULL,cf_notype,NULL,NULL}
};
/***************************************************************/
/* This is the primary set of constraints for an exec object */
struct BodySyntax CF_EXEC_BODIES[] =
{
{"args",cf_str,"","Alternative string of arguments for the command (concatenated with promiser string)"},
{"contain",cf_body,CF_EXECCONTAIN_BODY,"Containment options for the execution process"},
{"module",cf_opts,CF_BOOL,"true/false whether to expect the cfengine module protocol"},
{NULL,cf_notype,NULL,NULL}
};
/***************************************************************/
/* This is the point of entry from mod_common.c */
/***************************************************************/
struct SubTypeSyntax CF_EXEC_SUBTYPES[] =
{
{"agent","commands",CF_EXEC_BODIES},
{NULL,NULL,NULL},
};
cfengine-3.2.4/src/mod_process.c 0000644 0001750 0001750 00000013122 11715232734 013473 0000000 0000000 /*
Copyright (C) Cfengine AS
This file is part of Cfengine 3 - written and maintained by Cfengine 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 Commerical Open Source License
(COSL) may apply to this file if you as a licensee so wish it. See
included file COSL.txt.
*/
/*****************************************************************************/
/* */
/* File: mod_process.c */
/* */
/*****************************************************************************/
/*
This file can act as a template for adding functionality to cfengine 3.
All functionality can be added by extending the main array
CF_MOD_SUBTYPES[CF3_MODULES]
and its array dimension, in mod_common, in the manner shown here.
*/
#define CF3_MOD_PROCESS
#include "cf3.defs.h"
#include "cf3.extern.h"
/***********************************************************/
/* Read this module file backwards, as dependencies have */
/* to be defined first - these arrays declare pairs of */
/* constraints */
/* */
/* lval => rval */
/* */
/* in the form (lval,type,range) */
/* */
/* If the type is cf_body then the range is a pointer */
/* to another array of pairs, like in a body "sub-routine" */
/* */
/***********************************************************/
struct BodySyntax CF_MATCHCLASS_BODY[] =
{
{"in_range_define",cf_slist,"","List of classes to define if the matches are in range"},
{"match_range",cf_irange,CF_VALRANGE,"Integer range for acceptable number of matches for this process"},
{"out_of_range_define",cf_slist,"","List of classes to define if the matches are out of range"},
{NULL,cf_notype,NULL,NULL}
};
/***************************************************************/
struct BodySyntax CF_PROCFILTER_BODY[] =
{
{"command",cf_str,"","Regular expression matching the command/cmd field of a process"},
{"pid",cf_irange,CF_VALRANGE,"Range of integers matching the process id of a process"},
{"pgid",cf_irange,CF_VALRANGE,"Range of integers matching the parent group id of a process"},
{"ppid",cf_irange,CF_VALRANGE,"Range of integers matching the parent process id of a process"},
{"priority",cf_irange,"-20,+20","Range of integers matching the priority field (PRI/NI) of a process"},
{"process_owner",cf_slist,"","List of regexes matching the user of a process"},
{"process_result",cf_str,"[(process_owner|pid|ppid||pgid|rsize|vsize|status|command|ttime|stime|tty|priority|threads)[|&!.]*]*","Boolean class expression returning the logical combination of classes set by a process selection test"},
{"rsize",cf_irange,CF_VALRANGE,"Range of integers matching the resident memory size of a process, in kilobytes"},
{"status",cf_str,"","Regular expression matching the status field of a process"},
{"stime_range",cf_irange,CF_TIMERANGE,"Range of integers matching the start time of a process"},
{"ttime_range",cf_irange,CF_TIMERANGE,"Range of integers matching the total elapsed time of a process"},
{"tty",cf_str,"","Regular expression matching the tty field of a process"},
{"threads",cf_irange,CF_VALRANGE,"Range of integers matching the threads (NLWP) field of a process"},
{"vsize",cf_irange,CF_VALRANGE,"Range of integers matching the virtual memory size of a process, in kilobytes"},
{NULL,cf_notype,NULL,NULL}
};
/***************************************************************/
/* This is the primary set of constraints for an exec object */
struct BodySyntax CF_PROCESS_BODIES[] =
{
{"process_count",cf_body,CF_MATCHCLASS_BODY,"Criteria for constraining the number of processes matching other criteria"},
{"process_select",cf_body,CF_PROCFILTER_BODY,"Criteria for matching processes in the system process table"},
{"process_stop",cf_str,CF_ABSPATHRANGE,"A command used to stop a running process"},
{"restart_class",cf_str,CF_IDRANGE,"A class to be defined globally if the process is not running, so that a command: rule can be referred to restart the process"},
{"signals",cf_olist,CF_SIGNALRANGE,"A list of menu options representing signals to be sent to a process"},
{NULL,cf_notype,NULL,NULL}
};
/***************************************************************/
/* This is the point of entry from mod_common.c */
/***************************************************************/
struct SubTypeSyntax CF_PROCESS_SUBTYPES[] =
{
{"agent","processes",CF_PROCESS_BODIES},
{NULL,NULL,NULL},
};
cfengine-3.2.4/src/cf3lex.l.in 0000644 0001750 0001750 00000014564 11715232734 012773 0000000 0000000 %{
/*
Copyright (C) Cfengine AS
This file is part of Cfengine 3 - written and maintained by Cfengine 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 Commerical Open Source License
(COSL) may apply to this file if you as a licensee so wish it. See
included file COSL.txt.
*/
/*******************************************************************/
/* */
/* LEXER for cfengine 3 */
/* */
/*******************************************************************/
#include "cf3.defs.h"
#include "cf3.extern.h"
#include "cf3parse.h"
// Do not use lex - flex only
%}
@NOWRAP@
space [ \t]+
newline ([\n]|[\xd][\xa])
comment #[^\n]*
promises bundle
body body
nakedvar [$@][(][a-zA-Z0-9_\200-\377.]+[)]|[$@][{][a-zA-Z0-9_\200-\377.]+[}]
id [a-zA-Z0-9_\200-\377]+
assign =>
arrow ->
/*
* Three types of quoted strings:
*
* - string in double quotes, starts with double quote, runs until another
* double quote, \" masks the double quote.
* - string in single quotes, starts with single quote, runs until another
* single quote, \' masks the single quote.
* - string in backquotes, starts with backquote, runs until another backquote.
*
* The same rule formatted for the better readability:
*
* := \" \" | \' \' | ` `
* = *
* = \\ | [^"\\]
* = *
* = \\ | [^'\\]
* = *
* = [^`]
* = . | \n
*
*/
qstring \"((\\(.|\n))|[^"\\])*\"|\'((\\(.|\n))|[^'\\])*\'|`[^`]*`
class [.|&!()a-zA-Z0-9_\200-\377]+::
category [a-zA-Z_]+:
%%
{newline} {
P.line_no++;
P.line_pos = 0;
}
{promises} {
/* Note this has to come before "id" since it is a subset of id */
if (P.currentclasses != NULL)
{
free(P.currentclasses);
P.currentclasses = NULL;
}
P.line_pos += strlen(yytext);
return BUNDLE;
}
{body} {
/* Note this has to come before "id" since it is a subset of id */
if (P.currentclasses != NULL)
{
free(P.currentclasses);
P.currentclasses = NULL;
}
P.line_pos += strlen(yytext);
return BODY;
}
{id} {
P.line_pos += strlen(yytext);
if (strlen(yytext) > CF_MAXVARSIZE-1)
{
yyerror("identifier too long");
}
strncpy(P.currentid,yytext,CF_MAXVARSIZE);
return ID;
}
{assign} {
P.line_pos += strlen(yytext);
return ASSIGN;
}
{arrow} {
P.line_pos += strlen(yytext);
return ARROW;
}
{class} {
P.line_pos += strlen(yytext);
if (P.currentclasses != NULL)
{
free(P.currentclasses);
}
yytext[strlen(yytext)-2] = '\0';
ValidateClassSyntax(yytext);
P.currentclasses = strdup(yytext);
return CLASS;
}
{category} {
P.line_pos += strlen(yytext);
yytext[strlen(yytext)-1] = '\0';
strncpy(P.currenttype,yytext,CF_MAXVARSIZE);
if (P.currentclasses != NULL)
{
free(P.currentclasses);
P.currentclasses = NULL;
}
return CATEGORY;
}
{qstring} {
char *tmp = NULL;
int less = 0;
P.line_pos += strlen(yytext);
if ((tmp = malloc(strlen(yytext)+1)) == NULL)
{
FatalError("Malloc failure in parsing");
}
if ((less = DeEscapeQuotedString(yytext,tmp)) > 0)
{
yyless(less);
}
if (P.currentstring)
{
free(P.currentstring);
}
P.currentstring = strdup(tmp);
if (THIS_AGENT_TYPE == cf_common)
{
IsCf3VarString(tmp);
}
free(tmp);
return QSTRING;
}
{nakedvar} {
P.line_pos += strlen(yytext);
P.currentstring = strdup(yytext);
return NAKEDVAR;
}
{space}+ {
P.line_pos += strlen(yytext);
}
{comment} {
}
. {
P.line_pos++;
return yytext[0];
}
%%
/* EOF */
cfengine-3.2.4/src/cf.extern.h 0000644 0001750 0001750 00000012461 11715232734 013064 0000000 0000000 /*
Copyright (C) Cfengine AS
This file is part of Cfengine 3 - written and maintained by Cfengine 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 Commerical 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_EXTERN_H
#define CFENGINE_CF_EXTERN_H
#include "../pub/getopt.h"
#if defined HAVE_PTHREAD_H && (defined HAVE_LIBPTHREAD || defined BUILDTIN_GCC_THREAD)
extern pthread_mutex_t MUTEX_SYSCALL;
extern pthread_mutex_t MUTEX_LOCK;
extern pthread_attr_t PTHREADDEFAULTS;
extern pthread_mutex_t MUTEX_COUNT;
extern pthread_mutex_t MUTEX_OUTPUT;
extern pthread_mutex_t MUTEX_DBHANDLE;
extern pthread_mutex_t MUTEX_POLICY;
extern pthread_mutex_t MUTEX_GETADDR;
extern pthread_mutex_t MUTEX_DB_LASTSEEN;
extern pthread_mutex_t MUTEX_DB_REPORT;
extern pthread_mutex_t MUTEX_VSCOPE;
extern pthread_mutex_t MUTEX_SERVER_KEYSEEN;
extern pthread_mutex_t MUTEX_SERVER_CHILDREN;
# endif
extern pid_t ALARM_PID;
extern RSA *PRIVKEY, *PUBKEY;
extern char PUBKEY_DIGEST[CF_MAXVARSIZE];
extern char BINDINTERFACE[CF_BUFSIZE];
extern struct sock ECGSOCKS[ATTR];
extern char *TCPNAMES[CF_NETATTR];
extern struct Audit *AUDITPTR;
extern struct Audit *VAUDIT;
extern int PR_KEPT;
extern int PR_REPAIRED;
extern int PR_NOTKEPT;
extern char CONTEXTID[32];
extern char PADCHAR;
extern struct Item *IPADDRESSES;
extern char PIDFILE[CF_BUFSIZE];
extern char STR_CFENGINEPORT[16];
extern unsigned short SHORT_CFENGINEPORT;
extern time_t CONNTIMEOUT;
extern time_t RECVTIMEOUT;
extern char CFLOCK[CF_BUFSIZE];
extern char CFLOG[CF_BUFSIZE];
extern char CFLAST[CF_BUFSIZE];
extern char LOCKDB[CF_BUFSIZE];
extern int CFSIGNATURE; /*?*/
extern char CFPUBKEYFILE[CF_BUFSIZE];
extern char CFPRIVKEYFILE[CF_BUFSIZE];
extern char CFWORKDIR[CF_BUFSIZE];
extern char AVDB[CF_MAXVARSIZE];
extern char VYEAR[];
extern char VDAY[];
extern char VMONTH[];
extern char VSHIFT[];
extern char *CLASSTEXT[];
extern char *CLASSATTRIBUTES[CF_CLASSATTR][CF_ATTRDIM];
extern char VINPUTFILE[];
extern CF_DB *AUDITDBP;
extern int AUDIT;
extern char REPOSCHAR;
extern char PURGE;
extern int CHECKSUMUPDATES;
extern int ERRORCOUNT;
extern time_t CFSTARTTIME;
extern time_t CFINITSTARTTIME;
extern struct utsname VSYSNAME;
extern mode_t DEFAULTMODE;
extern char *PROTOCOL[];
extern char VIPADDRESS[];
extern char VPREFIX[];
extern int VRECURSE;
extern int RPCTIMEOUT;
extern int SKIPIDENTIFY;
extern char DEFAULTCOPYTYPE;
extern char VDOMAIN[CF_MAXVARSIZE];
extern char VMAILSERVER[CF_BUFSIZE];
extern struct Item *VDEFAULTROUTE;
extern char *VREPOSITORY;
extern enum classes VSYSTEMHARDCLASS;
extern char VFQNAME[];
extern char VUQNAME[];
extern char LOGFILE[];
extern struct Item *VNEGHEAP;
extern struct Item *VDELCLASSES;
extern struct Item *ABORTHEAP;
extern struct Mounted *MOUNTED; /* Files systems already mounted */
extern struct Item *VSETUIDLIST;
extern struct Item *SUSPICIOUSLIST;
extern struct Item *SCHEDULE;
extern struct Item *NONATTACKERLIST;
extern struct Item *MULTICONNLIST;
extern struct Item *TRUSTKEYLIST;
extern struct Item *DHCPLIST;
extern struct Item *ALLOWUSERLIST;
extern struct Item *SKIPVERIFY;
extern struct Item *ATTACKERLIST;
extern struct AlphaList VHEAP;
extern struct AlphaList VADDCLASSES;
extern struct Rlist *PRIVCLASSHEAP;
extern struct Item *VREPOSLIST;
extern struct Auth *VADMIT;
extern struct Auth *VDENY;
extern struct Auth *VADMITTOP;
extern struct Auth *VDENYTOP;
extern struct Auth *VARADMIT;
extern struct Auth *VARADMITTOP;
extern struct Auth *VARDENY;
extern struct Auth *VARDENYTOP;
extern int DEBUG;
extern int D1;
extern int D2;
extern int D3;
extern int D4;
extern int PARSING;
extern int VERBOSE;
extern int EXCLAIM;
extern int INFORM;
extern int LOGGING;
extern int CFPARANOID;
extern int DONTDO;
extern int IGNORELOCK;
extern int MINUSF;
extern int NOSPLAY;
extern char *VPSCOMM[];
extern char *VPSOPTS[];
extern char *VMOUNTCOMM[];
extern char *VMOUNTOPTS[];
extern char *VRESOLVCONF[];
extern char *VHOSTEQUIV[];
extern char *VFSTAB[];
extern char *VMAILDIR[];
extern char *VNETSTAT[];
extern char *VEXPORTS[];
extern char *VROUTE[];
extern char *VROUTEADDFMT[];
extern char *VROUTEDELFMT[];
extern char *VUNMOUNTCOMM[];
extern char *SIGNALS[];
#ifndef MINGW
extern char *tzname[2]; /* see man ctime */
#endif
extern int EDITFILESIZE;
extern int EDITBINFILESIZE;
extern int VIFELAPSED;
extern int VEXPIREAFTER;
extern char *OBS[CF_OBSERVABLES][2];
extern char *CF_DIGEST_TYPES[10][2];
extern int CF_DIGEST_SIZES[10];
/* Windows version constants */
extern unsigned int WINVER_MAJOR;
extern unsigned int WINVER_MINOR;
extern unsigned int WINVER_BUILD;
#endif
cfengine-3.2.4/src/files_properties.c 0000644 0001750 0001750 00000011067 11715232734 014542 0000000 0000000 /*
Copyright (C) Cfengine AS
This file is part of Cfengine 3 - written and maintained by Cfengine 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 Commerical Open Source License
(COSL) may apply to this file if you as a licensee so wish it. See
included file COSL.txt.
*/
/*****************************************************************************/
/* */
/* File: files_properties.c */
/* */
/*****************************************************************************/
#include "cf3.defs.h"
#include "cf3.extern.h"
/*********************************************************************/
/* Files to be ignored when parsing directories */
/*********************************************************************/
/*********************************************************************/
int ConsiderFile(const char *nodename,char *path,struct Attributes attr,struct Promise *pp)
{ int i, suspicious = true;
struct stat statbuf;
char newname[CF_BUFSIZE],vbuff[CF_BUFSIZE];
const char *sp;
static char *skipfiles[] =
{
".",
"..",
"lost+found",
".cfengine.rm",
NULL
};
if (strlen(nodename) < 1)
{
CfOut(cf_error,"","Empty (null) filename detected in %s\n",path);
return true;
}
if (IsItemIn(SUSPICIOUSLIST,nodename))
{
struct stat statbuf;
if (cfstat(nodename,&statbuf) != -1)
{
if (S_ISREG(statbuf.st_mode))
{
CfOut(cf_error,"","Suspicious file %s found in %s\n",nodename,path);
return false;
}
}
}
if (strcmp(nodename,"...") == 0)
{
CfOut(cf_verbose,"","Possible DFS/FS cell node detected in %s...\n",path);
return true;
}
for (i = 0; skipfiles[i] != NULL; i++)
{
if (strcmp(nodename,skipfiles[i]) == 0)
{
Debug("Filename %s/%s is classified as ignorable\n",path,nodename);
return false;
}
}
if ((strcmp("[",nodename) == 0) && (strcmp("/usr/bin",path) == 0))
{
if (VSYSTEMHARDCLASS == linuxx)
{
return true;
}
}
suspicious = true;
for (sp = nodename; *sp != '\0'; sp++)
{
if ((*sp > 31) && (*sp < 127))
{
suspicious = false;
break;
}
}
strcpy(vbuff,path);
AddSlash(vbuff);
strcat(vbuff,nodename);
for (sp = nodename; *sp != '\0'; sp++) /* Check for files like ".. ." */
{
if ((*sp != '.') && ! isspace(*sp))
{
suspicious = false;
return true;
}
}
if (cf_lstat(vbuff,&statbuf,attr,pp) == -1)
{
CfOut(cf_verbose,"lstat","Couldn't stat %s",vbuff);
return true;
}
if (statbuf.st_size == 0 && ! (VERBOSE||INFORM)) /* No sense in warning about empty files */
{
return false;
}
CfOut(cf_error,"","Suspicious looking file object \"%s\" masquerading as hidden file in %s\n",nodename,path);
Debug("Filename looks suspicious\n");
if (S_ISLNK(statbuf.st_mode))
{
CfOut(cf_inform,""," %s is a symbolic link\n",nodename);
}
else if (S_ISDIR(statbuf.st_mode))
{
CfOut(cf_inform,""," %s is a directory\n",nodename);
}
CfOut(cf_verbose,"","[%s] has size %ld and full mode %o\n",nodename,(unsigned long)(statbuf.st_size),(unsigned int)(statbuf.st_mode));
return true;
}
/********************************************************************/
void SetSearchDevice(struct stat *sb,struct Promise *pp)
{
Debug("Registering root device as %d\n",sb->st_dev);
pp->rootdevice = sb->st_dev;
}
/********************************************************************/
int DeviceBoundary(struct stat *sb,struct Promise *pp)
{
if (sb->st_dev == pp->rootdevice)
{
return false;
}
else
{
CfOut(cf_verbose,"","Device change from %d to %d\n",pp->rootdevice,sb->st_dev);
return true;
}
}
cfengine-3.2.4/src/cf3.server.h 0000644 0001750 0001750 00000005027 11715232734 013150 0000000 0000000 /*
Copyright (C) Cfengine AS
This file is part of Cfengine 3 - written and maintained by Cfengine 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 Commerical Open Source License
(COSL) may apply to this file if you as a licensee so wish it. See
included file COSL.txt.
*/
/*******************************************************************/
/* */
/* HEADER for cfServerd - Not generically includable! */
/* */
/*******************************************************************/
#ifndef CFENGINE_CF3_SERVER_H
#define CFENGINE_CF3_SERVER_H
#define queuesize 50
#define connection 1
#define RFC931_PORT 113
#define CF_BUFEXT 128
/**********************************************************************/
struct cfd_connection
{
int id_verified;
int rsa_auth;
int synchronized;
int maproot;
int trust;
int sd_reply;
unsigned char *session_key;
unsigned char digest[EVP_MAX_MD_SIZE+1];
char hostname[CF_MAXVARSIZE];
char username[CF_MAXVARSIZE];
#ifdef MINGW
char sid[CF_MAXSIDSIZE]; /* we avoid dynamically allocated buffers due to potential memory leaks */
#else
uid_t uid;
#endif
char encryption_type;
char ipaddr[CF_MAX_IP_LEN];
char output[CF_BUFSIZE*2]; /* Threadsafe output channel */
};
struct cfd_get_arg
{
struct cfd_connection *connect;
int encrypt;
int buf_size;
char *replybuff;
char *replyfile;
};
/*******************************************************************/
/* PARSER */
/*******************************************************************/
extern char CFRUNCOMMAND[];
extern time_t CFDSTARTTIME;
#ifdef RE_DUP_MAX
# undef RE_DUP_MAX
#endif
#endif
cfengine-3.2.4/src/hashes.c 0000644 0001750 0001750 00000015375 11715232734 012445 0000000 0000000 /*
Copyright (C) Cfengine AS
This file is part of Cfengine 3 - written and maintained by Cfengine 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 Commerical Open Source License
(COSL) may apply to this file if you as a licensee so wish it. See
included file COSL.txt.
*/
/*****************************************************************************/
/* */
/* File: hashes.c */
/* */
/*****************************************************************************/
#include "cf3.defs.h"
#include "cf3.extern.h"
static void EditHashValue(char *scopeid,char *lval,void *rval);
/*******************************************************************/
/* Hashes */
/*******************************************************************/
void InitHashes(struct CfAssoc **table)
{ int i;
for (i = 0; i < CF_HASHTABLESIZE; i++)
{
table[i] = NULL;
}
}
/******************************************************************/
void CopyHashes(struct CfAssoc **newhash,struct CfAssoc **oldhash)
{ int i;
for (i = 0; i < CF_HASHTABLESIZE; i++)
{
newhash[i] = CopyAssoc(oldhash[i]);
}
}
/******************************************************************/
static void EditHashValue(char *scopeid,char *lval,void *rval)
{ int found, slot = GetHash(lval);
int i = slot;
struct Scope *ptr = GetScope(scopeid);
struct CfAssoc *ap;
Debug("EditHashValue(%s,%s)\n",scopeid,lval);
if (CompareVariable(lval,ptr->hashtable[slot]) != 0)
{
/* Recover from hash collision */
while (true)
{
i++;
if (i >= CF_HASHTABLESIZE-1)
{
i = 0;
}
if (CompareVariable(lval,ptr->hashtable[i]) == 0)
{
found = true;
break;
}
/* Removed autolookup in Unix environment variables -
implement as getenv() fn instead */
if (i == slot)
{
found = false;
break;
}
}
if (!found)
{
Debug("No such variable found %s.%s\n",scopeid,lval);
return;
}
}
ap = ptr->hashtable[i];
ap->rval = rval;
}
/******************************************************************/
void DeleteHashes(struct CfAssoc **hashtable)
{ int i;
if (hashtable)
{
for (i = 0; i < CF_HASHTABLESIZE; i++)
{
if (hashtable[i] != NULL)
{
DeleteAssoc(hashtable[i]);
hashtable[i] = NULL;
}
}
}
}
/*******************************************************************/
void PrintHashes(FILE *fp,struct CfAssoc **table,int html)
{ int i;
if (html)
{
fprintf(fp,"
\n");
fprintf (fp,"
id
dtype
rtype
identifier
Rvalue
\n");
}
for (i = 0; i < CF_HASHTABLESIZE; i++)
{
if (table[i] != NULL)
{
if (html)
{
fprintf (fp,"
\n");
}
}
/*******************************************************************/
int GetHash(const char *name)
{
return OatHash(name);
}
/*******************************************************************/
bool HashInsertElement(CfAssoc **hashtable, const char *element,
void *rval, char rtype, enum cfdatatype dtype)
{
int bucket = GetHash(element);
int i = bucket;
do
{
/* Collision -- this element already exists */
if (CompareVariable(element, hashtable[i]) == 0)
{
return false;
}
/* Free bucket is found */
if (hashtable[i] == NULL)
{
hashtable[i] = NewAssoc(element, rval, rtype, dtype);
return true;
}
i = (i + 1) % CF_HASHTABLESIZE;
}
while (i != bucket);
/* Hash table is full */
return false;
}
/*******************************************************************/
bool HashDeleteElement(CfAssoc **hashtable, const char *element)
{
int bucket = GetHash(element);
int i = bucket;
do
{
/* Element is found */
if (hashtable[i] && strcmp(element, hashtable[i]->lval) == 0)
{
DeleteAssoc(hashtable[i]);
hashtable[i] = NULL;
return true;
}
i = (i + 1) % CF_HASHTABLESIZE;
}
while (i != bucket);
/* Looped through whole hashtable and did not find needed element */
return false;
}
/*******************************************************************/
CfAssoc *HashLookupElement(CfAssoc **hashtable, const char *element)
{
int bucket = GetHash(element);
int i = bucket;
do
{
/* Element is found */
if (CompareVariable(element, hashtable[i]) == 0)
{
return hashtable[i];
}
i = (i + 1) % CF_HASHTABLESIZE;
}
while (i != bucket);
/* Looped through whole hashtable and did not find needed element */
return NULL;
}
/*******************************************************************/
void HashClear(CfAssoc **hashtable)
{
int i;
for (i = 0; i < CF_HASHTABLESIZE; i++)
{
if (hashtable[i] != NULL)
{
DeleteAssoc(hashtable[i]);
hashtable[i] = NULL;
}
}
}
/*******************************************************************/
HashIterator HashIteratorInit(CfAssoc **hashtable)
{
return (HashIterator) { hashtable, 0 };
}
/*******************************************************************/
CfAssoc *HashIteratorNext(HashIterator *i)
{
while (i->bucket < CF_HASHTABLESIZE && i->hash[i->bucket] == NULL)
i->bucket++;
if (i->bucket == CF_HASHTABLESIZE)
{
return NULL;
}
else
{
return i->hash[i->bucket++];
}
}
cfengine-3.2.4/src/files_editline.c 0000644 0001750 0001750 00000127375 11715232734 014155 0000000 0000000 /*
Copyright (C) Cfengine AS
This file is part of Cfengine 3 - written and maintained by Cfengine 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 Commerical Open Source License
(COSL) may apply to this file if you as a licensee so wish it. See
included file COSL.txt.
*/
/*****************************************************************************/
/* */
/* File: files_edit_operators.c */
/* */
/*****************************************************************************/
#include "cf3.defs.h"
#include "cf3.extern.h"
/*****************************************************************************/
enum editlinetypesequence
{
elp_vars,
elp_classes,
elp_delete,
elp_columns,
elp_insert,
elp_replace,
elp_reports,
elp_none
};
char *EDITLINETYPESEQUENCE[] =
{
"vars",
"classes",
"delete_lines",
"field_edits",
"insert_lines",
"replace_patterns",
"reports",
NULL
};
static void KeepEditLinePromise(struct Promise *pp);
static void VerifyLineDeletions(struct Promise *pp);
static void VerifyColumnEdits(struct Promise *pp);
static void VerifyPatterns(struct Promise *pp);
static void VerifyLineInsertions(struct Promise *pp);
static int InsertMissingLinesToRegion(struct Item **start,struct Item *begin_ptr,struct Item *end_ptr,struct Attributes a,struct Promise *pp);
static int InsertMissingLinesAtLocation(struct Item **start,struct Item *begin_ptr,struct Item *end_ptr,struct Item *location,struct Item *prev,struct Attributes a,struct Promise *pp);
static int DeletePromisedLinesMatching(struct Item **start,struct Item *begin,struct Item *end,struct Attributes a,struct Promise *pp);
static int InsertMissingLineAtLocation(char *newline,struct Item **start,struct Item *location,struct Item *prev,struct Attributes a,struct Promise *pp);
static int InsertCompoundLineAtLocation(char *newline,struct Item **start,struct Item *location,struct Item *prev,struct Attributes a,struct Promise *pp);
static int ReplacePatterns(struct Item *start,struct Item *end,struct Attributes a,struct Promise *pp);
static int EditColumns(struct Item *file_start,struct Item *file_end,struct Attributes a,struct Promise *pp);
static int EditLineByColumn(struct Rlist **columns,struct Attributes a,struct Promise *pp);
static int EditColumn(struct Rlist **columns,struct Attributes a,struct Promise *pp);
static int SanityCheckInsertions(struct Attributes a);
static int SanityCheckDeletions(struct Attributes a,struct Promise *pp);
static int SelectLine(char *line,struct Attributes a,struct Promise *pp);
static int NotAnchored(char *s);
static void EditClassBanner(enum editlinetypesequence type);
static int SelectRegion(struct Item *start,struct Item **begin_ptr,struct Item **end_ptr,struct Attributes a,struct Promise *pp);
/*****************************************************************************/
/* Level */
/*****************************************************************************/
int ScheduleEditLineOperations(char *filename,struct Bundle *bp,struct Attributes a,struct Promise *parentp)
{ enum editlinetypesequence type;
struct SubType *sp;
struct Promise *pp;
char lockname[CF_BUFSIZE];
char *bp_stack = THIS_BUNDLE;
struct CfLock thislock;
int pass;
snprintf(lockname,CF_BUFSIZE-1,"masterfilelock-%s",filename);
thislock = AcquireLock(lockname,VUQNAME,CFSTARTTIME,a,parentp,true);
if (thislock.lock == NULL)
{
return false;
}
NewScope("edit");
NewScalar("edit","filename",filename,cf_str);
/* Reset the done state for every call here, since bundle is reusable */
for (type = 0; EDITLINETYPESEQUENCE[type] != NULL; type++)
{
if ((sp = GetSubTypeForBundle(EDITLINETYPESEQUENCE[type],bp)) == NULL)
{
continue;
}
for (pp = sp->promiselist; pp != NULL; pp=pp->next)
{
pp->donep = false;
}
}
for (pass = 1; pass < CF_DONEPASSES; pass++)
{
for (type = 0; EDITLINETYPESEQUENCE[type] != NULL; type++)
{
EditClassBanner(type);
if ((sp = GetSubTypeForBundle(EDITLINETYPESEQUENCE[type],bp)) == NULL)
{
continue;
}
BannerSubSubType(bp->name,sp->name);
THIS_BUNDLE = bp->name;
SetScope(bp->name);
for (pp = sp->promiselist; pp != NULL; pp=pp->next)
{
pp->edcontext = parentp->edcontext;
pp->this_server = filename;
pp->donep = &(pp->done);
ExpandPromise(cf_agent,bp->name,pp,KeepEditLinePromise);
if (Abort())
{
THIS_BUNDLE = bp_stack;
DeleteScope("edit");
YieldCurrentLock(thislock);
return false;
}
}
}
}
DeleteScope("edit");
SetScope(parentp->bundle);
THIS_BUNDLE = bp_stack;
YieldCurrentLock(thislock);
return true;
}
/***************************************************************************/
/* Level */
/***************************************************************************/
static void EditClassBanner(enum editlinetypesequence type)
{ struct Item *ip;
int i;
if (type != elp_delete) /* Just parsed all local classes */
{
return;
}
CfOut(cf_verbose,""," ?? Private class context\n");
for (i = 0; i < CF_ALPHABETSIZE; i++)
{
for (ip = VADDCLASSES.list[i]; ip != NULL; ip=ip->next)
{
CfOut(cf_verbose,""," ?? %s\n",ip->name);
}
}
CfOut(cf_verbose,"","\n");
}
/***************************************************************************/
static void KeepEditLinePromise(struct Promise *pp)
{ char *sp = NULL;
if (!IsDefinedClass(pp->classes))
{
CfOut(cf_verbose,"","\n");
CfOut(cf_verbose,""," . . . . . . . . . . . . . . . \n");
CfOut(cf_verbose,""," Skipping whole next edit promise, as context %s is not relevant\n",pp->classes);
CfOut(cf_verbose,""," . . . . . . . . . . . . . . . \n");
return;
}
if (pp->done)
{
// return;
}
if (VarClassExcluded(pp,&sp))
{
CfOut(cf_verbose,"","\n");
CfOut(cf_verbose,"",". . . . . . . . . . . . . . . . . . . . . . . . . . . . \n");
CfOut(cf_verbose,"","Skipping whole next edit promise (%s), as var-context %s is not relevant\n",pp->promiser,sp);
CfOut(cf_verbose,"",". . . . . . . . . . . . . . . . . . . . . . . . . . . . \n");
return;
}
PromiseBanner(pp);
if (strcmp("classes",pp->agentsubtype) == 0)
{
KeepClassContextPromise(pp);
return;
}
if (strcmp("delete_lines",pp->agentsubtype) == 0)
{
VerifyLineDeletions(pp);
return;
}
if (strcmp("field_edits",pp->agentsubtype) == 0)
{
VerifyColumnEdits(pp);
return;
}
if (strcmp("insert_lines",pp->agentsubtype) == 0)
{
VerifyLineInsertions(pp);
return;
}
if (strcmp("replace_patterns",pp->agentsubtype) == 0)
{
VerifyPatterns(pp);
return;
}
if (strcmp("reports",pp->agentsubtype) == 0)
{
VerifyReportPromise(pp);
return;
}
}
/***************************************************************************/
/* Level */
/***************************************************************************/
static void VerifyLineDeletions(struct Promise *pp)
{ struct Item **start = &(pp->edcontext->file_start);
struct Attributes a = {{0}};
struct Item *begin_ptr,*end_ptr;
struct CfLock thislock;
char lockname[CF_BUFSIZE];
/* *(pp->donep) = true; */
a = GetDeletionAttributes(pp);
a.transaction.ifelapsed = CF_EDIT_IFELAPSED;
if (!SanityCheckDeletions(a,pp))
{
cfPS(cf_error,CF_INTERPT,"",pp,a," !! The promised line deletion (%s) is inconsistent",pp->promiser);
return;
}
/* Are we working in a restricted region? */
if (!a.haveregion)
{
begin_ptr = CF_UNDEFINED_ITEM;
end_ptr = CF_UNDEFINED_ITEM;
}
else if (!SelectRegion(*start,&begin_ptr,&end_ptr,a,pp))
{
if (a.region.include_end || a.region.include_start)
{
cfPS(cf_verbose,CF_INTERPT,"",pp,a," !! The promised line deletion (%s) could not select an edit region in %s (this is a good thing, as policy suggests deleting the markers)",pp->promiser,pp->this_server);
}
else
{
cfPS(cf_inform,CF_INTERPT,"",pp,a," !! The promised line deletion (%s) could not select an edit region in %s (but the delimiters were expected in the file)",pp->promiser,pp->this_server);
}
return;
}
snprintf(lockname,CF_BUFSIZE-1,"deleteline-%s-%s",pp->promiser,pp->this_server);
thislock = AcquireLock(lockname,VUQNAME,CFSTARTTIME,a,pp,true);
if (thislock.lock == NULL)
{
return;
}
if (DeletePromisedLinesMatching(start,begin_ptr,end_ptr,a,pp))
{
(pp->edcontext->num_edits)++;
}
YieldCurrentLock(thislock);
}
/***************************************************************************/
static void VerifyColumnEdits(struct Promise *pp)
{ struct Item **start = &(pp->edcontext->file_start);
struct Attributes a = {{0}};
struct Item *begin_ptr,*end_ptr;
struct CfLock thislock;
char lockname[CF_BUFSIZE];
/* *(pp->donep) = true; */
a = GetColumnAttributes(pp);
a.transaction.ifelapsed = CF_EDIT_IFELAPSED;
if (a.column.column_separator == NULL)
{
cfPS(cf_error,CF_WARN,"",pp,a,"No field_separator in promise to edit by column for %s",pp->promiser);
PromiseRef(cf_error,pp);
return;
}
if (a.column.select_column <= 0)
{
cfPS(cf_error,CF_WARN,"",pp,a,"No select_field in promise to edit %s",pp->promiser);
PromiseRef(cf_error,pp);
return;
}
if (!a.column.column_value)
{
cfPS(cf_error,CF_WARN,"",pp,a,"No field_value is promised to column_edit %s",pp->promiser);
PromiseRef(cf_error,pp);
return;
}
/* Are we working in a restricted region? */
if (!a.haveregion)
{
begin_ptr = *start;
end_ptr =NULL; // EndOfList(*start);
}
else if (!SelectRegion(*start,&begin_ptr,&end_ptr,a,pp))
{
cfPS(cf_error,CF_INTERPT,"",pp,a," !! The promised column edit (%s) could not select an edit region in %s",pp->promiser,pp->this_server);
return;
}
/* locate and split line */
snprintf(lockname,CF_BUFSIZE-1,"column-%s-%s",pp->promiser,pp->this_server);
thislock = AcquireLock(lockname,VUQNAME,CFSTARTTIME,a,pp,true);
if (thislock.lock == NULL)
{
return;
}
if (EditColumns(begin_ptr,end_ptr,a,pp))
{
(pp->edcontext->num_edits)++;
}
YieldCurrentLock(thislock);
}
/***************************************************************************/
static void VerifyPatterns(struct Promise *pp)
{ struct Item **start = &(pp->edcontext->file_start);
struct Attributes a = {{0}};
struct Item *begin_ptr,*end_ptr;
struct CfLock thislock;
char lockname[CF_BUFSIZE];
/* *(pp->donep) = true; */
CfOut(cf_verbose,""," -> Looking at pattern %s\n",pp->promiser);
/* Are we working in a restricted region? */
a = GetReplaceAttributes(pp);
a.transaction.ifelapsed = CF_EDIT_IFELAPSED;
if (!a.replace.replace_value)
{
cfPS(cf_error,CF_INTERPT,"",pp,a," !! The promised pattern replace (%s) had no replacement string",pp->promiser);
return;
}
if (!a.haveregion)
{
begin_ptr = *start;
end_ptr = NULL; //EndOfList(*start);
}
else if (!SelectRegion(*start,&begin_ptr,&end_ptr,a,pp))
{
cfPS(cf_error,CF_INTERPT,"",pp,a," !! The promised pattern replace (%s) could not select an edit region in %s",pp->promiser,pp->this_server);
return;
}
snprintf(lockname,CF_BUFSIZE-1,"replace-%s-%s",pp->promiser,pp->this_server);
thislock = AcquireLock(lockname,VUQNAME,CFSTARTTIME,a,pp,true);
if (thislock.lock == NULL)
{
return;
}
/* Make sure back references are expanded */
if (ReplacePatterns(begin_ptr,end_ptr,a,pp))
{
(pp->edcontext->num_edits)++;
}
DeleteScope("match"); // because this might pollute the parent promise in next iteration
YieldCurrentLock(thislock);
}
/***************************************************************************/
static void VerifyLineInsertions(struct Promise *pp)
{ struct Item **start = &(pp->edcontext->file_start), *match, *prev;
struct Item *begin_ptr,*end_ptr;
struct Attributes a = {{0}};
struct CfLock thislock;
char lockname[CF_BUFSIZE];
/* *(pp->donep) = true; */
a = GetInsertionAttributes(pp);
a.transaction.ifelapsed = CF_EDIT_IFELAPSED;
if (!SanityCheckInsertions(a))
{
cfPS(cf_error,CF_INTERPT,"",pp,a," !! The promised line insertion (%s) breaks its own promises",pp->promiser);
return;
}
/* Are we working in a restricted region? */
if (!a.haveregion)
{
begin_ptr = *start;
end_ptr = NULL; //EndOfList(*start);
}
else if (!SelectRegion(*start,&begin_ptr,&end_ptr,a,pp))
{
cfPS(cf_error,CF_INTERPT,"",pp,a," !! The promised line insertion (%s) could not select an edit region in %s",pp->promiser,pp->this_server);
return;
}
snprintf(lockname,CF_BUFSIZE-1,"insertline-%s-%s",pp->promiser,pp->this_server);
thislock = AcquireLock(lockname,VUQNAME,CFSTARTTIME,a,pp,true);
if (thislock.lock == NULL)
{
return;
}
/* Are we looking for an anchored line inside the region? */
if (a.location.line_matching == NULL)
{
if (InsertMissingLinesToRegion(start,begin_ptr,end_ptr,a,pp))
{
(pp->edcontext->num_edits)++;
}
}
else
{
if (!SelectItemMatching(*start,a.location.line_matching,begin_ptr,end_ptr,&match,&prev,a.location.first_last))
{
cfPS(cf_error,CF_INTERPT,"",pp,a," !! The promised line insertion (%s) could not select a locator matching regex \"%s\" in %s",pp->promiser,a.location.line_matching,pp->this_server);
YieldCurrentLock(thislock);
return;
}
if (InsertMissingLinesAtLocation(start,begin_ptr,end_ptr,match,prev,a,pp))
{
(pp->edcontext->num_edits)++;
}
}
YieldCurrentLock(thislock);
}
/***************************************************************************/
/* Level */
/***************************************************************************/
static int SelectRegion(struct Item *start,struct Item **begin_ptr,struct Item **end_ptr,struct Attributes a,struct Promise *pp)
/*
This should provide pointers to the first and last line of text that include the
delimiters, since we need to include those in case they are being deleted, etc.
It returns true if a match was identified, else false.
If no such region matches, begin_ptr and end_ptr should point to CF_UNDEFINED_ITEM
*/
{ struct Item *ip,*beg = CF_UNDEFINED_ITEM,*end = CF_UNDEFINED_ITEM;
for (ip = start; ip != NULL; ip = ip->next)
{
if (a.region.select_start)
{
if (beg == CF_UNDEFINED_ITEM && FullTextMatch(a.region.select_start,ip->name))
{
if (!a.region.include_start)
{
if (ip->next == NULL)
{
cfPS(cf_verbose,CF_INTERPT,"",pp,a," !! The promised start pattern (%s) found an empty region at the end of file %s",a.region.select_start,pp->this_server);
return false;
}
}
beg = ip;
continue;
}
}
if (a.region.select_end && beg != CF_UNDEFINED_ITEM)
{
if (end == CF_UNDEFINED_ITEM && FullTextMatch(a.region.select_end,ip->name))
{
end = ip;
break;
}
}
if (beg != CF_UNDEFINED_ITEM && end != CF_UNDEFINED_ITEM)
{
break;
}
}
*begin_ptr = beg;
*end_ptr = end;
if (beg == CF_UNDEFINED_ITEM && a.region.select_start)
{
cfPS(cf_verbose,CF_INTERPT,"",pp,a," !! The promised start pattern (%s) was not found when selecting edit region in %s",a.region.select_start,pp->this_server);
return false;
}
/*if (end == CF_UNDEFINED_ITEM)
{
end = NULL;
return false;
}
*/
return true;
}
/***************************************************************************/
static int InsertMissingLinesToRegion(struct Item **start,struct Item *begin_ptr,struct Item *end_ptr,struct Attributes a,struct Promise *pp)
{ struct Item *ip, *prev = CF_UNDEFINED_ITEM;
/* find prev for region */
if (IsItemInRegion(pp->promiser,begin_ptr,end_ptr,a,pp))
{
cfPS(cf_verbose,CF_NOP,"",pp,a," -> Promised line \"%s\" exists within selected region of %s (promise kept)",pp->promiser,pp->this_server);
return false;
}
if (*start == NULL)
{
return InsertMissingLinesAtLocation(start,begin_ptr,end_ptr,*start,prev,a,pp);
}
if (a.location.before_after == cfe_before)
{
for (ip = *start; ip != NULL; ip=ip->next)
{
if (ip == begin_ptr)
{
return InsertMissingLinesAtLocation(start,begin_ptr,end_ptr,ip,prev,a,pp);
}
prev = ip;
}
}
if (a.location.before_after == cfe_after)
{
for (ip = *start; ip != NULL; ip=ip->next)
{
if (ip->next != NULL && ip->next == end_ptr)
{
return InsertMissingLinesAtLocation(start,begin_ptr,end_ptr,ip,prev,a,pp);
}
if (ip->next == NULL)
{
return InsertMissingLinesAtLocation(start,begin_ptr,end_ptr,ip,prev,a,pp);
}
prev = ip;
}
}
return false;
}
/***************************************************************************/
static int InsertMissingLinesAtLocation(struct Item **start,struct Item *begin_ptr,struct Item *end_ptr,struct Item *location,struct Item *prev,struct Attributes a,struct Promise *pp)
{ FILE *fin;
char buf[CF_BUFSIZE],exp[CF_EXPANDSIZE];
struct Item *loc = NULL;
int retval = false;
if (a.sourcetype && strcmp(a.sourcetype,"file") == 0)
{
if ((fin = fopen(pp->promiser,"r")) == NULL)
{
cfPS(cf_error,CF_INTERPT,"fopen",pp,a,"Could not read file %s",pp->promiser);
return false;
}
loc = location;
while (!feof(fin))
{
buf[0] = '\0';
fgets(buf,CF_BUFSIZE,fin);
StripTrailingNewline(buf);
if (feof(fin) && strlen(buf) == 0)
{
break;
}
if (a.expandvars)
{
ExpandScalar(buf,exp);
}
else
{
strcpy(exp,buf);
}
if (!SelectLine(exp,a,pp))
{
continue;
}
if (IsItemInRegion(exp,begin_ptr,end_ptr,a,pp))
{
cfPS(cf_verbose,CF_NOP,"",pp,a," -> Promised file line \"%s\" exists within file %s (promise kept)",exp,pp->this_server);
continue;
}
retval |= InsertCompoundLineAtLocation(exp,start,loc,prev,a,pp);
if (prev && prev != CF_UNDEFINED_ITEM)
{
prev = prev->next;
}
if (loc)
{
loc = loc->next;
}
}
fclose(fin);
return retval;
}
else
{
int multiline = a.sourcetype && strcmp(a.sourcetype,"preserve_block") == 0;
int need_insert = false;
if (strchr(pp->promiser,'\n') != NULL) /* Multi-line string */
{
char *sp;
loc = location;
for (sp = pp->promiser; sp <= pp->promiser+strlen(pp->promiser); sp++)
{
memset(buf,0,CF_BUFSIZE);
sscanf(sp,"%[^\n]",buf);
sp += strlen(buf);
if (!SelectLine(buf,a,pp))
{
continue;
}
if (IsItemInRegion(buf,begin_ptr,end_ptr,a,pp))
{
cfPS(cf_verbose,CF_NOP,"",pp,a," -> Promised file line \"%s\" exists within file %s (promise kept)",buf,pp->this_server);
continue;
}
if (!multiline)
{
retval |= InsertCompoundLineAtLocation(buf,start,loc,prev,a,pp);
if (prev && prev != CF_UNDEFINED_ITEM)
{
prev = prev->next;
}
if (loc)
{
loc = loc->next;
}
}
else
{
need_insert = true;
}
}
if (need_insert)
{
for (sp = pp->promiser; sp <= pp->promiser+strlen(pp->promiser); sp++)
{
memset(buf,0,CF_BUFSIZE);
sscanf(sp,"%[^\n]",buf);
sp += strlen(buf);
retval |= InsertCompoundLineAtLocation(buf,start,loc,prev,a,pp);
if (prev && prev != CF_UNDEFINED_ITEM)
{
prev = prev->next;
}
if (loc)
{
loc = loc->next;
}
}
}
return retval;
}
else
{
return InsertCompoundLineAtLocation(pp->promiser,start,location,prev,a,pp);
}
}
}
/***************************************************************************/
static int DeletePromisedLinesMatching(struct Item **start,struct Item *begin,struct Item *end,struct Attributes a,struct Promise *pp)
{ struct Item *ip,*np = NULL,*lp,*initiator = begin,*terminator = NULL;
int i,in_region = false, retval = false, matches, noedits = true;
char *sp,buf[CF_BUFSIZE];
if (start == NULL)
{
return false;
}
// Get a pointer from before the region so we can patch the hole later
if (begin == CF_UNDEFINED_ITEM)
{
initiator = *start;
}
else
{
if (a.region.include_start)
{
initiator = begin;
}
else
{
initiator = begin->next;
}
}
if (end == CF_UNDEFINED_ITEM)
{
terminator = NULL;
}
else
{
if (a.region.include_end)
{
terminator = end->next;
}
else
{
terminator = end;
}
}
// Now do the deletion
for (ip = initiator; ip != terminator && ip != NULL; ip = np)
{
if (a.not_matching)
{
matches = !MatchRegion(pp->promiser,*start,ip,terminator);
}
else
{
matches = MatchRegion(pp->promiser,*start,ip,terminator);
}
if (matches)
{
CfOut(cf_verbose,""," -> Multi-line region (size %d) matched text in the file",matches);
}
else
{
CfOut(cf_verbose,""," -> Multi-line region didn't match text in the file");
}
if (!SelectLine(ip->name,a,pp)) // Start search from location
{
np = ip->next;
continue;
}
if (matches)
{
CfOut(cf_verbose,""," -> Delete chunk of %d lines\n",matches,ip->name);
if (a.transaction.action == cfa_warn)
{
cfPS(cf_error,CF_WARN,"",pp,a," -> Need to delete line \"%s\" from %s - but only a warning was promised",ip->name,pp->this_server);
np = ip->next;
noedits = false;
}
else
{
for (i = 1; i <= matches; i++)
{
cfPS(cf_verbose,CF_CHG,"",pp,a," -> Deleting the promised line %d \"%s\" from %s",i,ip->name,pp->this_server);
retval = true;
noedits = false;
if (ip->name != NULL)
{
free(ip->name);
}
np = ip->next;
free((char *)ip);
lp = ip;
if (ip == *start)
{
if (initiator == *start)
{
initiator = np;
}
*start = np;
}
else
{
if (ip == initiator)
{
initiator = *start;
}
for (lp = initiator; lp->next != ip; lp=lp->next)
{
}
lp->next = np;
}
(pp->edcontext->num_edits)++;
ip = np;
}
}
}
else
{
np = ip->next;
}
}
if (noedits)
{
cfPS(cf_verbose,CF_NOP,"",pp,a," -> No need to delete lines from %s, ok",pp->this_server);
}
return retval;
}
/********************************************************************/
static int ReplacePatterns(struct Item *file_start,struct Item *file_end,struct Attributes a,struct Promise *pp)
{ char replace[CF_EXPANDSIZE],line_buff[CF_EXPANDSIZE];
char before[CF_BUFSIZE],after[CF_BUFSIZE];
int match_len,start_off,end_off,once_only = false,retval = false;
struct Item *ip;
int notfound = true, cutoff = 1, replaced=false;
if (a.replace.occurrences && (strcmp(a.replace.occurrences,"first") == 0))
{
CfOut(cf_inform,"","WARNING! Setting replace-occurrences policy to \"first\" is not convergent");
once_only = true;
}
for (ip = file_start; ip != NULL && ip != file_end; ip=ip->next)
{
if (ip->name == NULL)
{
continue;
}
cutoff = 1;
strncpy(line_buff,ip->name,CF_BUFSIZE);
replaced = false;
match_len = 0;
while (BlockTextMatch(pp->promiser,line_buff,&start_off,&end_off))
{
if (match_len == strlen(line_buff))
{
CfOut(cf_verbose,""," -> Improper convergent expression matches defacto convergence, so accepting");
break;
}
if (cutoff++ > CF_MAX_REPLACE)
{
CfOut(cf_verbose,""," !! Too many replacements on this line");
break;
}
match_len = end_off - start_off;
ExpandScalar(a.replace.replace_value,replace);
CfOut(cf_verbose,""," -> Verifying replacement of \"%s\" with \"%s\" (%d)\n",pp->promiser,replace,cutoff);
before[0] = after[0] = '\0';
// Model the partial substitution in line_buff to check convergence
strncat(before,line_buff,start_off);
strncat(after,line_buff+end_off,sizeof(after) - 1);
snprintf(line_buff,CF_EXPANDSIZE-1,"%s%s",before,replace);
notfound = false;
replaced = true;
// Model the full substitution in line_buff
snprintf(line_buff,CF_EXPANDSIZE-1,"%s%s%s",before,replace,after);
if (once_only)
{
CfOut(cf_verbose,""," -> Replace first occurrence only (warning, this is not a convergent policy)");
break;
}
}
if (NotAnchored(pp->promiser) && BlockTextMatch(pp->promiser,line_buff,&start_off,&end_off))
{
cfPS(cf_error,CF_INTERPT,"",pp,a," -> Promised replacement \"%s\" on line \"%s\" for pattern \"%s\" is not convergent while editing %s",line_buff,ip->name,pp->promiser,pp->this_server);
CfOut(cf_error,"","Because the regular expression \"%s\" still matches the replacement string \"%s\"",pp->promiser,line_buff);
PromiseRef(cf_error,pp);
break;
}
if (a.transaction.action == cfa_warn)
{
cfPS(cf_verbose,CF_WARN,"",pp,a," -> Need to replace line \"%s\" in %s - but only a warning was promised",pp->promiser,pp->this_server);
continue;
}
else if (replaced)
{
free(ip->name);
ip->name = strdup(line_buff);
cfPS(cf_verbose,CF_CHG,"",pp,a," -> Replaced pattern \"%s\" in %s",pp->promiser,pp->this_server);
(pp->edcontext->num_edits)++;
retval = true;
CfOut(cf_verbose,""," -> << (%d)\"%s\"\n",cutoff,ip->name);
CfOut(cf_verbose,""," -> >> (%d)\"%s\"\n",cutoff,line_buff);
if (once_only)
{
CfOut(cf_verbose,""," -> Replace first occurrence only (warning, this is not a convergent policy)");
break;
}
if (BlockTextMatch(pp->promiser,ip->name,&start_off,&end_off))
{
cfPS(cf_inform,CF_INTERPT,"",pp,a," -> Promised replacement \"%s\" for pattern \"%s\" is not properly convergent while editing %s",ip->name,pp->promiser,pp->this_server);
CfOut(cf_inform,"","Because the regular expression \"%s\" still matches the end-state replacement string \"%s\"",pp->promiser,line_buff);
PromiseRef(cf_inform,pp);
}
}
}
if (notfound)
{
cfPS(cf_verbose,CF_NOP,"",pp,a," -> No pattern \"%s\" in %s",pp->promiser,pp->this_server);
}
return retval;
}
/********************************************************************/
static int EditColumns(struct Item *file_start,struct Item *file_end,struct Attributes a,struct Promise *pp)
{ char separator[CF_MAXVARSIZE];
int s,e,retval = false;
struct Item *ip;
struct Rlist *columns = NULL;
if (!ValidateRegEx(pp->promiser))
{
return false;
}
for (ip = file_start; ip != file_end; ip=ip->next)
{
if (ip->name == NULL)
{
continue;
}
if (!FullTextMatch(pp->promiser,ip->name))
{
continue;
}
else
{
CfOut(cf_verbose,""," - Matched line (%s)\n",ip->name);
}
if (!BlockTextMatch(a.column.column_separator,ip->name,&s,&e))
{
cfPS(cf_verbose,CF_INTERPT,"",pp,a," ! Field edit - no fields found by promised pattern %s in %s",a.column.column_separator,pp->this_server);
return false;
}
if (e-s > CF_MAXVARSIZE / 2)
{
CfOut(cf_error,""," !! Line split criterion matches a huge part of the line -- seems to be in error");
return false;
}
strncpy(separator,ip->name+s,e-s);
separator[e-s]='\0';
columns = SplitRegexAsRList(ip->name,a.column.column_separator,CF_INFINITY,a.column.blanks_ok);
retval = EditLineByColumn(&columns,a,pp);
if (retval)
{
free(ip->name);
ip->name = Rlist2String(columns,separator);
}
DeleteRlist(columns);
}
return retval;
}
/***************************************************************************/
static int SanityCheckInsertions(struct Attributes a)
{ long not = 0;
long with = 0;
long ok = true;
struct Rlist *rp;
enum insert_match opt;
int exact = false, ignore_something = false;
int multiline = a.sourcetype && strcmp(a.sourcetype,"preserve_block") == 0;
if (a.line_select.startwith_from_list)
{
with++;
}
if (a.line_select.not_startwith_from_list)
{
not++;
}
if (a.line_select.match_from_list)
{
with++;
}
if (a.line_select.not_match_from_list)
{
not++;
}
if (a.line_select.contains_from_list)
{
with++;
}
if (a.line_select.not_contains_from_list)
{
not++;
}
if (not > 1)
{
CfOut(cf_error,""," !! Line insertion selection promise is meaningless - the alternatives are mutually exclusive (only one is allowed)");
ok = false;
}
if (with && not)
{
CfOut(cf_error,""," !! Line insertion selection promise is meaningless - cannot mix positive and negative constraints");
ok = false;
}
for (rp = a.insert_match; rp != NULL; rp=rp->next)
{
opt = String2InsertMatch(rp->item);
switch (opt)
{
case cf_exact_match:
exact = true;
break;
default:
ignore_something = true;
if (multiline)
{
CfOut(cf_error,""," !! Line insertion should not use whitespace policy with preserve_block");
ok = false;
}
break;
}
}
if (exact && ignore_something)
{
CfOut(cf_error,""," !! Line insertion selection promise is meaningless - cannot mix exact_match with other ignore whitespace options");
ok = false;
}
return ok;
}
/***************************************************************************/
static int SanityCheckDeletions(struct Attributes a,struct Promise *pp)
{
if (strchr(pp->promiser,'\n') != NULL) /* Multi-line string */
{
if (a.not_matching)
{
CfOut(cf_error,""," !! Makes no sense to promise multi-line delete with not_matching. Cannot be satisfied for all lines as a block.");
}
}
return true;
}
/***************************************************************************/
/* Level */
/***************************************************************************/
static int InsertCompoundLineAtLocation(char *newline,struct Item **start,struct Item *location,struct Item *prev,struct Attributes a,struct Promise *pp)
{
int result = false;
char buf[CF_EXPANDSIZE];
if (strchr(newline,'\n') != NULL) /* Multi-line string */
{
char *sp;
for (sp = newline; sp <= newline+strlen(newline); sp++)
{
memset(buf,0,CF_BUFSIZE);
sscanf(sp,"%2048[^\n]",buf);
sp += strlen(buf);
if (!SelectLine(buf,a,pp))
{
continue;
}
result |= InsertMissingLineAtLocation(buf,start,location,prev,a,pp);
}
}
else
{
result |= InsertMissingLineAtLocation(newline,start,location,prev,a,pp);
}
return result;
}
/***************************************************************************/
static int InsertMissingLineAtLocation(char *newline,struct Item **start,struct Item *location,struct Item *prev,struct Attributes a,struct Promise *pp)
/* Check line neighbourhood in whole file to avoid edge effects */
{
if (prev == CF_UNDEFINED_ITEM) /* Insert at first line */
{
if (a.location.before_after == cfe_before)
{
if (*start == NULL)
{
if (a.transaction.action == cfa_warn)
{
cfPS(cf_error,CF_WARN,"",pp,a," -> Need to insert the promised line \"%s\" in %s - but only a warning was promised",newline,pp->this_server);
return true;
}
else
{
PrependItemList(start,newline);
(pp->edcontext->num_edits)++;
cfPS(cf_verbose,CF_CHG,"",pp,a," -> Inserting the promised line \"%s\" into %s",newline,pp->this_server);
return true;
}
}
if (strcmp((*start)->name,newline) != 0)
{
if (a.transaction.action == cfa_warn)
{
cfPS(cf_error,CF_WARN,"",pp,a," -> Need to prepend the promised line \"%s\" to %s - but only a warning was promised",newline,pp->this_server);
return true;
}
else
{
PrependItemList(start,newline);
(pp->edcontext->num_edits)++;
cfPS(cf_verbose,CF_CHG,"",pp,a," -> Prepending the promised line \"%s\" to %s",newline,pp->this_server);
return true;
}
}
else
{
cfPS(cf_verbose,CF_NOP,"",pp,a," -> Promised line \"%s\" exists at start of file %s (promise kept)",newline,pp->this_server);
return false;
}
}
}
if (a.location.before_after == cfe_before)
{
if (NeighbourItemMatches(*start,location,newline,cfe_before,a,pp))
{
cfPS(cf_verbose,CF_NOP,"",pp,a," -> Promised line \"%s\" exists before locator in (promise kept)",newline);
return false;
}
else
{
if (a.transaction.action == cfa_warn)
{
cfPS(cf_error,CF_WARN,"",pp,a," -> Need to insert line \"%s\" into %s but only a warning was promised",newline,pp->this_server);
return true;
}
else
{
InsertAfter(start,prev,newline);
(pp->edcontext->num_edits)++;
cfPS(cf_verbose,CF_CHG,"",pp,a," -> Inserting the promised line \"%s\" into %s before locator",newline,pp->this_server);
return true;
}
}
}
else
{
if (NeighbourItemMatches(*start,location,newline,cfe_after,a,pp))
{
cfPS(cf_verbose,CF_NOP,"",pp,a," -> Promised line \"%s\" exists after locator (promise kept)",newline);
return false;
}
else
{
if (a.transaction.action == cfa_warn)
{
cfPS(cf_error,CF_WARN,"",pp,a," -> Need to insert line \"%s\" in %s but only a warning was promised",newline,pp->this_server);
return true;
}
else
{
InsertAfter(start,location,newline);
cfPS(cf_verbose,CF_CHG,"",pp,a," -> Inserting the promised line \"%s\" into %s after locator",newline,pp->this_server);
(pp->edcontext->num_edits)++;
return true;
}
}
}
}
/***************************************************************************/
static int EditLineByColumn(struct Rlist **columns,struct Attributes a,struct Promise *pp)
{ struct Rlist *rp,*this_column = NULL;
char sep[CF_MAXVARSIZE];
int i,count = 0,retval = false;
/* Now break up the line into a list - not we never remove an item/column */
for (rp = *columns; rp != NULL; rp=rp->next)
{
count++;
if (count == a.column.select_column)
{
CfOut(cf_verbose,""," -> Stopped at field %d\n",count);
break;
}
}
if (a.column.select_column > count)
{
if (!a.column.extend_columns)
{
cfPS(cf_error,CF_INTERPT,"",pp,a," !! The file %s has only %d fields, but there is a promise for field %d",pp->this_server,count,a.column.select_column);
return false;
}
else
{
for (i = 0; i < (a.column.select_column - count); i++)
{
AppendRScalar(columns,strdup(""),CF_SCALAR);
}
count = 0;
for (rp = *columns; rp != NULL; rp=rp->next)
{
count++;
if (count == a.column.select_column)
{
CfOut(cf_verbose,""," -> Stopped at column/field %d\n",count);
break;
}
}
}
}
if (a.column.value_separator != '\0')
{
/* internal separator, single char so split again */
if (strcmp(rp->item,a.column.column_value) == 0)
{
retval = false;
}
else
{
this_column = SplitStringAsRList(rp->item,a.column.value_separator);
retval = EditColumn(&this_column,a,pp);
}
if (retval)
{
if (a.transaction.action == cfa_warn)
{
cfPS(cf_error,CF_WARN,"",pp,a," -> Need to edit field in %s but only warning promised",pp->this_server);
retval = false;
}
else
{
cfPS(cf_inform,CF_CHG,"",pp,a," -> Edited field inside file object %s",pp->this_server);
(pp->edcontext->num_edits)++;
free(rp->item);
sep[0] = a.column.value_separator;
sep[1] = '\0';
rp->item = Rlist2String(this_column,sep);
}
}
else
{
cfPS(cf_verbose,CF_NOP,"",pp,a," -> No need to edit field in %s",pp->this_server);
}
DeleteRlist(this_column);
return retval;
}
else
{
/* No separator, so we set the whole field to the value */
if (a.column.column_operation && strcmp(a.column.column_operation,"delete") == 0)
{
if (a.transaction.action == cfa_warn)
{
cfPS(cf_error,CF_WARN,"",pp,a," -> Need to delete field field value %s in %s but only a warning was promised",rp->item,pp->this_server);
return false;
}
else
{
cfPS(cf_inform,CF_CHG,"",pp,a," -> Deleting column field value %s in %s",rp->item,pp->this_server);
(pp->edcontext->num_edits)++;
free(rp->item);
rp->item = strdup("");
return true;
}
}
else
{
if (a.transaction.action == cfa_warn)
{
cfPS(cf_error,CF_WARN,"",pp,a," -> Need to set column field value %s to %s in %s but only a warning was promised",rp->item,a.column.column_value,pp->this_server);
return false;
}
else
{
cfPS(cf_inform,CF_CHG,"",pp,a," -> Setting whole column field value %s to %s in %s",rp->item,a.column.column_value,pp->this_server);
free(rp->item);
rp->item = strdup(a.column.column_value);
(pp->edcontext->num_edits)++;
return true;
}
}
}
cfPS(cf_verbose,CF_NOP,"",pp,a," -> No need to edit column field value %s in %s",a.column.column_value,pp->this_server);
return false;
}
/***************************************************************************/
static int SelectLine(char *line,struct Attributes a,struct Promise *pp)
{ struct Rlist *rp,*c;
int s,e;
char *selector;
if ((c = a.line_select.startwith_from_list))
{
for (rp = c; rp != NULL; rp=rp->next)
{
selector = (char *)(rp->item);
if (strncmp(selector,line,strlen(selector)) == 0)
{
return true;
}
}
return false;
}
if ((c = a.line_select.not_startwith_from_list))
{
for (rp = c; rp != NULL; rp=rp->next)
{
selector = (char *)(rp->item);
if (strncmp(selector,line,strlen(selector)) == 0)
{
return false;
}
}
return true;
}
if ((c = a.line_select.match_from_list))
{
for (rp = c; rp != NULL; rp=rp->next)
{
selector = (char *)(rp->item);
if (FullTextMatch(selector,line))
{
return true;
}
}
return false;
}
if ((c = a.line_select.not_match_from_list))
{
for (rp = c; rp != NULL; rp=rp->next)
{
selector = (char *)(rp->item);
if (FullTextMatch(selector,line))
{
return false;
}
}
return true;
}
if ((c = a.line_select.contains_from_list))
{
for (rp = c; rp != NULL; rp=rp->next)
{
selector = (char *)(rp->item);
if (BlockTextMatch(selector,line,&s,&e))
{
return true;
}
}
return false;
}
if ((c = a.line_select.not_contains_from_list))
{
for (rp = c; rp != NULL; rp=rp->next)
{
selector = (char *)(rp->item);
if (BlockTextMatch(selector,line,&s,&e))
{
return false;
}
}
return true;
}
return true;
}
/***************************************************************************/
/* Level */
/***************************************************************************/
static int EditColumn(struct Rlist **columns,struct Attributes a,struct Promise *pp)
{ struct Rlist *rp, *found;
int retval = false;
if (a.column.column_operation && strcmp(a.column.column_operation,"delete") == 0)
{
if ((found = KeyInRlist(*columns,a.column.column_value)))
{
CfOut(cf_inform,""," -> Deleting column field sub-value %s in %s",a.column.column_value,pp->this_server);
DeleteRlistEntry(columns,found);
return true;
}
else
{
return false;
}
}
if (a.column.column_operation && strcmp(a.column.column_operation,"set") == 0)
{
if (RlistLen(*columns) == 1)
{
if (strcmp((*columns)->item,a.column.column_value) == 0)
{
CfOut(cf_verbose,""," -> Field sub-value set as promised\n");
return false;
}
}
CfOut(cf_inform,""," -> Setting field sub-value %s in %s",a.column.column_value,pp->this_server);
DeleteRlist(*columns);
*columns = NULL;
IdempPrependRScalar(columns,a.column.column_value,CF_SCALAR);
return true;
}
if (a.column.column_operation && strcmp(a.column.column_operation,"prepend") == 0)
{
if (IdempPrependRScalar(columns,a.column.column_value,CF_SCALAR))
{
CfOut(cf_inform,""," -> Prepending field sub-value %s in %s",a.column.column_value,pp->this_server);
return true;
}
else
{
return false;
}
}
if (a.column.column_operation && strcmp(a.column.column_operation,"alphanum") == 0)
{
if (IdempPrependRScalar(columns,a.column.column_value,CF_SCALAR))
{
retval = true;
}
rp = AlphaSortRListNames(*columns);
*columns = rp;
return retval;
}
/* default operation is append */
if (IdempAppendRScalar(columns,a.column.column_value,CF_SCALAR))
{
return true;
}
else
{
return false;
}
return false;
}
/********************************************************************/
static int NotAnchored(char *s)
{
if (*s != '^')
{
return true;
}
if (*(s+strlen(s)-1) != '$')
{
return true;
}
return false;
}
cfengine-3.2.4/src/crypto.c 0000644 0001750 0001750 00000037746 11715232734 012520 0000000 0000000 /*
Copyright (C) Cfengine AS
This file is part of Cfengine 3 - written and maintained by Cfengine 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 Commerical Open Source License
(COSL) may apply to this file if you as a licensee so wish it. See
included file COSL.txt.
*/
/*****************************************************************************/
/* */
/* File: crypto.c */
/* */
/*****************************************************************************/
#include "cf3.defs.h"
#include "cf3.extern.h"
static void MD5Random (unsigned char digest[EVP_MAX_MD_SIZE+1]);
static char *KeyPrint(RSA *key);
/**********************************************************************/
void RandomSeed()
{ static unsigned char digest[EVP_MAX_MD_SIZE+1];
struct stat statbuf;
char vbuff[CF_BUFSIZE];
/* Use the system database as the entropy source for random numbers */
Debug("RandomSeed() work directory is %s\n",CFWORKDIR);
snprintf(vbuff,CF_BUFSIZE,"%s%crandseed",CFWORKDIR,FILE_SEPARATOR);
if (cfstat(vbuff,&statbuf) == -1)
{
snprintf(AVDB,CF_MAXVARSIZE-1,"%s%cstate%c%s",CFWORKDIR,FILE_SEPARATOR,FILE_SEPARATOR,CF_AVDB_FILE);
}
else
{
strncpy(AVDB,vbuff,CF_MAXVARSIZE-1);
}
CfOut(cf_verbose,"","Looking for a source of entropy in %s\n",AVDB);
if (!RAND_load_file(AVDB,-1))
{
CfOut(cf_verbose,"","Could not read sufficient randomness from %s\n",AVDB);
}
while (!RAND_status())
{
MD5Random(digest);
RAND_seed((void *)digest,16);
}
}
/*****************************************************************************/
void KeepKeyPromises()
{ unsigned long err;
RSA *pair;
FILE *fp;
struct stat statbuf;
int fd;
static char *passphrase = "Cfengine passphrase";
const EVP_CIPHER *cipher;
char vbuff[CF_BUFSIZE];
NewScope("common");
cipher = EVP_des_ede3_cbc();
if (cfstat(CFPUBKEYFILE,&statbuf) != -1)
{
CfOut(cf_cmdout,"","A key file already exists at %s\n",CFPUBKEYFILE);
return;
}
if (cfstat(CFPRIVKEYFILE,&statbuf) != -1)
{
CfOut(cf_cmdout,"","A key file already exists at %s\n",CFPRIVKEYFILE);
return;
}
printf("Making a key pair for cfengine, please wait, this could take a minute...\n");
pair = RSA_generate_key(2048,35,NULL,NULL);
if (pair == NULL)
{
err = ERR_get_error();
CfOut(cf_error,"","Unable to generate key: %s\n",ERR_reason_error_string(err));
return;
}
if (DEBUG)
{
RSA_print_fp(stdout,pair,0);
}
fd = open(CFPRIVKEYFILE,O_WRONLY | O_CREAT | O_TRUNC, 0600);
if (fd < 0)
{
CfOut(cf_error,"open","Open %s failed: %s.",CFPRIVKEYFILE,strerror(errno));
return;
}
if ((fp = fdopen(fd, "w")) == NULL )
{
CfOut(cf_error,"fdopen","Couldn't open private key %s.",CFPRIVKEYFILE);
close(fd);
return;
}
CfOut(cf_verbose,"","Writing private key to %s\n",CFPRIVKEYFILE);
if (!PEM_write_RSAPrivateKey(fp,pair,cipher,passphrase,strlen(passphrase),NULL,NULL))
{
err = ERR_get_error();
CfOut(cf_error,"","Couldn't write private key: %s\n",ERR_reason_error_string(err));
return;
}
fclose(fp);
fd = open(CFPUBKEYFILE,O_WRONLY | O_CREAT | O_TRUNC, 0600);
if (fd < 0)
{
CfOut(cf_error,"open","Unable to open public key %s.",CFPUBKEYFILE);
return;
}
if ((fp = fdopen(fd, "w")) == NULL )
{
CfOut(cf_error,"fdopen","Open %s failed.",CFPUBKEYFILE);
close(fd);
return;
}
CfOut(cf_verbose,"","Writing public key to %s\n",CFPUBKEYFILE);
if (!PEM_write_RSAPublicKey(fp,pair))
{
err = ERR_get_error();
CfOut(cf_error,"","Unable to write public key: %s\n",ERR_reason_error_string(err));
return;
}
fclose(fp);
snprintf(vbuff,CF_BUFSIZE,"%s/randseed",CFWORKDIR);
RAND_write_file(vbuff);
cf_chmod(vbuff,0644);
}
/*********************************************************************/
void LoadSecretKeys()
{ FILE *fp;
static char *passphrase = "Cfengine passphrase",name[CF_BUFSIZE],source[CF_BUFSIZE];
char guard[CF_MAXVARSIZE];
unsigned char digest[EVP_MAX_MD_SIZE+1];
unsigned long err;
struct stat sb;
if ((fp = fopen(CFPRIVKEYFILE,"r")) == NULL)
{
CfOut(cf_inform,"fopen","Couldn't find a private key (%s) - use cf-key to get one",CFPRIVKEYFILE);
return;
}
if ((PRIVKEY = PEM_read_RSAPrivateKey(fp,(RSA **)NULL,NULL,passphrase)) == NULL)
{
err = ERR_get_error();
CfOut(cf_error,"PEM_read","Error reading Private Key = %s\n",ERR_reason_error_string(err));
PRIVKEY = NULL;
fclose(fp);
return;
}
fclose(fp);
CfOut(cf_verbose,""," -> Loaded private key %s\n",CFPRIVKEYFILE);
if ((fp = fopen(CFPUBKEYFILE,"r")) == NULL)
{
CfOut(cf_error,"fopen","Couldn't find a public key (%s) - use cf-key to get one",CFPUBKEYFILE);
return;
}
if ((PUBKEY = PEM_read_RSAPublicKey(fp,NULL,NULL,passphrase)) == NULL)
{
err = ERR_get_error();
CfOut(cf_error,"PEM_read","Error reading Private Key = %s\n",ERR_reason_error_string(err));
PUBKEY = NULL;
fclose(fp);
return;
}
CfOut(cf_verbose,""," -> Loaded public key %s\n",CFPUBKEYFILE);
fclose(fp);
if (BN_num_bits(PUBKEY->e) < 2 || !BN_is_odd(PUBKEY->e))
{
FatalError("RSA Exponent too small or not odd");
}
if (EMPTY(POLICY_SERVER))
{
snprintf(name,CF_MAXVARSIZE-1,"%s%cpolicy_server.dat",CFWORKDIR,FILE_SEPARATOR);
if ((fp = fopen(name,"r")) != NULL)
{
fscanf(fp,"%4095s",POLICY_SERVER);
fclose(fp);
}
}
/* Check that we have our own SHA key form of the key in the IP on the hub */
HashPubKey(PUBKEY,digest,CF_DEFAULT_DIGEST);
snprintf(name,CF_MAXVARSIZE,"%s/ppkeys/%s-%s.pub",CFWORKDIR,"root",HashPrint(CF_DEFAULT_DIGEST,digest));
MapName(name);
snprintf(source,CF_MAXVARSIZE,"%s/ppkeys/localhost.pub",CFWORKDIR);
MapName(source);
// During bootstrap we need the pre-registered IP/hash pair on the hub
snprintf(guard,sizeof(guard),"%s/state/am_policy_hub",CFWORKDIR);
MapName(guard);
// need to use cf_stat
if (stat(name,&sb) == -1 && stat(guard,&sb) != -1)
// copy localhost.pub to root-HASH.pub on policy server
{
LastSaw("root",POLICY_SERVER,digest,cf_connect);
if (!LinkOrCopy(source,name,false))
{
CfOut(cf_error,""," -> Unable to clone server's key file as %s\n",name);
}
}
}
/*********************************************************************/
RSA *HavePublicKeyByIP(char *username,char *ipaddress)
{ char hash[CF_MAXVARSIZE];
IPString2KeyDigest(ipaddress,hash);
return HavePublicKey(username,ipaddress,hash);
}
/*********************************************************************/
RSA *HavePublicKey(char *username,char *ipaddress,char *digest)
{ char keyname[CF_MAXVARSIZE],newname[CF_BUFSIZE],oldname[CF_BUFSIZE];
struct stat statbuf;
static char *passphrase = "public";
unsigned long err;
FILE *fp;
RSA *newkey = NULL;
snprintf(keyname,CF_MAXVARSIZE,"%s-%s",username,digest);
Debug("HavePublickey(%s)\n",keyname);
snprintf(newname,CF_BUFSIZE,"%s/ppkeys/%s.pub",CFWORKDIR,keyname);
MapName(newname);
if (cfstat(newname,&statbuf) == -1)
{
CfOut(cf_verbose,""," -> Did not find new key format %s",newname);
snprintf(oldname,CF_BUFSIZE,"%s/ppkeys/%s-%s.pub",CFWORKDIR,username,ipaddress);
MapName(oldname);
CfOut(cf_verbose,""," -> Trying old style %s",oldname);
if (cfstat(oldname,&statbuf) == -1)
{
Debug("Did not have old-style key %s\n",oldname);
return NULL;
}
if (strlen(digest) > 0)
{
CfOut(cf_inform,""," -> Renaming old key from %s to %s",oldname,newname);
if (rename(oldname,newname) != 0)
{
CfOut(cf_error, "rename", "!! Could not rename from old key format (%s) to new (%s)",oldname,newname);
}
}
else // we don't know the digest (e.g. because we are a client and
// have no lastseen-map and/or root-SHA...pub of the server's key
// yet) Just using old file format (root-IP.pub) without renaming for now.
{
CfOut(cf_verbose, "", " -> Could not map key file to new format - we have no digest yet (using %s)", oldname);
snprintf(newname,sizeof(newname),"%s",oldname);
}
}
if ((fp = fopen(newname,"r")) == NULL)
{
CfOut(cf_error,"fopen","Couldn't find a public key (%s)",newname);
return NULL;
}
if ((newkey = PEM_read_RSAPublicKey(fp,NULL,NULL,passphrase)) == NULL)
{
err = ERR_get_error();
CfOut(cf_error,"PEM_read","Error reading Private Key = %s\n",ERR_reason_error_string(err));
fclose(fp);
return NULL;
}
fclose(fp);
if (BN_num_bits(newkey->e) < 2 || !BN_is_odd(newkey->e))
{
FatalError("RSA Exponent too small or not odd");
}
return newkey;
}
/*********************************************************************/
void SavePublicKey(char *user,char *ipaddress,char *digest,RSA *key)
{ char keyname[CF_MAXVARSIZE],filename[CF_BUFSIZE];
struct stat statbuf;
FILE *fp;
int err;
Debug("SavePublicKey %s\n",ipaddress);
snprintf(keyname,CF_MAXVARSIZE,"%s-%s",user,digest);
snprintf(filename,CF_BUFSIZE,"%s/ppkeys/%s.pub",CFWORKDIR,keyname);
MapName(filename);
if (cfstat(filename,&statbuf) != -1)
{
return;
}
CfOut(cf_verbose,"","Saving public key %s\n",filename);
if ((fp = fopen(filename, "w")) == NULL )
{
CfOut(cf_error,"fopen","Unable to write a public key %s",filename);
return;
}
ThreadLock(cft_system);
if (!PEM_write_RSAPublicKey(fp,key))
{
err = ERR_get_error();
CfOut(cf_error,"PEM_write","Error saving public key %s = %s\n",filename,ERR_reason_error_string(err));
}
ThreadUnlock(cft_system);
fclose(fp);
}
/*********************************************************************/
/*
* Returns:
* amount of keys removed
* -1 if there was an error
*/
static int RemovePublicKey(const char *id)
{
char keysdir[CF_BUFSIZE];
snprintf(keysdir, CF_BUFSIZE, "%s/ppkeys", CFWORKDIR);
MapName(keysdir);
CFDIR *dirh;
const struct dirent *dirp;
char suffix[CF_BUFSIZE];
int removed = 0;
if ((dirh = OpenDirLocal(keysdir)) == NULL)
{
if (errno == ENOENT)
{
return 0;
}
else
{
CfOut(cf_error, "opendir", "Unable to open keys directory");
return -1;
}
}
snprintf(suffix, CF_BUFSIZE, "-%s.pub", id);
while ((dirp = ReadDir(dirh)) != NULL)
{
char *c = strstr(dirp->d_name, suffix);
if (c && c[strlen(suffix)] == '\0') /* dirp->d_name ends with suffix */
{
char keyfilename[CF_BUFSIZE];
snprintf(keyfilename, CF_BUFSIZE, "%s/%s", keysdir, dirp->d_name);
MapName(keyfilename);
if (unlink(keyfilename) < 0)
{
if (errno != ENOENT)
{
CfOut(cf_error, "unlink", "Unable to remove key file %s", dirp->d_name);
CloseDir(dirh);
return -1;
}
}
else
{
removed++;
}
}
}
if (errno)
{
CfOut(cf_error, "ReadDir", "Unable to enumerate files in keys directory");
CloseDir(dirh);
return -1;
}
CloseDir(dirh);
return removed;
}
/*********************************************************************/
/*
* Returns number of keys removed, -1 in case of error
*/
int RemovePublicKeys(const char *hostname)
{
char ip[CF_BUFSIZE];
char digest[CF_BUFSIZE];
int removed_by_digest, removed_by_ip;
strcpy(ip, Hostname2IPString(hostname));
IPString2KeyDigest(ip, digest);
removed_by_digest = RemovePublicKey(digest);
removed_by_ip = RemovePublicKey(ip);
if (removed_by_digest >= 0 && removed_by_ip >= 0)
{
return removed_by_digest + removed_by_ip;
}
else
{
return -1;
}
}
/*********************************************************************/
static void MD5Random(unsigned char digest[EVP_MAX_MD_SIZE+1])
/* Make a decent random number by crunching some system states & garbage through
MD5. We can use this as a seed for pseudo random generator */
{ unsigned char buffer[CF_BUFSIZE];
char pscomm[CF_BUFSIZE];
char uninitbuffer[100];
int md_len;
const EVP_MD *md;
EVP_MD_CTX context;
FILE *pp;
CfOut(cf_verbose,"","Looking for a random number seed...\n");
#ifdef HAVE_NOVA
md = EVP_get_digestbyname("sha256");
#else
md = EVP_get_digestbyname("md5");
#endif
EVP_DigestInit(&context,md);
CfOut(cf_verbose,"","...\n");
snprintf(buffer,CF_BUFSIZE,"%d%d%25s",(int)CFSTARTTIME,(int)*digest,VFQNAME);
EVP_DigestUpdate(&context,buffer,CF_BUFSIZE);
snprintf(pscomm,CF_BUFSIZE,"%s %s",VPSCOMM[VSYSTEMHARDCLASS],VPSOPTS[VSYSTEMHARDCLASS]);
if ((pp = cf_popen(pscomm,"r")) != NULL)
{
CfOut(cf_error,"cf_popen","Couldn't open the process list with command %s\n",pscomm);
while (!feof(pp))
{
CfReadLine(buffer,CF_BUFSIZE,pp);
EVP_DigestUpdate(&context,buffer,CF_BUFSIZE);
}
}
uninitbuffer[99] = '\0';
snprintf(buffer,CF_BUFSIZE-1,"%ld %s",time(NULL),uninitbuffer);
EVP_DigestUpdate(&context,buffer,CF_BUFSIZE);
cf_pclose(pp);
EVP_DigestFinal(&context,digest,&md_len);
}
/*********************************************************************/
int EncryptString(char type,char *in,char *out,unsigned char *key,int plainlen)
{ int cipherlen = 0, tmplen;
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};
EVP_CIPHER_CTX ctx;
EVP_CIPHER_CTX_init(&ctx);
EVP_EncryptInit_ex(&ctx,CfengineCipher(type),NULL,key,iv);
if (!EVP_EncryptUpdate(&ctx,out,&cipherlen,in,plainlen))
{
EVP_CIPHER_CTX_cleanup(&ctx);
return -1;
}
if (!EVP_EncryptFinal_ex(&ctx,out+cipherlen,&tmplen))
{
EVP_CIPHER_CTX_cleanup(&ctx);
return -1;
}
cipherlen += tmplen;
EVP_CIPHER_CTX_cleanup(&ctx);
return cipherlen;
}
/*********************************************************************/
int DecryptString(char type,char *in,char *out,unsigned char *key,int cipherlen)
{ int plainlen = 0, tmplen;
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};
EVP_CIPHER_CTX ctx;
EVP_CIPHER_CTX_init(&ctx);
EVP_DecryptInit_ex(&ctx,CfengineCipher(type),NULL,key,iv);
if (!EVP_DecryptUpdate(&ctx,out,&plainlen,in,cipherlen))
{
CfOut(cf_error, "", "!! Decrypt FAILED");
EVP_CIPHER_CTX_cleanup(&ctx);
return -1;
}
if (!EVP_DecryptFinal_ex(&ctx,out+plainlen,&tmplen))
{
unsigned long err = ERR_get_error();
CfOut(cf_error,"","decryption FAILED at final of %d: %s\n",cipherlen,ERR_error_string(err,NULL));
EVP_CIPHER_CTX_cleanup(&ctx);
return -1;
}
plainlen += tmplen;
EVP_CIPHER_CTX_cleanup(&ctx);
return plainlen;
}
/*********************************************************************/
void DebugBinOut(char *buffer,int len,char *comment)
{ unsigned char *sp;
char buf[CF_BUFSIZE];
char hexStr[3]; // one byte as hex
if (len >= (sizeof(buf) / 2)) // hex uses two chars per byte
{
Debug("Debug binary print is too large (len=%d)", len);
return;
}
memset(buf, 0, sizeof(buf));
for (sp = buffer; sp < (unsigned char *)(buffer+len); sp++)
{
snprintf(hexStr, sizeof(hexStr), "%2.2x", (int)*sp);
strcat(buf, hexStr);
}
CfOut(cf_verbose, "", "BinaryBuffer(%d bytes => %s) -> [%s]",len,comment,buf);
}
/*********************************************************************/
static char *KeyPrint(RSA *pubkey)
{ unsigned char digest[EVP_MAX_MD_SIZE+1];
int i;
for (i = 0; i < EVP_MAX_MD_SIZE+1; i++)
{
digest[i] = 0;
}
HashString((char *)pubkey,sizeof(BIGNUM)-4,digest,CF_DEFAULT_DIGEST);
return HashPrint(CF_DEFAULT_DIGEST,digest);
}
cfengine-3.2.4/src/cf3.extern.h 0000644 0001750 0001750 00000022037 11715232734 013147 0000000 0000000 /*
Copyright (C) Cfengine AS
This file is part of Cfengine 3 - written and maintained by Cfengine 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 Commerical Open Source License
(COSL) may apply to this file if you as a licensee so wish it. See
included file COSL.txt.
*/
/*****************************************************************************/
/* */
/* File: cf3.extern.h */
/* */
/* Created: Thu Aug 2 12:51:18 2007 */
/* */
/*****************************************************************************/
#ifndef CFENGINE_CF3_EXTERN_H
#define CFENGINE_CF3_EXTERN_H
/* See variables in cf3globals.c and syntax.c */
extern struct Topic *TOPICHASH[CF_HASHTABLESIZE];
extern struct PromiseParser P;
extern int REQUIRE_COMMENTS;
extern int FIPS_MODE;
extern char POLICY_SERVER[CF_BUFSIZE];
extern int ALWAYS_VALIDATE;
extern int LICENSES;
extern int AM_NOVA;
extern int AM_CONSTELLATION;
extern char EXPIRY[32];
extern char LICENSE_COMPANY[CF_SMALLBUF];
extern int IGNORE_MISSING_INPUTS;
extern int IGNORE_MISSING_BUNDLES;
extern char WEBDRIVER[CF_MAXVARSIZE];
extern char DOCROOT[CF_MAXVARSIZE];
extern char BANNER[2*CF_BUFSIZE];
extern char FOOTER[CF_BUFSIZE];
extern char STYLESHEET[CF_BUFSIZE];
extern int CF_TOPICS;
extern int CF_OCCUR;
extern int CF_EDGES;
extern int KEYTTL;
extern struct Rlist *SERVER_KEYSEEN;
extern enum cfhashes CF_DEFAULT_DIGEST;
extern int CF_DEFAULT_DIGEST_LEN;
extern struct Item *EDIT_ANCHORS;
extern struct Bundle *BUNDLES;
extern struct Body *BODIES;
extern struct Scope *VSCOPE;
extern struct Audit *AUDITPTR;
extern struct Audit *VAUDIT;
extern struct Rlist *VINPUTLIST;
extern struct Rlist *BODYPARTS;
extern struct Rlist *SUBBUNDLES;
extern struct Rlist *SINGLE_COPY_LIST;
extern struct Rlist *AUTO_DEFINE_LIST;
extern struct Rlist *SINGLE_COPY_CACHE;
extern struct Rlist *ACCESSLIST;
extern struct PromiseIdent *PROMISE_ID_LIST;
extern struct Item *DONELIST;
extern struct Rlist *CBUNDLESEQUENCE;
extern char *CBUNDLESEQUENCE_STR;
extern struct Item *ROTATED;
extern double FORGETRATE;
extern struct Rlist *GOALS;
extern struct Rlist *GOALCATEGORIES;
extern struct Rlist *CF_STCK;
extern int EDIT_MODEL;
extern int CF_STCKFRAME;
extern int CFA_BACKGROUND;
extern int CFA_BACKGROUND_LIMIT;
extern int AM_BACKGROUND_PROCESS;
extern int CF_PERSISTENCE;
extern int LOOKUP;
extern int BOOTSTRAP;
extern int XML;
extern FILE *FREPORT_HTML;
extern FILE *FREPORT_TXT;
extern FILE *FKNOW;
extern struct FnCallStatus FNCALL_STATUS;
extern int CSV;
extern struct SubTypeSyntax CF_NOSTYPE;
extern char *CF_DATATYPES[];
extern char *CF_AGENTTYPES[];
extern char HASHDB[CF_BUFSIZE];
extern int FSTAB_EDITS;
extern char GRAPHDIR[CF_BUFSIZE];
extern int CFA_MAXTHREADS;
extern char *THIS_BUNDLE;
extern char THIS_AGENT[CF_MAXVARSIZE];
extern enum cfagenttype THIS_AGENT_TYPE;
extern int INSTALL_SKIP;
extern int SHOWREPORTS;
extern char SYSLOGHOST[CF_MAXVARSIZE];
extern unsigned short SYSLOGPORT;
extern time_t PROMISETIME;
extern time_t CF_LOCKHORIZON;
extern int ABORTBUNDLE;
extern struct Item *ABORTBUNDLEHEAP;
extern int LASTSEENEXPIREAFTER;
extern char *DEFAULT_COPYTYPE;
extern struct Rlist *SERVERLIST;
extern struct Item *PROCESSTABLE;
extern struct Item *PROCESSREFRESH;
extern struct Item *FSTABLIST;
extern struct Rlist *MOUNTEDFSLIST;
extern int CF_MOUNTALL;
extern int CF_SAVEFSTAB;
extern const char *DAY_TEXT[];
extern const char *MONTH_TEXT[];
extern const char *SHIFT_TEXT[];
#if defined(NT) && !defined(__CYGWIN__)
# define FILE_SEPARATOR '\\'
# define FILE_SEPARATOR_STR "\\"
# else
# define FILE_SEPARATOR '/'
# define FILE_SEPARATOR_STR "/"
#endif
extern char *BASIC_REPORTS[cfrep_unknown][2];
extern char *CDP_REPORTS[cdp_unknown][2];
extern char SQL_DATABASE[CF_MAXVARSIZE];
extern char SQL_OWNER[CF_MAXVARSIZE];
extern char SQL_PASSWD[CF_MAXVARSIZE];
extern char SQL_SERVER[CF_MAXVARSIZE];
extern char SQL_CONNECT_NAME[CF_MAXVARSIZE];
extern enum cfdbtype SQL_TYPE;
extern double VAL_KEPT;
extern double VAL_REPAIRED;
extern double VAL_NOTKEPT;
extern double METER_KEPT[meter_endmark];
extern double METER_REPAIRED[meter_endmark];
extern double Q_MEAN;
extern double Q_SIGMA;
/***********************************************************/
/* SYNTAX MODULES */
/***********************************************************/
#ifndef CF3_MOD_COMMON
extern struct SubTypeSyntax CF_COMMON_SUBTYPES[];
extern struct BodySyntax CF_BODY_TRANSACTION[];
extern struct BodySyntax CF_VARBODY[];
extern struct BodySyntax CF_CLASSBODY[];
extern struct BodySyntax CFG_CONTROLBODY[];
extern struct BodySyntax CFH_CONTROLBODY[];
extern struct BodySyntax CFA_CONTROLBODY[];
extern struct BodySyntax CFS_CONTROLBODY[];
extern struct BodySyntax CFE_CONTROLBODY[];
extern struct BodySyntax CFR_CONTROLBODY[];
extern struct BodySyntax CFK_CONTROLBODY[];
extern struct BodySyntax CFEX_CONTROLBODY[];
extern struct BodySyntax CF_TRIGGER_BODY[];
extern struct BodySyntax CF_TRANSACTION_BODY[];
extern struct BodySyntax CF_DEFINECLASS_BODY[];
extern struct BodySyntax CF_COMMON_BODIES[];
extern struct SubTypeSyntax *CF_ALL_SUBTYPES[];
extern struct SubTypeSyntax CF_ALL_BODIES[];
#endif
#ifndef CF3_MOD_ENVIRON
extern struct BodySyntax CF_RESOURCE_BODY[];
extern struct BodySyntax CF_DESIGNATION_BODY[];
extern struct BodySyntax CF_ENVIRON_BODIES[];
extern struct SubTypeSyntax CF_ENVIRONMENT_SUBTYPES[];
#endif
#ifndef CF3_MOD_OUTPUTS
extern struct BodySyntax CF_OUTPUTS_BODIES[];
extern struct SubTypeSyntax CF_OUTPUTS_SUBTYPES[];
#endif
#ifndef CF3_MOD_FUNCTIONS
extern struct FnCallType CF_FNCALL_TYPES[];
#endif
#ifndef CF3_MOD_ACCESS
extern struct BodySyntax CF_REMACCESS_BODIES[];
extern struct SubTypeSyntax CF_REMACCESS_SUBTYPES[];
#endif
#ifndef CF_MOD_INTERFACES
extern struct BodySyntax CF_TCPIP_BODY[];
extern struct BodySyntax CF_INTERFACES_BODIES[];
extern struct SubTypeSyntax CF_INTERFACES_SUBTYPES[];
#endif
#ifndef CF3_MOD_STORAGE
extern struct BodySyntax CF_STORAGE_BODIES[];
extern struct SubTypeSyntax CF_STORAGE_SUBTYPES[];
extern struct BodySyntax CF_MOUNT_BODY[];
extern struct BodySyntax CF_CHECKVOL_BODY[];
#endif
#ifndef CF3_MOD_DATABASES
extern struct BodySyntax CF_DATABASES_BODIES[];
extern struct SubTypeSyntax CF_DATABASES_SUBTYPES[];
extern struct BodySyntax CF_SQLSERVER_BODY[];
#endif
#ifndef CF3_MOD_KNOWLEGDE
extern struct SubTypeSyntax CF_KNOWLEDGE_SUBTYPES[];
extern struct BodySyntax CF_TOPICS_BODIES[];
extern struct BodySyntax CF_OCCUR_BODIES[];
extern struct BodySyntax CF_INFER_BODIES[];
extern struct BodySyntax CF_INFERENCE_BODY[];
extern struct BodySyntax CF_RELATE_BODY[];
#endif
#ifndef CF3_MOD_PACKAGES
extern struct SubTypeSyntax CF_PACKAGES_SUBTYPES[];
extern struct BodySyntax CF_PACKAGES_BODIES[];
extern struct BodySyntax CF_EXISTS_BODY[];
#endif
#ifndef CF3_MOD_REPORT
extern struct SubTypeSyntax CF_REPORT_SUBTYPES[];
extern struct BodySyntax CF_REPORT_BODIES[];
extern struct BodySyntax CF_PRINTFILE_BODY[];
#endif
#ifndef CF3_MOD_FILES
extern struct BodySyntax CF_COMMON_EDITBODIES[];
extern struct SubTypeSyntax CF_FILES_SUBTYPES[];
extern struct BodySyntax CF_APPEND_REPL_BODIES[];
extern struct BodySyntax CF_FILES_BODIES[];
extern struct BodySyntax CF_COPYFROM_BODY[];
extern struct BodySyntax CF_LINKTO_BODY[];
extern struct BodySyntax CF_FILEFILTER_BODY[];
extern struct BodySyntax CF_CHANGEMGT_BODY[];
extern struct BodySyntax CF_TIDY_BODY[];
extern struct BodySyntax CF_RENAME_BODY[];
extern struct BodySyntax CF_RECURSION_BODY[];
#endif
#ifndef CF3_MOD_EXEC
extern struct SubTypeSyntax CF_EXEC_SUBTYPES[];
#endif
#ifndef CF3_MOD_METHODS
extern struct SubTypeSyntax CF_METHOD_SUBTYPES[];
#endif
#ifndef CF3_MOD_PROCESS
extern struct SubTypeSyntax CF_PROCESS_SUBTYPES[];
extern struct BodySyntax CF_MATCHCLASS_BODY[];
extern struct BodySyntax CF_PROCFILTER_BODY[];
extern struct BodySyntax CF_PROCESS_BODIES[];
#endif
#ifndef CF3_MOD_PROCESS
extern struct SubTypeSyntax CF_MEASUREMENT_SUBTYPES[];
extern struct BodySyntax CF_MEASURE_BODIES[];
#endif
#ifndef CF3_MOD_SERVICES
extern struct SubTypeSyntax CF_SERVICES_SUBTYPES[];
extern struct BodySyntax CF_SERVMETHOD_BODY[];
extern struct BodySyntax CF_SERVICES_BODIES[];
#endif
#endif
cfengine-3.2.4/src/mod_methods.c 0000644 0001750 0001750 00000004061 11715232734 013462 0000000 0000000 /*
Copyright (C) Cfengine AS
This file is part of Cfengine 3 - written and maintained by Cfengine 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 Commerical Open Source License
(COSL) may apply to this file if you as a licensee so wish it. See
included file COSL.txt.
*/
/*****************************************************************************/
/* */
/* File: mod_methods.c */
/* */
/*****************************************************************************/
#define CF3_MOD_METHODS
#include "cf3.defs.h"
#include "cf3.extern.h"
/***************************************************************/
/* This is the primary set of constraints for a methods object */
struct BodySyntax CF_METHOD_BODIES[] =
{
{"usebundle",cf_bundle,CF_BUNDLE,"Specify the name of a bundle to run as a parameterized method"},
{NULL,cf_notype,NULL}
};
/***************************************************************/
/* This is the point of entry from mod_common.c */
/***************************************************************/
struct SubTypeSyntax CF_METHOD_SUBTYPES[] =
{
{"agent","methods",CF_METHOD_BODIES},
{NULL,NULL,NULL},
};
cfengine-3.2.4/src/mod_packages.c 0000644 0001750 0001750 00000013460 11715232734 013600 0000000 0000000 /*
Copyright (C) Cfengine AS
This file is part of Cfengine 3 - written and maintained by Cfengine 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 Commerical Open Source License
(COSL) may apply to this file if you as a licensee so wish it. See
included file COSL.txt.
*/
/*****************************************************************************/
/* */
/* File: mod_interfaces.c */
/* */
/*****************************************************************************/
#include "cf3.defs.h"
#include "cf3.extern.h"
/*****************************************************************************/
#define CF3_MOD_PACKAGES
struct BodySyntax CF_PKGMETHOD_BODY[] =
{
{"package_add_command",cf_str,CF_ABSPATHRANGE,"Command to install a package to the system"},
{"package_arch_regex",cf_str,"","Regular expression with one backreference to extract package architecture string" },
{"package_changes",cf_opts,"individual,bulk","Menu option - whether to group packages into a single aggregate command"},
{"package_delete_command",cf_str,CF_ABSPATHRANGE,"Command to remove a package from the system"},
{"package_delete_convention",cf_str,"","This is how the package manager expects the package to be referred to in the deletion part of a package update, e.g. $(name)"},
{"package_file_repositories",cf_slist,"","A list of machine-local directories to search for packages"},
{"package_installed_regex",cf_str,"","Regular expression which matches packages that are already installed"},
{"package_list_arch_regex",cf_str,"","Regular expression with one backreference to extract package architecture string" },
{"package_list_command",cf_str,CF_ABSPATHRANGE,"Command to obtain a list of available packages"},
{"package_list_name_regex",cf_str,"","Regular expression with one backreference to extract package name string" },
{"package_list_update_command",cf_str,"","Command to update the list of available packages (if any)" },
{"package_list_update_ifelapsed",cf_int,CF_INTRANGE,"The ifelapsed locking time in between updates of the package list" },
{"package_list_version_regex",cf_str,"","Regular expression with one backreference to extract package version string" },
{"package_name_convention",cf_str,"","This is how the package manager expects the package to be referred to, e.g. $(name).$(arch)"},
{"package_name_regex",cf_str,"","Regular expression with one backreference to extract package name string" },
{"package_noverify_regex",cf_str,"","Regular expression to match verification failure output"},
{"package_noverify_returncode",cf_int,CF_INTRANGE,"Integer return code indicating package verification failure"},
{"package_patch_arch_regex",cf_str,"","Regular expression with one backreference to extract update architecture string" },
{"package_patch_command",cf_str,CF_ABSPATHRANGE,"Command to update to the latest patch release of an installed package"},
{"package_patch_installed_regex",cf_str,"","Regular expression which matches packages that are already installed"},
{"package_patch_list_command",cf_str,CF_ABSPATHRANGE,"Command to obtain a list of available patches or updates"},
{"package_patch_name_regex",cf_str,"","Regular expression with one backreference to extract update name string" },
{"package_patch_version_regex",cf_str,"","Regular expression with one backreference to extract update version string" },
{"package_update_command",cf_str,CF_ABSPATHRANGE,"Command to update to the latest version a currently installed package"},
{"package_verify_command",cf_str,CF_ABSPATHRANGE,"Command to verify the correctness of an installed package"},
{"package_version_regex",cf_str,"","Regular expression with one backreference to extract package version string" },
{"package_multiline_start",cf_str,"","Regular expression which matches the start of a new package in multiline output" },
{NULL,cf_notype,NULL,NULL}
};
/***************************************************************/
/* This is the primary set of constraints for an interfaces object */
struct BodySyntax CF_PACKAGES_BODIES[] =
{
{"package_architectures",cf_slist,"","Select the architecture for package selection"},
{"package_method",cf_body,CF_PKGMETHOD_BODY,"Criteria for installation and verification"},
{"package_policy",cf_opts,"add,delete,reinstall,update,addupdate,patch,verify","Criteria for package installation/upgrade on the current system"},
{"package_select",cf_opts,">,<,==,!=,>=,<=","A criterion for first acceptable match relative to \"package_version\""},
{"package_version",cf_str,"","Version reference point for determining promised version"},
{NULL,cf_notype,NULL,NULL}
};
/***************************************************************/
/* This is the point of entry from mod_common.c */
/***************************************************************/
struct SubTypeSyntax CF_PACKAGES_SUBTYPES[] =
{
{"agent","packages",CF_PACKAGES_BODIES},
{NULL,NULL,NULL},
};
cfengine-3.2.4/src/fncall.c 0000644 0001750 0001750 00000017346 11715232734 012431 0000000 0000000 /*
Copyright (C) Cfengine AS
This file is part of Cfengine 3 - written and maintained by Cfengine 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 Commerical Open Source License
(COSL) may apply to this file if you as a licensee so wish it. See
included file COSL.txt.
*/
/*****************************************************************************/
/* */
/* File: fncall.c */
/* */
/* Created: Wed Aug 8 14:45:53 2007 */
/* */
/*****************************************************************************/
#include "cf3.defs.h"
#include "cf3.extern.h"
static void PrintFunctions(void);
static void ClearFnCallStatus(void);
/*******************************************************************/
int IsBuiltinFnCall(void *rval,char rtype)
{ int i;
struct FnCall *fp;
if (rtype != CF_FNCALL)
{
return false;
}
fp = (struct FnCall *)rval;
if (FindFunction(fp->name))
{
Debug("%s is a builtin function\n",fp->name);
return true;
}
else
{
return false;
}
}
/*******************************************************************/
struct FnCall *NewFnCall(char *name, struct Rlist *args)
{ struct FnCall *fp;
char *sp = NULL;
Debug("Installing Function Call %s\n",name);
if ((fp = (struct FnCall *)malloc(sizeof(struct FnCall))) == NULL)
{
CfOut(cf_error,"malloc","Unable to allocate FnCall");
FatalError("");
}
if ((sp = strdup(name)) == NULL)
{
CfOut(cf_error,"malloc","Unable to allocate Promise");
FatalError("");
}
fp->name = sp;
fp->args = args;
fp->argc = RlistLen(args);
Debug("Installed ");
if (DEBUG)
{
ShowFnCall(stdout,fp);
}
Debug("\n\n");
return fp;
}
/*******************************************************************/
struct FnCall *CopyFnCall(struct FnCall *f)
{
Debug("CopyFnCall()\n");
return NewFnCall(f->name,CopyRlist(f->args));
}
/*******************************************************************/
void DeleteFnCall(struct FnCall *fp)
{
if (fp->name)
{
free(fp->name);
}
if (fp->args)
{
DeleteRlist(fp->args);
}
free(fp);
}
/*********************************************************************/
struct FnCall *ExpandFnCall(char *contextid,struct FnCall *f,int expandnaked)
{
Debug("ExpandFnCall()\n");
//return NewFnCall(f->name,ExpandList(contextid,f->args,expandnaked));
return NewFnCall(f->name,ExpandList(contextid,f->args,false));
}
/*******************************************************************/
static void PrintFunctions(void)
{
int i;
for (i = 0; i < 3; i++)
{
if (P.currentfncall[i] != NULL)
{
printf("(%d) =========================\n|",i);
ShowFnCall(stdout,P.currentfncall[i]);
printf("|\n==============================\n");
}
}
}
/*******************************************************************/
int PrintFnCall(char *buffer, int bufsize,struct FnCall *fp)
{ struct Rlist *rp;
char work[CF_MAXVARSIZE];
snprintf(buffer,bufsize,"%s(",fp->name);
for (rp = fp->args; rp != NULL; rp=rp->next)
{
switch (rp->type)
{
case CF_SCALAR:
Join(buffer,(char *)rp->item,bufsize);
break;
case CF_FNCALL:
PrintFnCall(work,CF_MAXVARSIZE,(struct FnCall *)rp->item);
Join(buffer,work,bufsize);
break;
default:
break;
}
if (rp->next != NULL)
{
strcat(buffer,",");
}
}
strcat(buffer, ")");
return strlen(buffer);
}
/*******************************************************************/
void ShowFnCall(FILE *fout,struct FnCall *fp)
{ struct Rlist *rp;
if (XML)
{
fprintf(fout,"%s(",fp->name);
}
else
{
fprintf(fout,"%s(",fp->name);
}
for (rp = fp->args; rp != NULL; rp=rp->next)
{
switch (rp->type)
{
case CF_SCALAR:
fprintf(fout,"%s,",(char *)rp->item);
break;
case CF_FNCALL:
ShowFnCall(fout,(struct FnCall *)rp->item);
break;
default:
fprintf(fout,"(** Unknown argument **)\n");
break;
}
}
if (XML)
{
fprintf(fout,")");
}
else
{
fprintf(fout,")");
}
}
/*******************************************************************/
enum cfdatatype FunctionReturnType(const char *name)
{
FnCallType *fn = FindFunction(name);
return fn ? fn->dtype : cf_notype;
}
/*******************************************************************/
struct Rval EvaluateFunctionCall(struct FnCall *fp,struct Promise *pp)
{ struct Rlist *expargs;
struct Rval rval;
FnCallType *this = FindFunction(fp->name);
rval.item = NULL;
rval.rtype = CF_NOPROMISEE;
if (this)
{
if (DEBUG)
{
printf("EVALUATE FN CALL %s\n",fp->name);
ShowFnCall(stdout,fp);
printf("\n");
}
}
else
{
if (pp)
{
CfOut(cf_error,"","No such FnCall \"%s()\" in promise @ %s near line %d\n",fp->name,pp->audit->filename,pp->lineno);
}
else
{
CfOut(cf_error,"","No such FnCall \"%s()\" - context info unavailable\n",fp->name);
}
return rval;
}
/* If the container classes seem not to be defined at this stage, then don't try to expand the function */
if ((pp != NULL) && !IsDefinedClass(pp->classes))
{
return rval;
}
ClearFnCallStatus();
expargs = NewExpArgs(fp,pp);
if (UnresolvedArgs(expargs))
{
FNCALL_STATUS.status = FNCALL_FAILURE;
rval.item = CopyFnCall(fp);
rval.rtype = CF_FNCALL;
DeleteExpArgs(expargs);
return rval;
}
if (this)
{
rval = CallFunction(this, fp, expargs);
}
else
{
CfOut(cf_error,"","Un-registered function call");
PromiseRef(cf_error,pp);
}
if (FNCALL_STATUS.status == FNCALL_FAILURE)
{
/* We do not assign variables to failed function calls */
rval.item = CopyFnCall(fp);
rval.rtype = CF_FNCALL;
}
DeleteExpArgs(expargs);
return rval;
}
/*******************************************************************/
FnCallType *FindFunction(const char *name)
{
int i;
for (i = 0; CF_FNCALL_TYPES[i].name != NULL; i++)
{
if (strcmp(CF_FNCALL_TYPES[i].name,name) == 0)
{
return CF_FNCALL_TYPES + i;
}
}
return NULL;
}
/*****************************************************************************/
static void ClearFnCallStatus(void)
{
FNCALL_STATUS.status = CF_NOP;
FNCALL_STATUS.message[0] = '\0';
FNCALL_STATUS.fncall_classes[0] = '\0';
}
/*****************************************************************************/
void SetFnCallReturnStatus(char *name,int status,char *message,char *fncall_classes)
{
FNCALL_STATUS.status = status;
if (message && strlen(message) > 0)
{
strncpy(FNCALL_STATUS.message,message,CF_BUFSIZE-1);
}
if (fncall_classes && strlen(fncall_classes))
{
strncpy(FNCALL_STATUS.fncall_classes,fncall_classes,CF_BUFSIZE-1);
AddPrefixedClasses(name,fncall_classes);
}
}
cfengine-3.2.4/src/verify_reports.c 0000644 0001750 0001750 00000042464 11715232734 014253 0000000 0000000 /*
Copyright (C) Cfengine AS
This file is part of Cfengine 3 - written and maintained by Cfengine 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 Commerical Open Source License
(COSL) may apply to this file if you as a licensee so wish it. See
included file COSL.txt.
*/
/*****************************************************************************/
/* */
/* File: verify_reports.c */
/* */
/*****************************************************************************/
#include "cf3.defs.h"
#include "cf3.extern.h"
static void FriendStatus(struct Attributes a,struct Promise *pp);
static void VerifyFriendReliability(struct Attributes a,struct Promise *pp);
static void VerifyFriendConnections(int hours,struct Attributes a,struct Promise *pp);
static void ShowState(char *type,struct Attributes a,struct Promise *pp);
static void PrintFile(struct Attributes a,struct Promise *pp);
/*******************************************************************/
/* Agent reporting */
/*******************************************************************/
void VerifyReportPromise(struct Promise *pp)
{ struct Attributes a = {{0}};
struct CfLock thislock;
struct Rlist *rp;
char unique_name[CF_EXPANDSIZE];
a = GetReportsAttributes(pp);
if (strcmp(pp->classes,"any") == 0)
{
CfOut(cf_verbose,""," --> Reports promises may not be in class \"any\"");
return;
}
snprintf(unique_name,CF_EXPANDSIZE-1,"%s_%d",pp->promiser,pp->lineno);
thislock = AcquireLock(unique_name,VUQNAME,CFSTARTTIME,a,pp,false);
if (thislock.lock == NULL)
{
return;
}
PromiseBanner(pp);
cfPS(cf_verbose,CF_CHG,"",pp,a,"Report: %s", pp->promiser);
if (a.report.to_file)
{
CfFOut(a.report.to_file,cf_error,"","%s",pp->promiser);
}
else
{
CfOut(cf_reporting,"","R: %s",pp->promiser);
}
if (a.report.haveprintfile)
{
PrintFile(a,pp);
}
if (a.report.showstate)
{
for (rp = a.report.showstate; rp != NULL; rp=rp->next)
{
ShowState(rp->item,a,pp);
}
}
if (a.report.havelastseen)
{
FriendStatus(a,pp);
}
YieldCurrentLock(thislock);
}
/*******************************************************************/
/* Level */
/*******************************************************************/
static void PrintFile(struct Attributes a,struct Promise *pp)
{ FILE *fp;
char buffer[CF_BUFSIZE];
int lines = 0;
if (a.report.filename == NULL)
{
CfOut(cf_verbose,"","Printfile promise was incomplete, with no filename.\n");
return;
}
if ((fp = fopen(a.report.filename,"r")) == NULL)
{
cfPS(cf_error,CF_INTERPT,"fopen",pp,a," !! Printing of file %s was not possible.\n",a.report.filename);
return;
}
while (!feof(fp) && (lines < a.report.numlines))
{
buffer[0] = '\0';
fgets(buffer,CF_BUFSIZE,fp);
CfOut(cf_error,"","R: %s",buffer);
lines++;
}
fclose(fp);
}
/*********************************************************************/
static void ShowState(char *type,struct Attributes a,struct Promise *pp)
{ struct stat statbuf;
char buffer[CF_BUFSIZE],vbuff[CF_BUFSIZE],assemble[CF_BUFSIZE];
struct Item *addresses = NULL,*saddresses = NULL,*ip;
int i = 0, tot=0, min_signal_diversity = 1,conns=1;
int maxlen = 0,count;
double *dist = NULL, S = 0.0;
char *offset = NULL;
FILE *fp;
Debug("ShowState(%s)\n",type);
snprintf(buffer,CF_BUFSIZE-1,"%s/state/cf_%s",CFWORKDIR,type);
if (cfstat(buffer,&statbuf) == 0)
{
if ((fp = fopen(buffer,"r")) == NULL)
{
CfOut(cf_inform,"fopen","Could not open state memory %s\n",buffer);
return;
}
while(!feof(fp))
{
char local[CF_BUFSIZE],remote[CF_BUFSIZE];
buffer[0] = local[0] = remote[0] = '\0';
memset(vbuff,0,CF_BUFSIZE);
fgets(buffer,CF_BUFSIZE,fp);
if (strlen(buffer) > 0)
{
CfOut(cf_verbose,"","(%2d) %s",conns,buffer);
if (IsSocketType(type))
{
if (strncmp(type,"incoming",8) == 0 || strncmp(type,"outgoing",8) == 0)
{
if (strncmp(buffer,"tcp",3) == 0)
{
sscanf(buffer,"%*s %*s %*s %s %s",local,remote); /* linux-like */
}
else
{
sscanf(buffer,"%s %s",local,remote); /* solaris-like */
}
strncpy(vbuff,remote,CF_BUFSIZE-1);
DePort(vbuff);
}
}
else if (IsTCPType(type))
{
count = 1;
sscanf(buffer,"%d %[^\n]",&count,remote);
AppendItem(&addresses,remote,"");
SetItemListCounter(addresses,remote,count);
conns += count;
continue;
}
else
{
/* If we get here this is a process thing */
if (offset == NULL)
{
if ((offset = strstr(buffer,"CMD")))
{
}
else if ((offset = strstr(buffer,"COMMAND")))
{
}
if (offset == NULL)
{
continue;
}
}
strncpy(vbuff,offset,CF_BUFSIZE-1);
Chop(vbuff);
}
if (!IsItemIn(addresses,vbuff))
{
conns++;
AppendItem(&addresses,vbuff,"");
IncrementItemListCounter(addresses,vbuff);
}
else
{
conns++;
IncrementItemListCounter(addresses,vbuff);
}
}
}
fclose(fp);
conns--;
CfOut(cf_error,"","\n");
CfOut(cf_error,"","R: The peak measured state was q = %d:\n",conns);
if (IsSocketType(type)||IsTCPType(type))
{
if (addresses != NULL)
{
cfPS(cf_error,CF_CHG,"",pp,a," {\n");
}
for (ip = addresses; ip != NULL; ip=ip->next)
{
tot+=ip->counter;
buffer[0] = '\0';
sscanf(ip->name,"%s",buffer);
if (!IsIPV4Address(buffer) && !IsIPV6Address(buffer))
{
CfOut(cf_verbose,"","Rejecting address %s\n",ip->name);
continue;
}
CfOut(cf_error,"","R: DNS key: %s = %s (%d/%d)\n",buffer,IPString2Hostname(buffer),ip->counter,conns);
if (strlen(ip->name) > maxlen)
{
maxlen = strlen(ip->name);
}
}
if (addresses != NULL)
{
printf("R: -\n");
}
}
else
{
for (ip = addresses; ip != NULL; ip=ip->next)
{
tot+=ip->counter;
}
}
saddresses = SortItemListCounters(addresses);
for (ip = saddresses; ip != NULL; ip=ip->next)
{
int s;
if (maxlen > 17) /* ipv6 */
{
snprintf(assemble,CF_BUFSIZE,"Frequency: %-40s|",ip->name);
}
else
{
snprintf(assemble,CF_BUFSIZE,"Frequency: %-17s|",ip->name);
}
for (s = 0; (s < ip->counter) && (s < 50); s++)
{
if (s < 48)
{
strcat(assemble,"*");
}
else
{
strcat(assemble,"+");
}
}
CfOut(cf_error,"","R: %s \t(%d/%d)\n",assemble,ip->counter,conns);
}
dist = (double *) malloc((tot+1)*sizeof(double));
if (conns > min_signal_diversity)
{
for (i = 0,ip = addresses; ip != NULL; i++,ip=ip->next)
{
dist[i] = ((double)(ip->counter))/((double)tot);
S -= dist[i]*log(dist[i]);
}
CfOut(cf_error,"","R: Variability/entropy of addresses = %.1f %%\n",S/log((double)tot)*100.0);
CfOut(cf_error,"","R: (Entropy = 0 for single source, 100 for flatly distributed source)\n -\n");
}
CfOut(cf_error,"","\n");
CfOut(cf_error,"","R: State of %s peaked at %s\n",type,cf_ctime(&statbuf.st_mtime));
}
else
{
CfOut(cf_inform,"","R: State parameter %s is not known or recorded\n",type);
}
DeleteItemList(addresses);
if (dist)
{
free((char *)dist);
}
}
/*********************************************************************/
static void FriendStatus(struct Attributes a,struct Promise *pp)
{
VerifyFriendConnections(a.report.lastseen,a,pp);
VerifyFriendReliability(a,pp);
}
/*********************************************************************/
/* Level */
/*********************************************************************/
static void VerifyFriendConnections(int hours,struct Attributes a,struct Promise *pp)
/* Go through the database of recent connections and check for
Long Time No See ...*/
{ CF_DB *dbp;
CF_DBC *dbcp;
char *key;
void *value;
int ksize,vsize;
int secs = SECONDS_PER_HOUR*hours, criterion, overdue;
time_t now = time(NULL),lsea = (time_t)CF_WEEK, tthen, then;
char name[CF_BUFSIZE],hostname[CF_BUFSIZE],datebuf[CF_MAXVARSIZE];
char addr[CF_BUFSIZE],type[CF_BUFSIZE],output[CF_BUFSIZE];
struct QPoint entry;
double average = 0.0, var = 0.0, ticksperminute = 60.0;
double ticksperhour = (double)SECONDS_PER_HOUR;
CfOut(cf_verbose,"","CheckFriendConnections(%d)\n",hours);
snprintf(name,CF_BUFSIZE-1,"%s/lastseen/%s",CFWORKDIR,CF_LASTDB_FILE);
MapName(name);
if (!OpenDB(name,&dbp))
{
return;
}
/* Acquire a cursor for the database. */
if (!NewDBCursor(dbp,&dbcp))
{
CfOut(cf_inform,""," !! Unable to scan friend db");
return;
}
/* Walk through the database and print out the key/data pairs. */
while(NextDB(dbp,dbcp,&key,&ksize,&value,&vsize))
{
memset(&entry, 0, sizeof(entry));
strncpy(hostname,(char *)key,ksize);
if (value != NULL)
{
memcpy(&entry,value,sizeof(entry));
then = (time_t)entry.q;
average = (double)entry.expect;
var = (double)entry.var;
}
else
{
continue;
}
if (then == 0)
{
continue; // No data
}
/* Got data, now get expiry criterion */
if (secs == 0)
{
/* Twice the average delta is significant */
criterion = (now - then > (int)(average+2.0*sqrt(var)+0.5));
overdue = now - then - (int)(average);
}
else
{
criterion = (now - then > secs);
overdue = (now - then - secs);
}
if (LASTSEENEXPIREAFTER < 0)
{
lsea = (time_t)CF_WEEK;
}
else
{
lsea = LASTSEENEXPIREAFTER;
}
if (a.report.friend_pattern)
{
if (FullTextMatch(a.report.friend_pattern,IPString2Hostname(hostname+1)))
{
CfOut(cf_verbose,"","Not judging friend %s\n",hostname);
criterion = false;
lsea = CF_INFINITY;
}
}
tthen = (time_t)then;
snprintf(datebuf,CF_MAXVARSIZE-1,"%s",cf_ctime(&tthen));
datebuf[strlen(datebuf)-9] = '\0'; /* Chop off second and year */
snprintf(addr,15,"%s",hostname+1);
switch(*hostname)
{
case '+':
snprintf(type,CF_BUFSIZE,"last responded to hails");
break;
case'-':
snprintf(type,CF_BUFSIZE,"last hailed us");
break;
}
snprintf(output,CF_BUFSIZE,"Host %s i.e. %s %s @ [%s] (overdue by %d mins)",
IPString2Hostname(hostname+1),
addr,
type,
datebuf,
overdue/(int)ticksperminute);
if (criterion)
{
CfOut(cf_error,"",output);
}
else
{
CfOut(cf_verbose,"",output);
}
snprintf(output,CF_BUFSIZE,"i.e. (%.2f) hrs ago, Av %.2f +/- %.2f hrs\n",
((double)(now-then))/ticksperhour,
average/ticksperhour,
sqrt(var)/ticksperhour);
if (criterion)
{
CfOut(cf_error,"",output);
}
else
{
CfOut(cf_verbose,"",output);
}
if (now - then > lsea)
{
CfOut(cf_error,"","Giving up on host %s -- %d hours since last seen",IPString2Hostname(hostname+1),hours);
DeleteDB(dbp,hostname);
}
memset(&value,0,sizeof(value));
memset(&key,0,sizeof(key));
}
DeleteDBCursor(dbp,dbcp);
CloseDB(dbp);
}
/***************************************************************/
static void VerifyFriendReliability(struct Attributes a,struct Promise *pp)
{ CF_DB *dbp;
CF_DBC *dbcp;
int i,ksize,vsize;
char *key;
void *value;
double n[CF_RELIABLE_CLASSES],n_av[CF_RELIABLE_CLASSES],total;
double p[CF_RELIABLE_CLASSES],p_av[CF_RELIABLE_CLASSES];
char name[CF_BUFSIZE],hostname[CF_BUFSIZE],timekey[CF_MAXVARSIZE];
struct QPoint entry;
struct Item *ip, *hostlist = NULL;
double average,var,sum,sum_av,expect,actual;
time_t now = time(NULL), then, lastseen = CF_WEEK;
CfOut(cf_verbose,"","CheckFriendReliability()\n");
snprintf(name,CF_BUFSIZE-1,"%s/%s",CFWORKDIR,CF_LASTDB_FILE);
average = (double) CF_HOUR; /* It will take a week for a host to be deemed reliable */
var = 0;
if (!OpenDB(name,&dbp))
{
return;
}
if (!NewDBCursor(dbp,&dbcp))
{
CfOut(cf_inform,""," !! Unable to scan last-seen db");
return;
}
while(NextDB(dbp,dbcp,&key,&ksize,&value,&vsize))
{
strcpy(hostname,IPString2Hostname((char *)key+1));
if (!IsItemIn(hostlist,hostname))
{
/* Check hostname not recorded twice with +/- */
AppendItem(&hostlist,hostname,NULL);
CfOut(cf_verbose,""," Measuring reliability of %s\n",hostname);
}
}
DeleteDBCursor(dbp,dbcp);
CloseDB(dbp);
/* Now go through each host and recompute entropy */
for (ip = hostlist; ip != NULL; ip=ip->next)
{
snprintf(name,CF_BUFSIZE-1,"%s/%s.%s",CFWORKDIR,CF_LASTDB_FILE,ip->name);
MapName(name);
if (!OpenDB(name,&dbp))
{
return;
}
for (i = 0; i < CF_RELIABLE_CLASSES; i++)
{
n[i] = n_av[i] = 0.0;
}
total = 0.0;
for (now = CF_MONDAY_MORNING; now < CF_MONDAY_MORNING+CF_WEEK; now += CF_MEASURE_INTERVAL)
{
strcpy(timekey,GenTimeKey(now));
if (ReadDB(dbp,timekey,&value,sizeof(entry)))
{
memcpy(&entry,value,sizeof(entry));
then = (time_t)entry.q;
lastseen = now - then;
if (lastseen < 0)
{
lastseen = 0; /* Never seen before, so pretend */
}
average = (double)entry.expect;
var = (double)entry.var;
Debug("%s => then = %ld, lastseen = %ld, average=%.2f\n",hostname,then,lastseen,average);
}
else
{
/* If we have no data, it means no contact for whatever reason.
It could be unable to respond unwilling to respond, policy etc.
Assume for argument that we expect regular responses ... */
lastseen += CF_MEASURE_INTERVAL; /* infer based on no data */
}
for (i = 0; i < CF_RELIABLE_CLASSES; i++)
{
if (lastseen >= i*CF_HOUR && lastseen < (i+1)*CF_HOUR)
{
n[i]++;
}
if (average >= (double)(i*CF_HOUR) && average < (double)((i+1)*CF_HOUR))
{
n_av[i]++;
}
}
total++;
}
sum = sum_av = 0.0;
for (i = 0; i < CF_RELIABLE_CLASSES; i++)
{
p[i] = n[i]/total;
p_av[i] = n_av[i]/total;
sum += p[i];
sum_av += p_av[i];
}
Debug("Reliabilities sum to %.2f av %.2f\n\n",sum,sum_av);
sum = sum_av = 0.0;
for (i = 0; i < CF_RELIABLE_CLASSES; i++)
{
if (p[i] == 0.0)
{
continue;
}
sum -= p[i] * log(p[i]);
}
for (i = 0; i < CF_RELIABLE_CLASSES; i++)
{
if (p_av[i] == 0.0)
{
continue;
}
sum_av -= p_av[i] * log(p_av[i]);
}
actual = sum/log((double)CF_RELIABLE_CLASSES)*100.0;
expect = sum_av/log((double)CF_RELIABLE_CLASSES)*100.0;
CfOut(cf_verbose,"","Scaled entropy for %s = %.1f %%\n",ip->name,actual);
CfOut(cf_verbose,"","Expected entropy for %s = %.1f %%\n\n",ip->name,expect);
if (actual > expect)
{
CfOut(cf_inform,""," !! The reliability of %s deteriorated\n",ip->name);
}
if (actual > 50.0)
{
CfOut(cf_error,"","FriendStatus reports the intermittency of %s above 50%% (SEUs)\n",ip->name);
}
if (expect > actual)
{
CfOut(cf_inform,"","The reliability of %s is improved\n",ip->name);
}
CloseDB(dbp);
}
DeleteItemList(hostlist);
}
cfengine-3.2.4/src/verify_storage.c 0000644 0001750 0001750 00000027523 11715232734 014220 0000000 0000000 /*
Copyright (C) Cfengine AS
This file is part of Cfengine 3 - written and maintained by Cfengine 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 Commerical Open Source License
(COSL) may apply to this file if you as a licensee so wish it. See
included file COSL.txt.
*/
/*****************************************************************************/
/* */
/* File: verify_storage.c */
/* */
/*****************************************************************************/
#include "cf3.defs.h"
#include "cf3.extern.h"
static void FindStoragePromiserObjects(struct Promise *pp);
static int VerifyFileSystem(char *name,struct Attributes a,struct Promise *pp);
static int VerifyFreeSpace(char *file,struct Attributes a,struct Promise *pp);
static void VolumeScanArrivals(char *file,struct Attributes a,struct Promise *pp);
static int FileSystemMountedCorrectly(struct Rlist *list,char *name,char *options,struct Attributes a,struct Promise *pp);
static int IsForeignFileSystem (struct stat *childstat,char *dir);
#ifndef MINGW
static int VerifyMountPromise(char *file,struct Attributes a,struct Promise *pp);
#endif /* NOT MINGW */
/*****************************************************************************/
void *FindAndVerifyStoragePromises(struct Promise *pp)
{
PromiseBanner(pp);
FindStoragePromiserObjects(pp);
return (void *)NULL;
}
/*****************************************************************************/
static void FindStoragePromiserObjects(struct Promise *pp)
{
/* Check if we are searching over a regular expression */
LocateFilePromiserGroup(pp->promiser,pp,VerifyStoragePromise);
}
/*****************************************************************************/
void VerifyStoragePromise(char *path,struct Promise *pp)
{ struct Attributes a = {{0}};
struct CfLock thislock;
a = GetStorageAttributes(pp);
CF_OCCUR++;
#ifdef MINGW
if(!a.havemount)
{
CfOut(cf_verbose, "", "storage.mount is not supported on Windows");
}
#endif
/* No parameter conflicts here */
if (a.mount.unmount)
{
if (a.mount.mount_source || a.mount.mount_server)
{
CfOut(cf_verbose,""," !! An unmount promise indicates a mount-source information - probably in error\n");
}
}
else if (a.havemount)
{
if (a.mount.mount_source == NULL || a.mount.mount_server == NULL)
{
CfOut(cf_error,""," !! Insufficient specification in mount promise - need source and server\n");
return;
}
}
thislock = AcquireLock(path,VUQNAME,CFSTARTTIME,a,pp,false);
if (thislock.lock == NULL)
{
return;
}
/* Do mounts first */
#ifndef MINGW
if (!MOUNTEDFSLIST && !LoadMountInfo(&MOUNTEDFSLIST))
{
CfOut(cf_error,"","Couldn't obtain a list of mounted filesystems - aborting\n");
YieldCurrentLock(thislock);
return;
}
if (a.havemount)
{
VerifyMountPromise(path,a,pp);
}
#endif /* NOT MINGW */
/* Then check file system */
if (a.havevolume)
{
VerifyFileSystem(path,a,pp);
if (a.volume.freespace != CF_NOINT)
{
VerifyFreeSpace(path,a,pp);
}
if (a.volume.scan_arrivals)
{
VolumeScanArrivals(path,a,pp);
}
}
YieldCurrentLock(thislock);
}
/*******************************************************************/
/** Level */
/*******************************************************************/
static int VerifyFileSystem(char *name,struct Attributes a,struct Promise *pp)
{ struct stat statbuf, localstat;
CFDIR *dirh;
const struct dirent *dirp;
off_t sizeinbytes = 0;
long filecount = 0;
char buff[CF_BUFSIZE];
CfOut(cf_verbose,""," -> Checking required filesystem %s\n",name);
if (cfstat(name,&statbuf) == -1)
{
return(false);
}
if (S_ISLNK(statbuf.st_mode))
{
KillGhostLink(name,a,pp);
return(true);
}
if (S_ISDIR(statbuf.st_mode))
{
if ((dirh = OpenDirLocal(name)) == NULL)
{
CfOut(cf_error,"opendir","Can't open directory %s which checking required/disk\n",name);
return false;
}
for (dirp = ReadDir(dirh); dirp != NULL; dirp = ReadDir(dirh))
{
if (!ConsiderFile(dirp->d_name,name,a,pp))
{
continue;
}
filecount++;
strcpy(buff,name);
if (buff[strlen(buff)] != FILE_SEPARATOR)
{
strcat(buff,FILE_SEPARATOR_STR);
}
strcat(buff,dirp->d_name);
if (lstat(buff,&localstat) == -1)
{
if (S_ISLNK(localstat.st_mode))
{
KillGhostLink(buff,a,pp);
continue;
}
CfOut(cf_error,"lstat","Can't stat volume %s\n",buff);
continue;
}
sizeinbytes += localstat.st_size;
}
CloseDir(dirh);
if (sizeinbytes < 0)
{
CfOut(cf_verbose,"","Internal error: count of byte size was less than zero!\n");
return true;
}
if (sizeinbytes < a.volume.sensible_size)
{
cfPS(cf_error,CF_INTERPT,"",pp,a," !! File system %s is suspiciously small! (%d bytes)\n",name,sizeinbytes);
return(false);
}
if (filecount < a.volume.sensible_count)
{
cfPS(cf_error,CF_INTERPT,"",pp,a," !! Filesystem %s has only %d files/directories.\n",name,filecount);
return(false);
}
}
cfPS(cf_inform,CF_NOP,"",pp,a," -> Filesystem %s's content seems to be sensible as promised\n",name);
return(true);
}
/*******************************************************************/
static int VerifyFreeSpace(char *file,struct Attributes a,struct Promise *pp)
{ struct stat statbuf;
long kilobytes;
#ifdef MINGW
if (!a.volume.check_foreign)
{
CfOut(cf_verbose, "", "storage.volume.check_foreign is not supported on Windows (checking every mount)");
}
#endif /* MINGW */
if (cfstat(file,&statbuf) == -1)
{
CfOut(cf_error,"stat","Couldn't stat %s checking diskspace\n",file);
return true;
}
#ifndef MINGW
if (!a.volume.check_foreign)
{
if (IsForeignFileSystem(&statbuf,file))
{
CfOut(cf_inform,"","Filesystem %s is mounted from a foreign system, so skipping it",file);
return true;
}
}
#endif /* NOT MINGW */
kilobytes = a.volume.freespace;
if (kilobytes < 0)
{
int free = (int)GetDiskUsage(file,cfpercent);
kilobytes = -1 * kilobytes;
if (free < (int)kilobytes)
{
cfPS(cf_error,CF_FAIL,"",pp,a," !! Free disk space is under %ld%% for volume containing %s (%d%% free)\n",kilobytes,file,free);
return false;
}
}
else
{
off_t free = GetDiskUsage(file, cfabs);
kilobytes = kilobytes / 1024;
if (free < kilobytes)
{
cfPS(cf_error,CF_FAIL,"",pp,a," !! Disk space under %ld kB for volume containing %s (%lld kB free)\n",kilobytes,file,(long long)free);
return false;
}
}
return true;
}
/*******************************************************************/
static void VolumeScanArrivals(char *file,struct Attributes a,struct Promise *pp)
{
CfOut(cf_verbose,"","Scan arrival sequence . not yet implemented\n");
}
/*******************************************************************/
static int FileSystemMountedCorrectly(struct Rlist *list,char *name,char *options,struct Attributes a,struct Promise *pp)
{ struct Rlist *rp;
struct CfMount *mp;
int found = false;
for (rp = list; rp != NULL; rp=rp->next)
{
mp = (struct CfMount *)rp->item;
if (mp == NULL)
{
continue;
}
/* Give primacy to the promised / affected object */
if (strcmp(name,mp->mounton) == 0)
{
/* We have found something mounted on the promiser dir */
found = true;
if (a.mount.mount_source && (strcmp(mp->source,a.mount.mount_source) != 0))
{
CfOut(cf_inform,"","A different file system (%s:%s) is mounted on %s than what is promised\n",mp->host,mp->source,name);
return false;
}
else
{
CfOut(cf_verbose,""," -> File system %s seems to be mounted correctly\n",mp->source);
break;
}
}
}
if (!found)
{
if (! a.mount.unmount)
{
CfOut(cf_verbose,""," !! File system %s seems not to be mounted correctly\n",name);
CF_MOUNTALL = true;
}
}
return found;
}
/*********************************************************************/
/* Mounting */
/*********************************************************************/
static int IsForeignFileSystem (struct stat *childstat,char *dir)
/* Is FS NFS mounted ? */
{ struct stat parentstat;
char vbuff[CF_BUFSIZE];
strncpy(vbuff,dir,CF_BUFSIZE-1);
if (vbuff[strlen(vbuff)-1] == FILE_SEPARATOR)
{
strcat(vbuff,"..");
}
else
{
strcat(vbuff,FILE_SEPARATOR_STR);
strcat(vbuff,"..");
}
if (cfstat(vbuff,&parentstat) == -1)
{
CfOut(cf_verbose,"stat"," !! Unable to stat %s",vbuff);
return(false);
}
if (childstat->st_dev != parentstat.st_dev)
{
struct Rlist *rp;
struct CfMount *entry;
Debug("[%s is on a different file system, not descending]\n",dir);
for (rp = MOUNTEDFSLIST; rp != NULL; rp=rp->next)
{
entry = (struct CfMount *)rp->item;
if (!strcmp(entry->mounton, dir))
{
if (entry->options && strstr(entry->options,"nfs"))
{
return (true);
}
}
}
}
Debug("NotMountedFileSystem\n");
return(false);
}
/*********************************************************************/
/* Unix-specific implementations */
/*********************************************************************/
#ifndef MINGW
static int VerifyMountPromise(char *name,struct Attributes a,struct Promise *pp)
{ char *options;
char dir[CF_BUFSIZE];
int changes = 0;
CfOut(cf_verbose,""," -> Verifying mounted file systems on %s\n",name);
snprintf(dir,CF_BUFSIZE,"%s/.",name);
if (!IsPrivileged())
{
cfPS(cf_error,CF_INTERPT,"",pp,a,"Only root can mount filesystems.\n","");
return false;
}
options = Rlist2String(a.mount.mount_options,",");
if (!FileSystemMountedCorrectly(MOUNTEDFSLIST,name,options,a,pp))
{
if (!a.mount.unmount)
{
if (!MakeParentDirectory(dir,a.move_obstructions))
{
}
if (a.mount.editfstab)
{
changes += VerifyInFstab(name,a,pp);
}
else
{
cfPS(cf_inform,CF_FAIL,"",pp,a," -> Filesystem %s was not mounted as promised, and no edits were promised in %s\n",name,VFSTAB[VSYSTEMHARDCLASS]);
// Mount explicitly
VerifyMount(name,a,pp);
}
}
else
{
if (a.mount.editfstab)
{
changes += VerifyNotInFstab(name,a,pp);
}
}
if (changes)
{
CF_MOUNTALL = true;
}
}
else
{
if (a.mount.unmount)
{
VerifyUnmount(name,a,pp);
if (a.mount.editfstab)
{
VerifyNotInFstab(name,a,pp);
}
}
else
{
cfPS(cf_inform,CF_NOP,"",pp,a," -> Filesystem %s seems to be mounted as promised\n",name);
}
}
free(options);
return true;
}
#endif /* NOT MINGW */
cfengine-3.2.4/src/recursion.c 0000644 0001750 0001750 00000017012 11715232734 013171 0000000 0000000 /*
Copyright (C) Cfengine AS
This file is part of Cfengine 3 - written and maintained by Cfengine 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 Commerical Open Source License
(COSL) may apply to this file if you as a licensee so wish it. See
included file COSL.txt.
*/
/*****************************************************************************/
/* */
/* File: recursion.c */
/* */
/*****************************************************************************/
#include "cf3.defs.h"
#include "cf3.extern.h"
static int PushDirState(char *name,struct stat *sb);
static void PopDirState(int goback,char * name,struct stat *sb,struct Recursion r);
static void CheckLinkSecurity(struct stat *sb,char *name);
/*********************************************************************/
/* Depth searches */
/*********************************************************************/
int DepthSearch(char *name,struct stat *sb,int rlevel,struct Attributes attr,struct Promise *pp)
{ CFDIR *dirh;
int goback;
const struct dirent *dirp;
char path[CF_BUFSIZE];
struct stat lsb;
if (!attr.havedepthsearch) /* if the search is trivial, make sure that we are in the parent dir of the leaf */
{
char basedir[CF_BUFSIZE];
Debug(" -> Direct file reference %s, no search implied\n",name);
snprintf(basedir, sizeof(basedir), "%s", name);
ChopLastNode(basedir);
chdir(basedir);
return VerifyFileLeaf(name,sb,attr,pp);
}
if (rlevel > CF_RECURSION_LIMIT)
{
CfOut(cf_error,"","WARNING: Very deep nesting of directories (>%d deep): %s (Aborting files)",rlevel,name);
return false;
}
if (rlevel > CF_RECURSION_LIMIT)
{
CfOut(cf_error,"","WARNING: Very deep nesting of directories (>%d deep): %s (Aborting files)",rlevel,name);
return false;
}
memset(path,0,CF_BUFSIZE);
Debug("To iterate is Human, to recurse is Divine...(%s)\n",name);
if (!PushDirState(name,sb))
{
return false;
}
if ((dirh = OpenDirLocal(".")) == NULL)
{
CfOut(cf_inform,"opendir","Could not open existing directory %s\n",name);
return false;
}
for (dirp = ReadDir(dirh); dirp != NULL; dirp = ReadDir(dirh))
{
if (!ConsiderFile(dirp->d_name,name,attr,pp))
{
continue;
}
strcpy(path,name);
AddSlash(path);
if (!JoinPath(path,dirp->d_name))
{
CloseDir(dirh);
return true;
}
if (lstat(dirp->d_name,&lsb) == -1)
{
CfOut(cf_verbose,"lstat","Recurse was looking at %s when an error occurred:\n",path);
continue;
}
if (S_ISLNK(lsb.st_mode)) /* should we ignore links? */
{
if (!KillGhostLink(path,attr,pp))
{
VerifyFileLeaf(path,&lsb,attr,pp);
}
else
{
continue;
}
}
/* See if we are supposed to treat links to dirs as dirs and descend */
if (attr.recursion.travlinks && S_ISLNK(lsb.st_mode))
{
if (lsb.st_uid != 0 && lsb.st_uid != getuid())
{
CfOut(cf_inform,"","File %s is an untrusted link: cfengine will not follow it with a destructive operation",path);
continue;
}
/* if so, hide the difference by replacing with actual object */
if (cfstat(dirp->d_name,&lsb) == -1)
{
CfOut(cf_error,"stat","Recurse was working on %s when this failed:\n",path);
continue;
}
}
if (attr.recursion.xdev && DeviceBoundary(&lsb,pp))
{
CfOut(cf_verbose,"","Skipping %s on different device - use xdev option to change this\n",path);
continue;
}
if (S_ISDIR(lsb.st_mode))
{
if (SkipDirLinks(path,dirp->d_name,attr.recursion))
{
continue;
}
if (attr.recursion.depth > 1 && rlevel <= attr.recursion.depth)
{
CfOut(cf_verbose,""," ->> Entering %s (%d)\n",path,rlevel);
goback = DepthSearch(path,&lsb,rlevel+1,attr,pp);
PopDirState(goback,name,sb,attr.recursion);
VerifyFileLeaf(path,&lsb,attr,pp);
}
else
{
VerifyFileLeaf(path,&lsb,attr,pp);
}
}
else
{
VerifyFileLeaf(path,&lsb,attr,pp);
}
}
CloseDir(dirh);
return true;
}
/*******************************************************************/
/* Level */
/*******************************************************************/
static int PushDirState(char *name,struct stat *sb)
{
if (chdir(name) == -1)
{
CfOut(cf_inform,"chdir","Could not change to directory %s, mode %o in tidy",name,sb->st_mode & 07777);
return false;
}
else
{
Debug("Changed directory to %s\n",name);
}
CheckLinkSecurity(sb,name);
return true;
}
/**********************************************************************/
static void PopDirState(int goback,char *name,struct stat *sb,struct Recursion r)
{
if (goback && r.travlinks)
{
if (chdir(name) == -1)
{
CfOut(cf_error,"chdir","Error in backing out of recursive travlink descent securely to %s",name);
HandleSignals(SIGTERM);
}
CheckLinkSecurity(sb,name);
}
else if (goback)
{
if (chdir("..") == -1)
{
CfOut(cf_error,"chdir","Error in backing out of recursive descent securely to %s",name);
HandleSignals(SIGTERM);
}
}
}
/**********************************************************************/
int SkipDirLinks(char *path,const char *lastnode,struct Recursion r)
{
Debug("SkipDirLinks(%s,%s)\n",path,lastnode);
if (r.exclude_dirs)
{
if (MatchRlistItem(r.exclude_dirs,path) || MatchRlistItem(r.exclude_dirs,lastnode))
{
CfOut(cf_verbose,"","Skipping matched excluded directory %s\n",path);
return true;
}
}
if (r.include_dirs)
{
if (!(MatchRlistItem(r.include_dirs,path) || MatchRlistItem(r.include_dirs,lastnode)))
{
CfOut(cf_verbose,"","Skipping matched non-included directory %s\n",path);
return true;
}
}
return false;
}
/**********************************************************************/
static void CheckLinkSecurity(struct stat *sb,char *name)
{ struct stat security;
Debug("Checking the inode and device to make sure we are where we think we are...\n");
if (cfstat(".",&security) == -1)
{
CfOut(cf_error,"stat","Could not stat directory %s after entering!",name);
return;
}
if ((sb->st_dev != security.st_dev) || (sb->st_ino != security.st_ino))
{
CfOut(cf_error,"","SERIOUS SECURITY ALERT: path race exploited in recursion to/from %s. Not safe for agent to continue - aborting",name);
HandleSignals(SIGTERM);
/* Exits */
}
}
cfengine-3.2.4/src/client_protocol.c 0000644 0001750 0001750 00000037065 11715232734 014371 0000000 0000000
/*
Copyright (C) Cfengine AS
This file is part of Cfengine 3 - written and maintained by Cfengine 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 Commerical Open Source License
(COSL) may apply to this file if you as a licensee so wish it. See
included file COSL.txt.
*/
/*****************************************************************************/
/* */
/* File: client_protocol.c */
/* */
/*****************************************************************************/
#include "cf3.defs.h"
#include "cf3.extern.h"
static void CheckServerVersion(struct cfagent_connection *conn,struct Attributes attr, struct Promise *pp);
static void FreeRSAKey(RSA *key);
/*********************************************************************/
static void SetSessionKey(struct cfagent_connection *conn);
/*********************************************************************/
int IdentifyAgent(int sd,char *localip,int family)
{ char uname[CF_BUFSIZE], sendbuff[CF_BUFSIZE],dnsname[CF_BUFSIZE];
int len,err;
#if defined(HAVE_GETADDRINFO)
char myaddr[256]; /* Compilation trick for systems that don't know ipv6 */
#else
struct sockaddr_in myaddr;
struct in_addr *iaddr;
struct hostent *hp;
#endif
memset(sendbuff,0,CF_BUFSIZE);
memset(dnsname,0,CF_BUFSIZE);
if (!SKIPIDENTIFY && (strcmp(VDOMAIN,CF_START_DOMAIN) == 0))
{
CfOut(cf_error,"","Undefined domain name");
return false;
}
if (!SKIPIDENTIFY)
{
/* First we need to find out the IP address and DNS name of the socket
we are sending from. This is not necessarily the same as VFQNAME if
the machine has a different uname from its IP name (!) This can
happen on poorly set up machines or on hosts with multiple
interfaces, with different names on each interface ... */
switch (family)
{
case AF_INET: len = sizeof(struct sockaddr_in);
break;
#if defined(HAVE_GETADDRINFO)
case AF_INET6: len = sizeof(struct sockaddr_in6);
break;
#endif
default:
CfOut(cf_error,"","Software error in IdentifyForVerification");
}
if (getsockname(sd,(struct sockaddr *)&myaddr,&len) == -1)
{
CfOut(cf_error,"getsockname","Couldn't get socket address\n");
return false;
}
snprintf(localip,CF_MAX_IP_LEN-1,"%s",sockaddr_ntop((struct sockaddr *)&myaddr));
Debug("Identifying this agent as %s i.e. %s, with signature %d\n",localip,VFQNAME,CFSIGNATURE);
#if defined(HAVE_GETADDRINFO)
if ((err=getnameinfo((struct sockaddr *)&myaddr,len,dnsname,CF_MAXVARSIZE,NULL,0,0)) != 0)
{
CfOut(cf_error,"","Couldn't look up address v6 for %s: %s\n",dnsname,gai_strerror(err));
return false;
}
#else
iaddr = &(myaddr.sin_addr);
hp = gethostbyaddr((void *)iaddr,sizeof(myaddr.sin_addr),family);
if ((hp == NULL) || (hp->h_name == NULL))
{
CfOut(cf_error,"gethostbyaddr","Couldn't lookup IP address\n");
return false;
}
strncpy(dnsname,hp->h_name,CF_MAXVARSIZE);
if ((strstr(hp->h_name,".") == 0) && (strlen(VDOMAIN) > 0))
{
strcat(dnsname,".");
strcat(dnsname,VDOMAIN);
}
#endif
}
else
{
strcpy(localip,VIPADDRESS);
if (strlen(VFQNAME) > 0)
{
CfOut(cf_verbose,"","skipidentify was promised, so we are trusting and simply announcing the identity as (%s) for this host\n",VFQNAME);
strcat(dnsname,VFQNAME);
}
else
{
strcat(dnsname,"skipident");
}
}
/* client always identifies as root on windows */
#ifdef MINGW
snprintf(uname, sizeof(uname), "%s", "root");
#else
GetCurrentUserName(uname, sizeof(uname));
#endif
/* Some resolvers will not return FQNAME and missing PTR will give numerical result */
if ((strlen(VDOMAIN) > 0) && !IsIPV6Address(dnsname) && !strchr(dnsname,'.'))
{
Debug("Appending domain %s to %s\n",VDOMAIN,dnsname);
strcat(dnsname,".");
strncat(dnsname,VDOMAIN,CF_MAXVARSIZE/2);
}
if (strncmp(dnsname,localip,strlen(localip)) == 0)
{
/* Seems to be a bug in some resolvers that adds garbage, when it just returns the input */
strcpy(dnsname,localip);
}
if (strlen(dnsname) == 0)
{
strcpy(dnsname,localip);
}
snprintf(sendbuff,CF_BUFSIZE-1,"CAUTH %s %s %s %d",localip,dnsname,uname,CFSIGNATURE);
Debug("SENT:::%s\n",sendbuff);
SendTransaction(sd,sendbuff,0,CF_DONE);
return true;
}
/*********************************************************************/
int AuthenticateAgent(struct cfagent_connection *conn,struct Attributes attr,struct Promise *pp)
{ char sendbuffer[CF_EXPANDSIZE],in[CF_BUFSIZE],*out,*decrypted_cchall;
BIGNUM *nonce_challenge, *bn = NULL;
unsigned long err;
unsigned char digest[EVP_MAX_MD_SIZE];
int encrypted_len,nonce_len = 0,len,session_size;
char dont_implicitly_trust_server,enterprise_field = 'c';
RSA *server_pubkey = NULL;
if (PUBKEY == NULL || PRIVKEY == NULL)
{
CfOut(cf_error,"","No public/private key pair found\n");
return false;
}
enterprise_field = CfEnterpriseOptions();
session_size = CfSessionKeySize(enterprise_field);
/* Generate a random challenge to authenticate the server */
nonce_challenge = BN_new();
BN_rand(nonce_challenge,CF_NONCELEN,0,0);
nonce_len = BN_bn2mpi(nonce_challenge,in);
if (FIPS_MODE)
{
HashString(in,nonce_len,digest,CF_DEFAULT_DIGEST);
}
else
{
HashString(in,nonce_len,digest,cf_md5);
}
/* We assume that the server bound to the remote socket is the official one i.e. = root's */
if ((server_pubkey = HavePublicKeyByIP(conn->username,conn->remoteip)))
{
dont_implicitly_trust_server = 'y';
encrypted_len = RSA_size(server_pubkey);
}
else
{
dont_implicitly_trust_server = 'n'; /* have to trust server, since we can't verify id */
encrypted_len = nonce_len;
}
// Server pubkey is what we want to has as a unique ID
snprintf(sendbuffer,sizeof(sendbuffer),"SAUTH %c %d %d %c",dont_implicitly_trust_server,encrypted_len,nonce_len,enterprise_field);
if ((out = malloc(encrypted_len)) == NULL)
{
FatalError("memory failure");
}
if (server_pubkey != NULL)
{
if (RSA_public_encrypt(nonce_len,in,out,server_pubkey,RSA_PKCS1_PADDING) <= 0)
{
err = ERR_get_error();
cfPS(cf_error,CF_FAIL,"",pp,attr,"Public encryption failed = %s\n",ERR_reason_error_string(err));
free(out);
FreeRSAKey(server_pubkey);
return false;
}
memcpy(sendbuffer+CF_RSA_PROTO_OFFSET,out,encrypted_len);
}
else
{
memcpy(sendbuffer+CF_RSA_PROTO_OFFSET,in,nonce_len);
}
/* proposition C1 - Send challenge / nonce */
SendTransaction(conn->sd,sendbuffer,CF_RSA_PROTO_OFFSET+encrypted_len,CF_DONE);
BN_free(bn);
BN_free(nonce_challenge);
free(out);
if (DEBUG||D2)
{
RSA_print_fp(stdout,PUBKEY,0);
}
/*Send the public key - we don't know if server has it */
/* proposition C2 */
memset(sendbuffer,0,CF_EXPANDSIZE);
len = BN_bn2mpi(PUBKEY->n,sendbuffer);
SendTransaction(conn->sd,sendbuffer,len,CF_DONE); /* No need to encrypt the public key ... */
/* proposition C3 */
memset(sendbuffer,0,CF_EXPANDSIZE);
len = BN_bn2mpi(PUBKEY->e,sendbuffer);
SendTransaction(conn->sd,sendbuffer,len,CF_DONE);
/* check reply about public key - server can break connection here */
/* proposition S1 */
memset(in,0,CF_BUFSIZE);
if (ReceiveTransaction(conn->sd,in,NULL) == -1)
{
cfPS(cf_error,CF_INTERPT,"recv",pp,attr,"Protocol transaction broken off (1)");
FreeRSAKey(server_pubkey);
return false;
}
if (BadProtoReply(in))
{
CfOut(cf_error,"",in);
FreeRSAKey(server_pubkey);
return false;
}
/* Get challenge response - should be CF_DEFAULT_DIGEST of challenge */
/* proposition S2 */
memset(in,0,CF_BUFSIZE);
if (ReceiveTransaction(conn->sd,in,NULL) == -1)
{
cfPS(cf_error,CF_INTERPT,"recv",pp,attr,"Protocol transaction broken off (2)");
FreeRSAKey(server_pubkey);
return false;
}
if (HashesMatch(digest,in,CF_DEFAULT_DIGEST) || HashesMatch(digest,in,cf_md5)) // Legacy
{
if (dont_implicitly_trust_server == 'y') /* challenge reply was correct */
{
CfOut(cf_verbose,"",".....................[.h.a.i.l.].................................\n");
CfOut(cf_verbose,"","Strong authentication of server=%s connection confirmed\n",pp->this_server);
}
else
{
if (attr.copy.trustkey)
{
CfOut(cf_verbose,""," -> Trusting server identity, promise to accept key from %s=%s",pp->this_server,conn->remoteip);
}
else
{
CfOut(cf_error,""," !! Not authorized to trust the server=%s's public key (trustkey=false)\n",pp->this_server);
PromiseRef(cf_verbose,pp);
FreeRSAKey(server_pubkey);
return false;
}
}
}
else
{
cfPS(cf_error,CF_INTERPT,"",pp,attr,"Challenge response from server %s/%s was incorrect!",pp->this_server,conn->remoteip);
FreeRSAKey(server_pubkey);
return false;
}
/* Receive counter challenge from server */
Debug("Receive counter challenge from server\n");
/* proposition S3 */
memset(in,0,CF_BUFSIZE);
encrypted_len = ReceiveTransaction(conn->sd,in,NULL);
if (encrypted_len <= 0)
{
CfOut(cf_error,"","Protocol transaction sent illegal cipher length");
FreeRSAKey(server_pubkey);
return false;
}
if ((decrypted_cchall = malloc(encrypted_len)) == NULL)
{
FatalError("memory failure");
}
if (RSA_private_decrypt(encrypted_len,in,decrypted_cchall,PRIVKEY,RSA_PKCS1_PADDING) <= 0)
{
err = ERR_get_error();
cfPS(cf_error,CF_INTERPT,"",pp,attr,"Private decrypt failed = %s, abandoning\n",ERR_reason_error_string(err));
FreeRSAKey(server_pubkey);
return false;
}
/* proposition C4 */
if (FIPS_MODE)
{
HashString(decrypted_cchall,nonce_len,digest,CF_DEFAULT_DIGEST);
}
else
{
HashString(decrypted_cchall,nonce_len,digest,cf_md5);
}
Debug("Replying to counter challenge with hash\n");
if (FIPS_MODE)
{
SendTransaction(conn->sd,digest,CF_DEFAULT_DIGEST_LEN,CF_DONE);
}
else
{
SendTransaction(conn->sd,digest,CF_MD5_LEN,CF_DONE);
}
free(decrypted_cchall);
/* If we don't have the server's public key, it will be sent */
if (server_pubkey == NULL)
{
RSA *newkey = RSA_new();
CfOut(cf_verbose,""," -> Collecting public key from server!\n");
/* proposition S4 - conditional */
if ((len = ReceiveTransaction(conn->sd,in,NULL)) <= 0)
{
CfOut(cf_error,"","Protocol error in RSA authentation from IP %s\n",pp->this_server);
return false;
}
if ((newkey->n = BN_mpi2bn(in,len,NULL)) == NULL)
{
err = ERR_get_error();
cfPS(cf_error,CF_INTERPT,"",pp,attr,"Private key decrypt failed = %s\n",ERR_reason_error_string(err));
FreeRSAKey(newkey);
return false;
}
/* proposition S5 - conditional */
if ((len=ReceiveTransaction(conn->sd,in,NULL)) <= 0)
{
cfPS(cf_inform,CF_INTERPT,"",pp,attr,"Protocol error in RSA authentation from IP %s\n",pp->this_server);
FreeRSAKey(newkey);
return false;
}
if ((newkey->e = BN_mpi2bn(in,len,NULL)) == NULL)
{
err = ERR_get_error();
cfPS(cf_error,CF_INTERPT,"",pp,attr,"Public key decrypt failed = %s\n",ERR_reason_error_string(err));
FreeRSAKey(newkey);
return false;
}
server_pubkey = RSAPublicKey_dup(newkey);
FreeRSAKey(newkey);
}
/* proposition C5 */
SetSessionKey(conn);
if (conn->session_key == NULL)
{
CfOut(cf_error,"","A random session key could not be established");
FreeRSAKey(server_pubkey);
return false;
}
encrypted_len = RSA_size(server_pubkey);
Debug("Encrypt %d bytes of session key into %d RSA bytes\n",session_size,encrypted_len);
if ((out = malloc(encrypted_len)) == NULL)
{
FatalError("memory failure");
}
if (RSA_public_encrypt(session_size,conn->session_key,out,server_pubkey,RSA_PKCS1_PADDING) <= 0)
{
err = ERR_get_error();
cfPS(cf_error,CF_INTERPT,"",pp,attr,"Public encryption failed = %s\n",ERR_reason_error_string(err));
free(out);
FreeRSAKey(server_pubkey);
return false;
}
SendTransaction(conn->sd,out,encrypted_len,CF_DONE);
if (server_pubkey != NULL)
{
HashPubKey(server_pubkey,conn->digest,CF_DEFAULT_DIGEST);
CfOut(cf_verbose,""," -> Public key identity of host \"%s\" is \"%s\"",conn->remoteip,HashPrint(CF_DEFAULT_DIGEST,conn->digest));
SavePublicKey(conn->username,conn->remoteip,HashPrint(CF_DEFAULT_DIGEST,conn->digest),server_pubkey); // FIXME: username is local
LastSaw(conn->username,conn->remoteip,conn->digest,cf_connect);
}
free(out);
FreeRSAKey(server_pubkey);
return true;
}
/*********************************************************************/
static void FreeRSAKey(RSA *key)
/* Maybe not needed - RSA_free(NULL) seems to work, but who knows
* with older OpenSSL versions */
{
if(key == NULL)
{
return;
}
RSA_free(key);
}
/*********************************************************************/
static void CheckServerVersion(struct cfagent_connection *conn,struct Attributes attr, struct Promise *pp)
{ char sendbuffer[CF_BUFSIZE];
char recvbuffer[CF_BUFSIZE];
int tosend;
Debug("CheckRemoteVersion\n");
snprintf(sendbuffer,CF_BUFSIZE,"VERSION");
tosend = strlen(sendbuffer);
if (SendTransaction(conn->sd,sendbuffer,tosend,CF_DONE) == -1)
{
cfPS(cf_inform,CF_INTERPT,"send",pp,attr,"Transmission failed while checking version");
return;
}
if (ReceiveTransaction(conn->sd,recvbuffer,NULL) == -1)
{
cfPS(cf_inform,CF_INTERPT,"send",pp,attr,"Reply failed while checking version");
conn->protoversion = 0;
return;
}
if (BadProtoReply(recvbuffer))
{
conn->protoversion = 0;
return;
}
else
{
conn->protoversion = 1;
return;
}
}
/*********************************************************************/
/* Level */
/*********************************************************************/
static void SetSessionKey(struct cfagent_connection *conn)
{ BIGNUM *bp;
int session_size = CfSessionKeySize(conn->encryption_type);
bp = BN_new();
if(bp == NULL)
{
FatalError("Could not allocate session key");
}
// session_size is in bytes
if(!BN_rand(bp,session_size*8,-1,0))
{
FatalError("Can't generate cryptographic key");
}
//BN_print_fp(stdout,bp);
conn->session_key = (unsigned char *)bp->d;
}
/*********************************************************************/
int BadProtoReply(char *buf)
{
Debug("Protoreply: (%s)\n",buf);
return (strncmp(buf,"BAD:",4) == 0);
}
/*********************************************************************/
int OKProtoReply(char *buf)
{
return(strncmp(buf,"OK:",3) == 0);
}
/*********************************************************************/
int FailedProtoReply(char *buf)
{
return(strncmp(buf,CF_FAILEDSTR,strlen(CF_FAILEDSTR)) == 0);
}
cfengine-3.2.4/src/granules.c 0000644 0001750 0001750 00000011163 11715232734 013001 0000000 0000000 /*
Copyright (C) Cfengine AS
This file is part of Cfengine 3 - written and maintained by Cfengine 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 Commerical Open Source License
(COSL) may apply to this file if you as a licensee so wish it. See
included file COSL.txt.
*/
/*****************************************************************************/
/* */
/* File: granules.c */
/* */
/*****************************************************************************/
#include "cf3.defs.h"
#include "cf3.extern.h"
#include
static char *PrintTimeSlot(int slot);
/*****************************************************************************/
char *ConvTimeKey(char *str)
{ int i;
char buf1[10],buf2[10],buf3[10],buf4[10],buf5[10],buf[10],out[10];
static char timekey[64];
sscanf(str,"%s %s %s %s %s",buf1,buf2,buf3,buf4,buf5);
timekey[0] = '\0';
/* Day */
sprintf(timekey,"%s:",buf1);
/* Hours */
sscanf(buf4,"%[^:]",buf);
sprintf(out,"Hr%s",buf);
strcat(timekey,out);
/* Minutes */
sscanf(buf4,"%*[^:]:%[^:]",buf);
sprintf(out,"Min%s",buf);
strcat(timekey,":");
sscanf(buf,"%d",&i);
switch ((i / 5))
{
case 0: strcat(timekey,"Min00_05");
break;
case 1: strcat(timekey,"Min05_10");
break;
case 2: strcat(timekey,"Min10_15");
break;
case 3: strcat(timekey,"Min15_20");
break;
case 4: strcat(timekey,"Min20_25");
break;
case 5: strcat(timekey,"Min25_30");
break;
case 6: strcat(timekey,"Min30_35");
break;
case 7: strcat(timekey,"Min35_40");
break;
case 8: strcat(timekey,"Min40_45");
break;
case 9: strcat(timekey,"Min45_50");
break;
case 10: strcat(timekey,"Min50_55");
break;
case 11: strcat(timekey,"Min55_00");
break;
}
return timekey;
}
/*****************************************************************************/
char *GenTimeKey(time_t now)
{ static char str[64];
char timebuf[26];
snprintf(str,sizeof(str),"%s",cf_strtimestamp_utc(now,timebuf));
return ConvTimeKey(str);
}
/*****************************************************************************/
int GetTimeSlot(time_t here_and_now)
{ time_t now;
int slot = 0;
char timekey[CF_MAXVARSIZE];
strcpy(timekey,GenTimeKey(here_and_now));
for (now = CF_MONDAY_MORNING; now < CF_MONDAY_MORNING+CF_WEEK; now += CF_MEASURE_INTERVAL,slot++)
{
if (strcmp(timekey,GenTimeKey(now)) == 0)
{
return slot;
}
}
return -1;
}
/*****************************************************************************/
static char *PrintTimeSlot(int slot)
{ time_t now,i;
for (now = CF_MONDAY_MORNING, i = 0; now < CF_MONDAY_MORNING+CF_WEEK; now += CF_MEASURE_INTERVAL,i++)
{
if (i == slot)
{
return GenTimeKey(now);
}
}
return "UNKNOWN";
}
/*****************************************************************************/
int GetShiftSlot(time_t here_and_now)
{ time_t now = time(NULL);
int slot = 0, chour = -1;
char cstr[64];
char str[64];
char buf[10],cbuf[10];
int hour = -1;
char timebuf[26];
snprintf(cstr,sizeof(str),"%s",cf_strtimestamp_utc(here_and_now,timebuf));
sscanf(cstr,"%s %*s %*s %d",cbuf,&chour);
// Format Tue Sep 28 14:58:27 CEST 2010
for (now = CF_MONDAY_MORNING; now < CF_MONDAY_MORNING+CF_WEEK; now += CF_SHIFT_INTERVAL,slot++)
{
snprintf(str,sizeof(str),"%s",cf_strtimestamp_utc(now,timebuf));
sscanf(str,"%s %*s %*s %d",buf,&hour);
if ((hour/6 == chour/6) && (strcmp(cbuf,buf) == 0))
{
return slot;
}
}
return -1;
}
/*****************************************************************************/
time_t GetShiftSlotStart(time_t t)
{
return (t - (t % SECONDS_PER_SHIFT));
}
cfengine-3.2.4/src/verify_methods.c 0000644 0001750 0001750 00000007422 11715232734 014213 0000000 0000000 /*
Copyright (C) Cfengine AS
This file is part of Cfengine 3 - written and maintained by Cfengine 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 Commerical Open Source License
(COSL) may apply to this file if you as a licensee so wish it. See
included file COSL.txt.
*/
/*****************************************************************************/
/* */
/* File: verify_methods.c */
/* */
/*****************************************************************************/
#include "cf3.defs.h"
#include "cf3.extern.h"
/*****************************************************************************/
void VerifyMethodsPromise(struct Promise *pp)
{ struct Attributes a = {{0}};
a = GetMethodAttributes(pp);
VerifyMethod(a,pp);
DeleteScalar("this","promiser");
}
/*****************************************************************************/
int VerifyMethod(struct Attributes a,struct Promise *pp)
{ struct Bundle *bp;
void *vp;
struct FnCall *fp;
char method_name[CF_EXPANDSIZE];
struct Rlist *params = NULL;
int retval = false;
struct CfLock thislock;
char lockname[CF_BUFSIZE];
if (a.havebundle)
{
if ((vp = GetConstraint("usebundle",pp,CF_FNCALL)))
{
fp = (struct FnCall *)vp;
ExpandScalar(fp->name,method_name);
params = fp->args;
}
else if ((vp = GetConstraint("usebundle",pp,CF_SCALAR)))
{
ExpandScalar((char *)vp,method_name);
params = NULL;
}
else
{
return false;
}
}
GetLockName(lockname,"method",pp->promiser,params);
thislock = AcquireLock(lockname,VUQNAME,CFSTARTTIME,a,pp,false);
if (thislock.lock == NULL)
{
return false;
}
PromiseBanner(pp);
if ((bp = GetBundle(method_name,"agent")))
{
char *bp_stack = THIS_BUNDLE;
BannerSubBundle(bp,params);
DeleteScope(bp->name);
NewScope(bp->name);
HashVariables(bp->name);
AugmentScope(bp->name,bp->args,params);
THIS_BUNDLE = bp->name;
PushPrivateClassContext();
retval = ScheduleAgentOperations(bp);
PopPrivateClassContext();
THIS_BUNDLE = bp_stack;
if (retval)
{
cfPS(cf_verbose,CF_NOP,"",pp,a," -> Method invoked successfully\n");
}
else
{
cfPS(cf_inform,CF_FAIL,"",pp,a," !! Method could not be invoked successfully\n");
}
DeleteFromScope(bp->name,bp->args);
}
else
{
if (IsCf3VarString(method_name))
{
CfOut(cf_error,""," !! A variable seems to have been used for the name of the method. In this case, the promiser also needs to contain the uique name of the method");
}
if (bp && bp->name)
{
cfPS(cf_error,CF_FAIL,"",pp,a," !! Method \"%s\" was used but was not defined!\n",bp->name);
}
else
{
cfPS(cf_error,CF_FAIL,"",pp,a," !! A method attempted to use a bundle \"%s\" that was apparently not defined!\n",method_name);
}
}
YieldCurrentLock(thislock);
return retval;
}
cfengine-3.2.4/src/cf3.defs.h 0000644 0001750 0001750 00000130750 11715232734 012565 0000000 0000000 /*
Copyright (C) Cfengine AS
This file is part of Cfengine 3 - written and maintained by Cfengine 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 Commerical Open Source License
(COSL) may apply to this file if you as a licensee so wish it. See
included file COSL.txt.
*/
/*****************************************************************************/
/* */
/* File: cf3.defs.h */
/* */
/*****************************************************************************/
#ifndef CFENGINE_CF3_DEFS_H
#define CFENGINE_CF3_DEFS_H
/* These files are hard links to the cfengine 2 sources */
#include "cf.defs.h"
#include "cf.extern.h"
#undef VERSION
#undef Verbose
#include "conf.h"
#ifndef NGROUPS
# define NGROUPS 20
#endif
/*************************************************************************/
/* Fundamental (meta) types */
/*************************************************************************/
#define CF3COPYRIGHT "Copyright (C) CFEngine AS 2008,2010-"
#define CF_SCALAR 's'
#define CF_LIST 'l'
#define CF_FNCALL 'f'
#define CF_STACK 'k'
#define CF_NOPROMISEE 'X'
#define CF_UNDEFINED -1
#define CF_NODOUBLE -123.45
#define CF_NOINT -678L
#define CF_ANYUSER (uid_t)-1
#define CF_ANYGROUP (gid_t)-1
#define CF_UNDEFINED_ITEM (void *)0x1234
#define CF_VARARGS 99
#define CF_UNKNOWN_IP "location unknown"
#define CF_INBODY 1
#define CF_INBUNDLE 2
#define CF_MAX_NESTING 10
#define CF_MAX_REPLACE 20
#define CF_DONEPASSES 4
#define CF_TIME_SIZE 32
#define CF_FIPS_SIZE 32
#define CFPULSETIME 60
/*************************************************************************/
/** Design criteria */
/*************************************************************************/
#define CF_DUNBAR_INTIMATE 6
#define CF_DUNBAR_WORK 30
#define CF_DUNBAR_KNOW 120
/*************************************************************************/
/* Parsing and syntax tree structures */
/*************************************************************************/
#define CF_DEFINECLASSES "classes"
#define CF_TRANSACTION "action"
#define CF3_MODULES 15 /* This value needs to be incremented when adding modules */
/*************************************************************************/
struct PromiseParser
{
char *block; /* body/bundle */
char blocktype[CF_MAXVARSIZE];
char blockid[CF_MAXVARSIZE];
char filename[CF_MAXVARSIZE];
int line_pos;
int line_no;
int arg_nesting;
int list_nesting;
char lval[CF_MAXVARSIZE];
void *rval;
char rtype;
int isbody;
char *promiser;
void *promisee;
char currentid[CF_MAXVARSIZE];
char currenttype[CF_MAXVARSIZE];
char *currentstring;
char *currentclasses;
struct Bundle *currentbundle;
struct Body *currentbody;
struct Promise *currentpromise;
struct SubType *currentstype;
struct Rlist *useargs;
struct RList *currentRlist;
char *currentfnid[CF_MAX_NESTING];
struct Rlist *giveargs[CF_MAX_NESTING];
struct FnCall *currentfncall[CF_MAX_NESTING];
};
/*************************************************************************/
/* Abstract datatypes */
/*************************************************************************/
enum cfdatatype
{
cf_str,
cf_int,
cf_real,
cf_slist,
cf_ilist,
cf_rlist,
cf_opts,
cf_olist,
cf_body,
cf_bundle,
cf_class,
cf_clist,
cf_irange,
cf_rrange,
cf_counter,
cf_notype
};
enum cfx_formatindex
{
cfb,
cfe,
};
enum cfx_format
{
cfx_head,
cfx_bundle,
cfx_block,
cfx_blockheader,
cfx_blockid,
cfx_blocktype,
cfx_args,
cfx_promise,
cfx_class,
cfx_subtype,
cfx_object,
cfx_lval,
cfx_rval,
cfx_qstring,
cfx_rlist,
cfx_function,
cfx_line,
};
/*************************************************************************/
#define CF_COMMONC "common"
#define CF_AGENTC "agent"
#define CF_SERVERC "server"
#define CF_MONITORC "monitor"
#define CF_EXECC "executor"
#define CF_KNOWC "knowledge"
#define CF_RUNC "runagent"
#define CF_REPORTC "reporter"
#define CF_KEYGEN "keygenerator"
#define CF_HUBC "hub"
enum cfagenttype
{
cf_common,
cf_agent,
cf_server,
cf_monitor,
cf_executor,
cf_runagent,
cf_know,
cf_report,
cf_keygen,
cf_hub,
cf_noagent
};
/*************************************************************************/
enum cfgcontrol
{
cfg_bundlesequence,
cfg_goalcategories,
cfg_goalpatterns,
cfg_ignore_missing_bundles,
cfg_ignore_missing_inputs,
cfg_inputs,
cfg_version,
cfg_lastseenexpireafter,
cfg_output_prefix,
cfg_domain,
cfg_require_comments,
cfg_licenses,
cfg_site_classes,
cfg_syslog_host,
cfg_syslog_port,
cfg_fips_mode,
cfg_noagent
};
/*************************************************************************/
enum cfacontrol
{
cfa_abortclasses,
cfa_abortbundleclasses,
cfa_addclasses,
cfa_agentaccess,
cfa_agentfacility,
cfa_alwaysvalidate,
cfa_auditing,
cfa_binarypaddingchar,
cfa_bindtointerface,
cfa_hashupdates,
cfa_childlibpath,
cfa_checksum_alert_time,
cfa_defaultcopytype,
cfa_dryrun,
cfa_editbinaryfilesize,
cfa_editfilesize,
cfa_environment,
cfa_exclamation,
cfa_expireafter,
cfa_fsinglecopy,
cfa_fautodefine,
cfa_hostnamekeys,
cfa_ifelapsed,
cfa_inform,
cfa_intermittency,
cfa_max_children,
cfa_maxconnections,
cfa_mountfilesystems,
cfa_nonalphanumfiles,
cfa_repchar,
cfa_refresh_processes,
cfa_repository,
cfa_secureinput,
cfa_sensiblecount,
cfa_sensiblesize,
cfa_skipidentify,
cfa_suspiciousnames,
cfa_syslog,
cfa_track_value,
cfa_timezone,
cfa_timeout,
cfa_verbose,
cfa_notype,
};
/*************************************************************************/
enum cfexcontrol
{
cfex_splaytime,
cfex_mailfrom,
cfex_mailto,
cfex_smtpserver,
cfex_mailmaxlines,
cfex_schedule,
cfex_executorfacility,
cfex_execcommand,
cfex_notype,
};
/*************************************************************************/
enum cfmcontrol
{
cfm_forgetrate,
cfm_monitorfacility,
cfm_histograms,
cfm_tcpdump,
cfm_notype,
};
/*************************************************************************/
enum cfrcontrol
{
cfr_hosts,
cfr_portnumber,
cfr_force_ipv4,
cfr_trustkey,
cfr_encrypt,
cfr_background,
cfr_maxchild,
cfr_output_to_file,
cfr_output_directory,
cfr_timeout,
cfr_notype
};
/*************************************************************************/
enum cfscontrol
{
cfs_allowallconnects,
cfs_allowconnects,
cfs_allowusers,
cfs_auditing,
cfs_bindtointerface,
cfs_cfruncommand,
cfs_denybadclocks,
cfs_denyconnects,
cfs_dynamicaddresses,
cfs_hostnamekeys,
cfs_keyttl,
cfs_logallconnections,
cfs_logencryptedtransfers,
cfs_maxconnections,
cfs_portnumber,
cfs_serverfacility,
cfs_skipverify,
cfs_trustkeysfrom,
cfs_notype,
};
/*************************************************************************/
enum cfkcontrol
{
cfk_builddir,
cfk_docroot,
cfk_genman,
cfk_graph_dir,
cfk_graph_output,
cfk_htmlbanner,
cfk_htmlfooter,
cfk_tm_prefix,
cfk_mandir,
cfk_query_engine,
cfk_query_output,
cfk_sql_type,
cfk_sql_database,
cfk_sql_owner,
cfk_sql_passwd,
cfk_sql_server,
cfk_sql_connect_db,
cfk_stylesheet,
cfk_views,
cfk_view_projection,
cfk_notype
};
/*************************************************************************/
enum cfrecontrol
{
cfre_aggregation_point,
cfre_autoscale,
cfre_builddir,
cfre_csv,
cfre_errorbars,
cfre_htmlbanner,
cfre_html_embed,
cfre_htmlfooter,
cfre_query_engine,
cfre_reports,
cfre_report_output,
cfre_stylesheet,
cfre_timestamps,
cfre_notype
};
/*************************************************************************/
enum cfhcontrol
{
cfh_export_zenoss,
cfh_federation,
cfh_exclude_hosts,
cfh_schedule,
cfh_port,
cfh_notype
};
/*************************************************************************/
enum cfsbundle
{
cfs_access,
cfs_nobtype
};
enum cfsrole
{
cfs_authorize,
cfs_nortype
};
enum cfspromises
{
cfs_admit,
cfs_deny,
cfs_maproot,
cfs_encrypted,
cfs_noptype
};
enum cfreport
{
cf_inform,
cf_verbose,
cf_error,
cf_log,
cf_reporting,
cf_cmdout,
cf_noreport
};
enum cfeditorder
{
cfe_before,
cfe_after
};
/*************************************************************************/
/* Syntax module range/pattern constants for type validation */
/*************************************************************************/
#define CF_BUNDLE (void*)1234 /* any non-null value, not used */
#define CF_HIGHINIT 99999L
#define CF_LOWINIT -999999L
#define CF_SIGNALRANGE "hup,int,trap,kill,pipe,cont,abrt,stop,quit,term,child,usr1,usr2,bus,segv"
#define CF_BOOL "true,false,yes,no,on,off"
#define CF_LINKRANGE "symlink,hardlink,relative,absolute"
#define CF_TIMERANGE "0,2147483647"
#define CF_VALRANGE "0,99999999999"
#define CF_INTRANGE "-99999999999,9999999999"
#define CF_INTLISTRANGE "[-0-9_$(){}\\[\\].]+"
#define CF_REALRANGE "-9.99999E100,9.99999E100"
#define CF_CHARRANGE "^.$"
#define CF_NULL_VALUE "cf_null"
#define CF_MODERANGE "[0-7augorwxst,+-]+"
#define CF_BSDFLAGRANGE "[+-]*[(arch|archived|nodump|opaque|sappnd|sappend|schg|schange|simmutable|sunlnk|sunlink|uappnd|uappend|uchg|uchange|uimmutable|uunlnk|uunlink)]+"
#define CF_CLASSRANGE "[a-zA-Z0-9_!&@@$|.()\\[\\]{}]+"
#define CF_IDRANGE "[a-zA-Z0-9_$(){}\\[\\].]+"
#define CF_USERRANGE "[a-zA-Z0-9_$.-]+"
#define CF_IPRANGE "[a-zA-Z0-9_$(){}.:-]+"
#define CF_FNCALLRANGE "[a-zA-Z0-9_(){}.$@]+"
#define CF_NAKEDLRANGE "@[(][a-zA-Z0-9]+[)]"
#define CF_ANYSTRING ".*"
#ifndef MINGW
#define CF_ABSPATHRANGE "\042?(/.*)"
#else
// can start with e.g. c:\... or "c:\... | unix (for Cygwin-style paths)
#define CF_ABSPATHRANGE "\042?(([a-zA-Z]:\\\\.*)|(/.*))"
#endif
/* Any non-empty string can be an absolute path under Unix */
#define CF_PATHRANGE ".+"
#define CF_LOGRANGE "stdout|udp_syslog|(\042?[a-zA-Z]:\\\\.*)|(/.*)"
#define CF_FACILITY "LOG_USER,LOG_DAEMON,LOG_LOCAL0,LOG_LOCAL1,LOG_LOCAL2,LOG_LOCAL3,LOG_LOCAL4,LOG_LOCAL5,LOG_LOCAL6,LOG_LOCAL7"
// Put this here now for caching efficiency
#define SOFTWARE_PACKAGES_CACHE "software_packages.csv"
/***************************************************************************/
/* Knowledge relationships */
/***************************************************************************/
enum storytype
{
cfi_cause,
cfi_connect,
cfi_part,
cfi_access,
cfi_none
};
#define KM_AFFECTS_CERT_F "affects"
#define KM_AFFECTS_CERT_B "is affected by"
#define KM_CAUSE_CERT_F "causes"
#define KM_CAUSE_CERT_B "is caused by"
#define KM_PARTOF_CERT_F "is/are a part of"
#define KM_PARTOF_CERT_B "has/have a part"
#define KM_DETERMINES_CERT_F "determine(s)"
#define KM_DETERMINES_CERT_B "is/are determined by"
#define KM_CONTRIBUTES_CERT_F "contibutes to"
#define KM_CONTRIBUTES_CERT_B "is contibuted to by"
#define KM_USES_CERT_F "use(s)"
#define KM_USES_CERT_B "is/are used by"
#define KM_PROVIDES_CERT_F "provide(s)"
#define KM_PROVIDES_CERT_B "is/are provided by"
#define KM_BELONGS_CERT_F "belongs to"
#define KM_BELONGS_CERT_B "owns"
#define KM_CONNECTS_CERT_F "connects to"
#define KM_CONNECTS_CERT_B "connects to"
#define KM_NEEDS_CERT_F "need(s)"
#define KM_NEEDS_CERT_B "is needed by"
#define KM_EQUIV_CERT_F "is equivalent to"
#define KM_EQUIV_CERT_B "is equivalent to"
#define KM_SHIELD_CERT_F "denies access from"
#define KM_SHIELD_CERT_B "is not allowed access to"
#define KM_ACCESS_CERT_F "grants access to"
#define KM_ACCESS_CERT_B "is allowed to access"
#define KM_MONITOR_CERT_F "monitor(s)"
#define KM_MONITOR_CERT_B "is/are monitored by"
#define KM_LOCATED_CERT_F "is located in"
#define KM_LOCATED_CERT_B "situates"
#define KM_REPAIR_CERT_F "repairs"
#define KM_REPAIR_CERT_B "is repaired by"
#define KM_CAUSE_POSS_F "can cause"
#define KM_CAUSE_POSS_B "can be caused by"
#define KM_PARTOF_POSS_F "can be a part of"
#define KM_PARTOF_POSS_B "can have a part"
#define KM_DETERMINES_POSS_F "can determine"
#define KM_DETERMINES_POSS_B "can be determined by"
#define KM_CONTRIBUTES_POSS_F "can contibute to"
#define KM_CONTRIBUTES_POSS_B "can be contibuted to by"
#define KM_USES_POSS_F "can use"
#define KM_USES_POSS_B "can be used by"
#define KM_PROVIDES_POSS_F "can provide"
#define KM_PROVIDES_POSS_B "can be provided by"
#define KM_BELONGS_POSS_F "can belong to"
#define KM_BELONGS_POSS_B "can own"
#define KM_AFFECTS_POSS_F "can affect"
#define KM_AFFECTS_POSS_B "can be affected by"
#define KM_CONNECTS_POSS_F "can connect to"
#define KM_CONNECTS_POSS_B "can connect to"
#define KM_NEEDS_POSS_F "can need"
#define KM_NEEDS_POSS_B "can be needed by"
#define KM_EQUIV_POSS_F "can be equivalent to"
#define KM_EQUIV_POSS_B "can be equivalent to"
#define KM_MONITOR_POSS_F "can monitor"
#define KM_MONITOR_POSS_B "can be monitored by"
#define KM_ACCESS_POSS_F "can access to"
#define KM_ACCESS_POSS_B "can be allowed to access"
#define KM_LOCATED_POSS_F "can be located in"
#define KM_LOCATED_POSS_B "can situate"
#define KM_REPAIR_POSS_F "can repair"
#define KM_REPAIR_POSS_B "can be repaired by"
#define KM_CAUSE_UNCERT_F "might cause"
#define KM_CAUSE_UNCERT_B "might be caused by"
#define KM_PARTOF_UNCERT_F "might be a part of"
#define KM_PARTOF_UNCERT_B "might have a part"
#define KM_DETERMINES_UNCERT_F "might determine"
#define KM_DETERMINES_UNCERT_B "might be determined by"
#define KM_CONTRIBUTES_UNCERT_F "might contibute to"
#define KM_CONTRIBUTES_UNCERT_B "might be contibuted to by"
#define KM_USES_UNCERT_F "might use"
#define KM_USES_UNCERT_B "might be used by"
#define KM_PROVIDES_UNCERT_F "might provide"
#define KM_PROVIDES_UNCERT_B "might be provided by"
#define KM_BELONGS_UNCERT_F "might belong to"
#define KM_BELONGS_UNCERT_B "might own"
#define KM_AFFECTS_UNCERT_F "might affect"
#define KM_AFFECTS_UNCERT_B "might be affected by"
#define KM_CONNECTS_UNCERT_F "might connect to"
#define KM_CONNECTS_UNCERT_B "might connect to"
#define KM_NEEDS_UNCERT_F "might need"
#define KM_NEEDS_UNCERT_B "might be needed by"
#define KM_EQUIV_UNCERT_F "might be equivalent to"
#define KM_EQUIV_UNCERT_B "might be equivalent to"
#define KM_SHIELD_UNCERT_F "might deny access from"
#define KM_SHIELD_UNCERT_B "might not be allowed access to"
#define KM_MONITOR_UNCERT_F "might monitor"
#define KM_MONITOR_UNCERT_B "might be monitored by"
#define KM_ACCESS_UNCERT_F "might grant access to"
#define KM_ACCESS_UNCERT_B "might be allowed to access"
#define KM_LOCATED_UNCERT_F "might be located in"
#define KM_LOCATED_UNCERT_B "might situate"
#define KM_REPAIR_UNCERT_F "might repair"
#define KM_REPAIR_UNCERT_B "might be repaired by"
#define KM_GENERALIZES_F "is a generalization of"
#define KM_GENERALIZES_B "is a special case of"
#define KM_SYNONYM "is a synonym for"
enum knowledgecertainty
{
cfk_certain,
cfk_uncertain,
cfk_possible
};
/*************************************************************************/
struct BodySyntax
{
char *lval;
enum cfdatatype dtype;
void *range; /* either char or struct BodySyntax **/
char *description;
};
struct BodyDefault
{
char *lval;
char *rval;
};
/*************************************************************************/
struct SubTypeSyntax
{
char *btype;
char *subtype;
struct BodySyntax *bs;
};
/*************************************************************************/
struct FnCall;
typedef struct FnCallType
{
char *name;
enum cfdatatype dtype;
int numargs;
struct FnCallArg *args;
struct Rval (*impl)(struct FnCall *, struct Rlist *);
char *description;
} FnCallType;
struct FnCallArg
{
char *pattern;
enum cfdatatype dtype;
char *description;
};
/*************************************************************************/
#define UNKNOWN_FUNCTION -1
/*************************************************************************/
struct Bundle
{
char *type;
char *name;
struct Rlist *args;
struct SubType *subtypes;
struct Bundle *next;
};
/*************************************************************************/
struct Body
{
char *type;
char *name;
struct Rlist *args;
struct Constraint *conlist;
struct Body *next;
};
/*************************************************************************/
struct SubType
{
char *name;
struct Promise *promiselist;
struct SubType *next;
};
/*************************************************************************/
struct edit_context
{
char *filename;
struct Item *file_start;
struct Item *file_classes;
int num_edits;
int empty_first;
};
/*************************************************************************/
struct Promise
{
char *classes;
char *ref; /* comment */
char ref_alloc;
char *promiser;
void *promisee; /* Can be a general rval */
char petype; /* rtype of promisee - list or scalar recipient? */
int lineno;
char *bundle;
struct Audit *audit;
struct Constraint *conlist;
struct Promise *next;
/* Runtime bus for private flags and work space */
char *agentsubtype; /* cache the promise subtype */
char *bundletype; /* cache the agent type */
int done; /* this needs to be preserved across runs */
int *donep; /* used by locks to mark as done */
int makeholes;
char *this_server;
struct cfstat *cache;
struct cfagent_connection *conn;
struct CompressedArray *inode_cache;
struct edit_context *edcontext;
dev_t rootdevice; /* for caching during work*/
};
/*************************************************************************/
struct PromiseIdent
{
char *handle;
char *filename;
char *classes;
int lineno;
struct PromiseIdent *next;
};
/*************************************************************************/
struct Constraint
{
char *lval;
void *rval; /* should point to either string, Rlist or FnCall */
char type; /* scalar, list, or function */
char *classes; /* only used within bodies */
int lineno;
int isbody;
struct Audit *audit;
struct Constraint *next;
};
/*************************************************************************/
/* Rvalues and lists - basic workhorse structure */
/*************************************************************************/
/*
In an OO language one would probably think of Rval as a parent class
and CF_SCALAR, CF_LIST and CF_FNCALL as children. There is more or
less a sub-type polymorphism going on in the code around these structures,
but it is not a proper inheritance relationship as lists could
contain functions which return lists or scalars etc..
*/
/*************************************************************************/
struct Rval
{
void *item; /* (char *), (struct Rlist *), or (struct FnCall) */
char rtype; /* Points to CF_SCALAR, CF_LIST, CF_FNCALL usually */
};
/*************************************************************************/
struct Rlist
{
void *item;
char type;
struct Rlist *state_ptr; /* Points to "current" state/element of sub-list */
struct Rlist *next;
};
/*************************************************************************/
struct FnCall
{
char *name;
struct Rlist *args;
int argc;
};
/*******************************************************************/
/* Variable processing */
/*******************************************************************/
struct Scope /* $(bundlevar) $(scope.name) */
{
char *scope; /* Name of scope */
struct CfAssoc *hashtable[CF_HASHTABLESIZE]; /* Variable heap */
struct Scope *next;
};
/*******************************************************************/
typedef struct CfAssoc /* variable reference linkage , with metatype*/
{
char *lval;
void *rval;
char rtype;
enum cfdatatype dtype;
} CfAssoc;
/*******************************************************************/
/*
* Disposable iterator over hash table. Does not require deinitialization.
*/
typedef struct HashIterator
{
CfAssoc **hash;
int bucket;
} HashIterator;
/*******************************************************************/
/* Return value signalling */
/*******************************************************************/
#define FNCALL_NOP -1
#define FNCALL_SUCCESS 0
#define FNCALL_FAILURE 1
#define FNCALL_ALERT 2
struct FnCallStatus /* from builtin functions */
{
int status;
char message[CF_BUFSIZE];
char fncall_classes[CF_BUFSIZE]; /* set by functions in the form fncall_CLASS */
};
/*******************************************************************/
/* Return value signalling */
/*******************************************************************/
enum cfinterval
{
cfa_hourly,
cfa_daily,
cfa_nointerval
};
enum cfdatetemplate
{
cfa_year,
cfa_month,
cfa_day,
cfa_hour,
cfa_min,
cfa_sec
};
enum cfcomparison
{
cfa_atime,
cfa_mtime,
cfa_ctime,
cfa_checksum,
cfa_hash,
cfa_binary,
cfa_exists,
cfa_nocomparison
};
enum cflinktype
{
cfa_symlink,
cfa_hardlink,
cfa_relative,
cfa_absolute,
cfa_notlinked
};
enum cfopaction
{
cfa_fix,
cfa_warn,
};
enum cfbackupoptions
{
cfa_backup,
cfa_nobackup,
cfa_timestamp,
cfa_repos_store/* for internal use only */
};
enum cftidylinks
{
cfa_linkdelete,
cfa_linkkeep
};
enum cfhashes
{
cf_md5,
cf_sha224,
cf_sha256,
cf_sha384,
cf_sha512,
cf_sha1,
cf_sha,
cf_besthash,
cf_crypt,
cf_nohash
};
enum cfnofile
{
cfa_force,
cfa_delete,
cfa_skip
};
enum cflinkchildren
{
cfa_override,
cfa_onlynonexisting
};
enum cfchanges
{
cfa_noreport,
cfa_contentchange,
cfa_statschange,
cfa_allchanges
};
enum signalnames
{
cfa_hup,
cfa_int,
cfa_trap,
cfa_kill,
cfa_pipe,
cfa_cont,
cfa_abrt,
cfa_stop,
cfa_quit,
cfa_term,
cfa_child,
cfa_usr1,
cfa_usr2,
cfa_bus,
cfa_segv
};
enum representations
{
cfk_url,
cfk_web,
cfk_file,
cfk_db,
cfk_literal,
cfk_image,
cfk_portal,
cfk_none
};
enum package_actions
{
cfa_addpack,
cfa_deletepack,
cfa_reinstall,
cfa_update,
cfa_addupdate,
cfa_patch,
cfa_verifypack,
cfa_pa_none
};
enum version_cmp
{
cfa_eq,
cfa_neq,
cfa_gt,
cfa_lt,
cfa_ge,
cfa_le,
cfa_cmp_none
};
enum action_policy
{
cfa_individual,
cfa_bulk,
cfa_no_ppolicy
};
enum cf_thread_mutex
/* Adding:
*) Add enum here
*) Add mutex in cf3globals.c and cf.extern.h
*) Add enum -> mutex in NameToThreadMutex() */
{
cft_system,
cft_count,
cft_getaddr,
cft_lock,
cft_output,
cft_dbhandle,
cft_policy, // protects structs for refreshing policy files
cft_db_lastseen, // lastseen dbs (in cf-serverd)
cft_no_tpolicy,
cft_report,
cft_vscope, // protects VSCOPE
cft_server_keyseen, // protects SERVER_KEYSEEN
cft_server_children,
};
enum cf_status
{
cfn_repaired,
cfn_notkept,
cfn_kept,
cfn_nop
};
/************************************************************************************/
enum cf_acl_method
{
cfacl_append,
cfacl_overwrite,
cfacl_nomethod
};
enum cf_acl_type
{
cfacl_generic,
cfacl_posix,
cfacl_ntfs,
cfacl_notype
};
enum cf_acl_inherit
{
cfacl_nochange,
cfacl_specify,
cfacl_parent,
cfacl_clear,
cfacl_noinherit,
};
struct CfACL
{
enum cf_acl_method acl_method;
enum cf_acl_type acl_type;
enum cf_acl_inherit acl_directory_inherit;
struct Rlist *acl_entries;
struct Rlist *acl_inherit_entries;
};
typedef enum
{
INHERIT_ACCESS_ONLY,
INHERIT_DEFAULT_ONLY,
INHERIT_ACCESS_AND_DEFAULT
}
inherit_t;
enum insert_match
{
cf_ignore_leading,
cf_ignore_trailing,
cf_ignore_embedded,
cf_exact_match
};
enum monitord_rep
{
mon_rep_mag,
mon_rep_week,
mon_rep_yr
};
enum software_rep
{
sw_rep_installed,
sw_rep_patch_avail,
sw_rep_patch_installed
};
enum promiselog_rep
{
plog_repaired,
plog_notkept
};
enum time_window
{
time_hour,
time_day,
time_week
};
/*************************************************************************/
enum cfd_menu
{
cfd_menu_delta,
cfd_menu_full,
cfd_menu_relay,
cfd_menu_error
};
/*************************************************************************/
/* Runtime constraint structures */
/*************************************************************************/
#define OVECCOUNT 30
/*******************************************************************/
struct CfKeyBinding
{
char *name;
RSA *key;
char *address;
time_t timestamp;
};
/*************************************************************************/
struct CfKeyHostSeen
{
char address[CF_ADDRSIZE];
struct QPoint Q;
};
/*************************************************************************/
struct CfLock
{
char *last;
char *lock;
char *log;
};
/*************************************************************************/
struct CfMount
{
char *host;
char *source;
char *mounton;
char *options;
int unmount;
};
/*************************************************************************/
struct Recursion
{
int travlinks;
int rmdeadlinks;
int depth;
int xdev;
int include_basedir;
struct Rlist *include_dirs;
struct Rlist *exclude_dirs;
};
/*************************************************************************/
struct TransactionContext
{
enum cfopaction action;
int ifelapsed;
int expireafter;
int background;
char *log_string;
char *log_kept;
char *log_repaired;
char *log_failed;
int log_priority;
char *measure_id;
double value_kept;
double value_notkept;
double value_repaired;
int audit;
enum cfreport report_level;
enum cfreport log_level;
};
/*************************************************************************/
struct DefineClasses
{
struct Rlist *change;
struct Rlist *failure;
struct Rlist *denied;
struct Rlist *timeout;
struct Rlist *kept;
struct Rlist *interrupt;
int persist;
enum statepolicy timer;
struct Rlist *del_change;
struct Rlist *del_kept;
struct Rlist *del_notkept;
struct Rlist *retcode_kept;
struct Rlist *retcode_repaired;
struct Rlist *retcode_failed;
};
/*************************************************************************/
/* Ontology */
/*************************************************************************/
struct Topic
{
int id;
char *topic_context;
char *topic_name;
double evc;
struct TopicAssociation *associations;
struct Topic *next;
};
struct TopicAssociation
{
char *fwd_context;
char *fwd_name;
char *bwd_name;
struct Item *associates;
char *bwd_context;
struct TopicAssociation *next;
};
struct Occurrence
{
char *occurrence_context;
char *locator; /* Promiser */
enum representations rep_type;
struct Rlist *represents; /* subtype represented by promiser */
struct Occurrence *next;
};
struct Inference
{
char *inference; // Promiser
char *precedent;
char *qualifier;
struct Inference *next;
};
/*************************************************************************/
/* SQL Database connectors */
/*************************************************************************/
enum cfdbtype
{
cfd_mysql,
cfd_postgres,
cfd_notype
};
typedef struct
{
int connected;
int result;
int row;
unsigned int maxcolumns;
unsigned int maxrows;
int column;
char **rowdata;
char *blank;
enum cfdbtype type;
void *data; /* Generic pointer to RDBMS-specific data */
}
CfdbConn;
/*************************************************************************/
/* Threading container */
/*************************************************************************/
struct PromiseThread
{
enum cfagenttype agent;
char *scopeid;
struct Promise *pp;
void *fnptr;
};
/*************************************************************************/
/* Package promises */
/*************************************************************************/
struct CfPackageManager
{
char *manager;
enum package_actions action;
enum action_policy policy;
struct CfPackageItem *pack_list;
struct CfPackageItem *patch_list;
struct CfPackageItem *patch_avail;
struct CfPackageManager *next;
};
/*************************************************************************/
struct CfPackageItem
{
char *name;
char *version;
char *arch;
struct Promise *pp;
struct CfPackageItem *next;
};
/*************************************************************************/
/* Files */
/*************************************************************************/
struct FileCopy
{
char *source;
char *destination;
enum cfcomparison compare;
enum cflinktype link_type;
struct Rlist *servers;
struct Rlist *link_instead;
struct Rlist *copy_links;
enum cfbackupoptions backup;
int stealth;
int preserve;
int collapse;
int check_root;
int type_check;
int force_update;
int force_ipv4;
size_t min_size; /* Safety margin not search criterion */
size_t max_size;
int trustkey;
int encrypt;
int verify;
int purge;
short portnumber;
short timeout;
};
struct ServerItem
{
char *server;
struct cfagent_connection *conn;
int busy;
};
/*************************************************************************/
struct CfState
{
unsigned int expires;
enum statepolicy policy;
};
/*************************************************************************/
struct FilePerms
{
mode_t plus;
mode_t minus;
struct UidList *owners;
struct GidList *groups;
char *findertype;
u_long plus_flags; /* for *BSD chflags */
u_long minus_flags; /* for *BSD chflags */
int rxdirs;
};
/*************************************************************************/
struct FileSelect
{
struct Rlist *name;
struct Rlist *path;
struct Rlist *perms;
struct Rlist *bsdflags;
struct Rlist *owners;
struct Rlist *groups;
long max_size;
long min_size;
time_t max_ctime;
time_t min_ctime;
time_t max_mtime;
time_t min_mtime;
time_t max_atime;
time_t min_atime;
char *exec_regex;
char *exec_program;
struct Rlist *filetypes;
struct Rlist *issymlinkto;
char *result;
};
/*************************************************************************/
struct FileDelete
{
enum cftidylinks dirlinks;
int rmdirs;
};
/*************************************************************************/
struct FileRename
{
char *newname;
char *disable_suffix;
int disable;
int rotate;
mode_t plus;
mode_t minus;
};
/*************************************************************************/
struct FileChange
{
enum cfhashes hash;
enum cfchanges report_changes;
int report_diffs;
int update;
};
/*************************************************************************/
struct FileLink
{
char *source;
enum cflinktype link_type;
struct Rlist *copy_patterns;
enum cfnofile when_no_file;
enum cflinkchildren when_linking_children;
int link_children;
};
/*************************************************************************/
struct ExecContain
{
int useshell;
mode_t umask;
uid_t owner;
gid_t group;
char *chdir;
char *chroot;
int preview;
int nooutput;
int timeout;
};
/*************************************************************************/
struct ProcessCount
{
long min_range;
long max_range;
struct Rlist *in_range_define;
struct Rlist *out_of_range_define;
};
/*************************************************************************/
struct ProcessSelect
{
struct Rlist *owner;
long min_pid;
long max_pid;
long min_ppid;
long max_ppid;
long min_pgid;
long max_pgid;
long min_rsize;
long max_rsize;
long min_vsize;
long max_vsize;
time_t min_ttime;
time_t max_ttime;
time_t min_stime;
time_t max_stime;
long min_pri;
long max_pri;
long min_thread;
long max_thread;
char *status;
char *command;
char *tty;
char *process_result;
};
/*************************************************************************/
struct Context
{
struct Constraint *expression;
int broken;
};
/*************************************************************************/
struct EditDefaults
{
enum cfbackupoptions backup;
int empty_before_use;
int maxfilesize;
int joinlines;
};
/*************************************************************************/
struct LineSelect
{
struct Rlist *startwith_from_list;
struct Rlist *not_startwith_from_list;
struct Rlist *match_from_list;
struct Rlist *not_match_from_list;
struct Rlist *contains_from_list;
struct Rlist *not_contains_from_list;
};
struct EditLocation
{
char *line_matching;
enum cfeditorder before_after;
char *first_last;
};
struct EditRegion
{
char *select_start;
char *select_end;
int include_start;
int include_end;
};
struct EditColumn
{
char *column_separator;
int select_column;
char value_separator;
char *column_value;
char *column_operation;
int extend_columns;
int blanks_ok;
};
struct EditReplace
{
char *replace_value;
char *occurrences;
};
/*************************************************************************/
struct StorageMount
{
char *mount_type;
char *mount_source;
char *mount_server;
struct Rlist *mount_options;
int editfstab;
int unmount;
};
struct StorageVolume
{
int check_foreign;
long freespace;
int sensible_size;
int sensible_count;
int scan_arrivals;
};
/*************************************************************************/
struct Report
{
int haveprintfile;
int havelastseen;
int lastseen;
double intermittency;
char *friend_pattern;
char *filename;
char *to_file;
int numlines;
struct Rlist *showstate;
};
/*************************************************************************/
struct Packages
{
enum package_actions package_policy;
int have_package_methods;
char *package_version;
struct Rlist *package_architectures;
enum version_cmp package_select;
enum action_policy package_changes;
struct Rlist *package_file_repositories;
char *package_list_command;
char *package_list_version_regex;
char *package_list_name_regex;
char *package_list_arch_regex;
char *package_patch_list_command;
char *package_patch_version_regex;
char *package_patch_name_regex;
char *package_patch_arch_regex;
char *package_patch_installed_regex;
char *package_list_update_command;
int package_list_update_ifelapsed;
char *package_version_regex;
char *package_name_regex;
char *package_arch_regex;
char *package_installed_regex;
char *package_add_command;
char *package_delete_command;
char *package_update_command;
char *package_patch_command;
char *package_verify_command;
char *package_noverify_regex;
char *package_name_convention;
char *package_delete_convention;
char *package_multiline_start;
int package_noverify_returncode;
};
/*************************************************************************/
struct Measurement
{
char *stream_type;
enum cfdatatype data_type;
char *history_type;
char *select_line_matching;
int select_line_number;
char *extraction_regex;
char *units;
int growing;
};
/*************************************************************************/
struct CfTcpIp
{
char *ipv4_address;
char *ipv4_netmask;
};
/*************************************************************************/
struct CfDatabase
{
char *db_server_owner;
char *db_server_password;
char *db_server_host;
char *db_connect_db;
enum cfdbtype db_server_type;
char *server;
char *type;
char *operation;
struct Rlist *columns;
struct Rlist *rows;
struct Rlist *exclude;
};
/*************************************************************************/
enum cf_srv_policy
{
cfsrv_start,
cfsrv_stop,
cfsrv_disable,
cfsrv_nostatus
};
struct CfServices
{
struct Rlist *service_depend;
char *service_type;
char *service_args;
enum cf_srv_policy service_policy;
char *service_autostart_policy;
char *service_depend_chain;
};
/*************************************************************************/
struct Outputs
{
char *level;
char *promiser_type;
};
/*************************************************************************/
enum cfhypervisors
{
cfv_virt_xen,
cfv_virt_kvm,
cfv_virt_esx,
cfv_virt_test,
cfv_virt_xen_net,
cfv_virt_kvm_net,
cfv_virt_esx_net,
cfv_virt_test_net,
cfv_zone,
cfv_ec2,
cfv_eucalyptus,
cfv_none
};
enum cfenvironment_state
{
cfvs_create,
cfvs_delete,
cfvs_running,
cfvs_suspended,
cfvs_down,
cfvs_none
};
struct CfEnvironments
{
int cpus;
int memory;
int disk;
char *baseline;
char *specfile;
struct Rlist *addresses;
char *name;
char *host;
char *type;
enum cfenvironment_state state;
};
/*************************************************************************/
/* This is huge, but the simplification of logic is huge too
so we leave it to the compiler to optimize */
struct Attributes
{
struct Outputs output;
struct FileSelect select;
struct FilePerms perms;
struct FileCopy copy;
struct FileDelete delete;
struct FileRename rename;
struct FileChange change;
struct FileLink link;
struct EditDefaults edits;
struct Packages packages;
struct Context context;
struct Measurement measure;
struct CfACL acl;
struct CfDatabase database;
struct CfServices service;
struct CfEnvironments env;
char *transformer;
char *pathtype;
char *repository;
int touch;
int create;
int move_obstructions;
struct Recursion recursion;
struct TransactionContext transaction;
struct DefineClasses classes;
struct ExecContain contain;
char *args;
int module;
struct Rlist *signals;
char *process_stop;
char *restart_class;
struct ProcessCount process_count;
struct ProcessSelect process_select;
struct Report report;
struct StorageMount mount;
struct StorageVolume volume;
struct CfTcpIp tcpip;
int havedepthsearch;
int haveselect;
int haverename;
int havedelete;
int haveperms;
int havechange;
int havecopy;
int havelink;
int haveeditline;
int haveeditxml;
int haveedit;
int havecontain;
int haveclasses;
int havetrans;
int haveprocess_count;
int havemount;
int havevolume;
int havebundle;
int havetcpip;
int havepackages;
/* editline */
struct EditRegion region;
struct EditLocation location;
struct EditColumn column;
struct EditReplace replace;
int haveregion;
int havelocation;
int havecolumn;
int havereplace;
int haveinsertselect;
int havedeleteselect;
struct LineSelect line_select;
char *sourcetype;
int expandvars;
int not_matching;
struct Rlist *insert_match;
/* knowledge */
char *fwd_name;
char *bwd_name;
struct Rlist *precedents;
struct Rlist *qualifiers;
struct Rlist *associates;
struct Rlist *represents;
struct Rlist *synonyms;
struct Rlist *general;
char *rep_type;
char *path_root;
char *web_root;
};
enum cf_meter
{
meter_compliance_week,
meter_compliance_day,
meter_compliance_hour,
meter_perf_day,
meter_other_day,
meter_comms_hour,
meter_anomalies_day,
meter_endmark
};
/*************************************************************************/
/* definitions for reporting */
/*************************************************************************/
typedef enum cdp_report
{
cdp_acls,
cdp_commands,
cdp_filechanges,
cdp_filediffs,
cdp_registry,
cdp_services,
cdp_unknown
}
cdp_t;
typedef enum basic_reports
{
cfrep_bundle,
cfrep_business,
cfrep_classes,
cfrep_promise_compliance,
cfrep_total_compliance,
cfrep_change,
cfrep_diff,
cfrep_lastseen,
cfrep_patch_avail,
cfrep_patch_status,
cfrep_performance,
cfrep_repaired,
cfrep_repair_summary,
cfrep_notkept,
cfrep_notkept_summary,
cfrep_setuid,
cfrep_software_installed,
cfrep_variables,
cfrep_unknown
}
cfrep_t;
/*************************************************************************/
/* definitions for test suite */
/*************************************************************************/
// Classes: 601 - 650
#define CF_CLASS_ALL 0
#define CF_CLASS_REPORT 2
#define CF_CLASS_VARS 4
#define CF_CLASS_SLIST 8
#define CF_CLASS_STRING 16
#define CF_CLASS_PROCESS 32
#define CF_CLASS_FILE 64
#define CF_CLASS_DIR 128
#define CF_CLASS_CMD 256
#define CF_CLASS_OTHER 512
#define CF_CLASS_TOP10 1024
/*************************************************************************/
/* common macros */
/*************************************************************************/
#define EMPTY(str) ((str == NULL) || (str[0] == '\0'))
#define BEGINSWITH(str,start) (strncmp(str,start,strlen(start)) == 0)
#define CFSTRDUP(str) ((str != NULL) ? strdup(str) : NULL)
#define CFFREE(ptr) if(ptr) free(ptr)
// classes not interesting in reports
#define IGNORECLASS(c) \
(strncmp(c,"Min",3) == 0 || strncmp(c,"Hr",2) == 0 || strcmp(c,"Q1") == 0 \
|| strcmp(c,"Q2") == 0 || strcmp(c,"Q3") == 0 || strcmp(c,"Q4") == 0 \
|| strncmp(c,"GMT_Hr",6) == 0 || strncmp(c,"Yr",2) == 0 \
|| strncmp(c,"Day",3) == 0 || strcmp(c,"license_expired") == 0 \
|| strcmp(c,"any") == 0 || strcmp(c,"from_cfexecd") == 0 \
|| IsStrIn(c,MONTH_TEXT) || IsStrIn(c,DAY_TEXT) \
|| IsStrIn(c,SHIFT_TEXT))
// Date time classes
#define ISCLASS_DATETIME(c) \
(strncmp(c,"Min",3) == 0 || strncmp(c,"Hr",2) == 0 || strcmp(c,"Q1") == 0 \
|| strcmp(c,"Q2") == 0 || strcmp(c,"Q3") == 0 || strcmp(c,"Q4") == 0 \
|| strncmp(c,"GMT_Hr",6) == 0 || strncmp(c,"Yr",2) == 0 \
|| strncmp(c,"Day",3) == 0 || IsStrIn(c,MONTH_TEXT) \
|| IsStrIn(c,DAY_TEXT) || IsStrIn(c,SHIFT_TEXT) \
|| strncmp(c,"Lcycle",6) == 0)
#include "prototypes3.h"
#ifdef HAVE_NOVA
#include
#endif
#endif
cfengine-3.2.4/src/rlist.c 0000644 0001750 0001750 00000065266 11715232734 012333 0000000 0000000 /*
Copyright (C) Cfengine AS
This file is part of Cfengine 3 - written and maintained by Cfengine 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 Commerical Open Source License
(COSL) may apply to this file if you as a licensee so wish it. See
included file COSL.txt.
*/
/*****************************************************************************/
/* */
/* File: rlist.c */
/* */
/*****************************************************************************/
#include "cf3.defs.h"
#include "cf3.extern.h"
static int IsRegexIn(struct Rlist *list,char *s);
static int CompareRlist(struct Rlist *list1, struct Rlist *list2);
static void DeleteRlistNoRef(struct Rlist *list);
static void ShowRlistState(FILE *fp,struct Rlist *list);
/*******************************************************************/
struct Rlist *KeyInRlist(struct Rlist *list,char *key)
{ struct Rlist *rp;
for (rp = list; rp != NULL; rp = rp->next)
{
if (rp->type != CF_SCALAR)
{
continue;
}
if (strcmp((char *)rp->item,key) == 0)
{
return rp;
}
}
return NULL;
}
/*******************************************************************/
int IsStringIn(struct Rlist *list,char *s)
{ struct Rlist *rp;
if (s == NULL || list == NULL)
{
return false;
}
for (rp = list; rp != NULL; rp=rp->next)
{
if (rp->type != CF_SCALAR)
{
continue;
}
if (strcmp(s,rp->item) == 0)
{
return true;
}
}
return false;
}
/*******************************************************************/
int IsIntIn(struct Rlist *list,int i)
{ struct Rlist *rp;
char s[CF_SMALLBUF];
snprintf(s,CF_SMALLBUF-1,"%d",i);
if (list == NULL)
{
return false;
}
for (rp = list; rp != NULL; rp=rp->next)
{
if (rp->type != CF_SCALAR)
{
continue;
}
if (strcmp(s,rp->item) == 0)
{
return true;
}
}
return false;
}
/*******************************************************************/
static int IsRegexIn(struct Rlist *list,char *regex)
{ struct Rlist *rp;
if (regex == NULL || list == NULL)
{
return false;
}
for (rp = list; rp != NULL; rp=rp->next)
{
if (rp->type != CF_SCALAR)
{
continue;
}
if (FullTextMatch(regex,rp->item))
{
return true;
}
}
return false;
}
/*******************************************************************/
int IsInListOfRegex(struct Rlist *list,char *str)
{ struct Rlist *rp;
if (str == NULL || list == NULL)
{
return false;
}
for (rp = list; rp != NULL; rp=rp->next)
{
if (rp->type != CF_SCALAR)
{
continue;
}
if (FullTextMatch(rp->item,str))
{
return true;
}
}
return false;
}
/*******************************************************************/
void *CopyRvalItem(void *item, char type)
{ struct Rlist *rp,*srp,*start = NULL;
struct FnCall *fp;
void *new,*rval;
char rtype = CF_SCALAR;
char naked[CF_BUFSIZE];
Debug("CopyRvalItem(%c)\n",type);
if (item == NULL)
{
switch (type)
{
case CF_SCALAR:
return strdup("");
case CF_LIST:
return NULL;
}
}
naked[0] = '\0';
switch(type)
{
case CF_SCALAR:
/* the rval is just a string */
if ((new = strdup((char *)item)) == NULL)
{
CfOut(cf_error,"strdup","Memory allocation");
FatalError("CopyRvalItem");
}
return new;
case CF_FNCALL:
/* the rval is a fncall */
fp = (struct FnCall *)item;
return CopyFnCall(fp);
case CF_LIST:
/* The rval is an embedded rlist (2d) */
for (rp = (struct Rlist *)item; rp != NULL; rp=rp->next)
{
if (IsNakedVar(rp->item,'@'))
{
GetNaked(naked,rp->item);
if (GetVariable(CONTEXTID,naked,&rval,&rtype) != cf_notype)
{
switch (rtype)
{
case CF_LIST:
for (srp = (struct Rlist *)rval; srp != NULL; srp=srp->next)
{
AppendRlist(&start,srp->item,srp->type);
}
break;
default:
AppendRlist(&start,rp->item,rp->type);
break;
}
}
else
{
AppendRlist(&start,rp->item,rp->type);
}
}
else
{
AppendRlist(&start,rp->item,rp->type);
}
}
return start;
}
//snprintf(output,CF_BUFSIZE,"Unknown type %c in CopyRvalItem - should not happen",type);
//FatalError(output);
return NULL;
}
/*******************************************************************/
int CompareRval(void *rval1, char rtype1, void *rval2, char rtype2)
{
if (rtype1 != rtype2)
{
return -1;
}
switch (rtype1)
{
case CF_SCALAR:
if (IsCf3VarString((char *)rval1) || IsCf3VarString((char *)rval2))
{
return -1; // inconclusive
}
if (strcmp(rval1,rval2) != 0)
{
return false;
}
break;
case CF_LIST:
return CompareRlist(rval1,rval2);
case CF_FNCALL:
return -1;
}
return true;
}
/*******************************************************************/
static int CompareRlist(struct Rlist *list1, struct Rlist *list2)
{ struct Rlist *rp1,*rp2;
for (rp1 = list1, rp2 = list2; rp1 != NULL && rp2!= NULL; rp1=rp1->next,rp2=rp2->next)
{
if (rp1->item && rp2->item)
{
struct Rlist *rc1,*rc2;
if (rp1->type == CF_FNCALL || rp2->type == CF_FNCALL)
{
return -1; // inconclusive
}
rc1 = rp1;
rc2 = rp2;
// Check for list nesting with { fncall(), "x" ... }
if (rp1->type == CF_LIST)
{
rc1 = rp1->item;
}
if (rp2->type == CF_LIST)
{
rc2 = rp2->item;
}
if (IsCf3VarString(rc1->item) || IsCf3VarString(rp2->item))
{
return -1; // inconclusive
}
if (strcmp(rc1->item,rc2->item) != 0)
{
return false;
}
}
else
{
return false;
}
}
return true;
}
/*******************************************************************/
struct Rlist *CopyRlist(struct Rlist *list)
{ struct Rlist *rp,*start = NULL;
Debug("CopyRlist()\n");
if (list == NULL)
{
return NULL;
}
for (rp = list; rp != NULL; rp = rp->next)
{
AppendRlist(&start,rp->item,rp->type); // allocates memory for objects
}
return start;
}
/*******************************************************************/
void DeleteRlist(struct Rlist *list)
/* Delete an rlist and all its references */
{ struct Rlist *rl, *next;
if (list != NULL)
{
for(rl = list; rl != NULL; rl = next)
{
next = rl->next;
if (rl->item != NULL)
{
DeleteRvalItem(rl->item,rl->type);
}
free(rl);
}
}
}
/*******************************************************************/
static void DeleteRlistNoRef(struct Rlist *list)
/* Delete a rlist, but not its references */
{ struct Rlist *rl, *next;
if(list != NULL)
{
for(rl = list; rl != NULL; rl = next)
{
next = rl->next;
free(rl);
}
}
}
/*******************************************************************/
struct Rlist *IdempAppendRScalar(struct Rlist **start,void *item, char type)
{ char *scalar = item;
if (type != CF_SCALAR)
{
FatalError("Cannot append non-scalars to lists");
}
if (!KeyInRlist(*start,(char *)item))
{
return AppendRlist(start,scalar,type);
}
else
{
return NULL;
}
}
/*******************************************************************/
struct Rlist *IdempPrependRScalar(struct Rlist **start,void *item, char type)
{ char *scalar = item;
if (type != CF_SCALAR)
{
FatalError("Cannot append non-scalars to lists");
}
if (!KeyInRlist(*start,(char *)item))
{
return PrependRlist(start,scalar,type);
}
else
{
return NULL;
}
}
/*******************************************************************/
struct Rlist *IdempAppendRlist(struct Rlist **start,void *item, char type)
{ char *scalar;
struct Rlist *rp,*ins = NULL;
if (type == CF_LIST)
{
for (rp = (struct Rlist *)item; rp != NULL; rp=rp->next)
{
ins = IdempAppendRlist(start,rp->item,rp->type);
}
return ins;
}
scalar = strdup((char *)item);
if (!KeyInRlist(*start,(char *)item))
{
return AppendRlist(start,scalar,type);
}
else
{
return NULL;
}
}
/*******************************************************************/
struct Rlist *AppendRScalar(struct Rlist **start,void *item, char type)
{ char *scalar = item;
if (type != CF_SCALAR)
{
FatalError("Cannot append non-scalars to lists");
}
return AppendRlist(start,scalar,type);
}
/*******************************************************************/
struct Rlist *PrependRScalar(struct Rlist **start,void *item, char type)
{ char *scalar = item;
if (type != CF_SCALAR)
{
FatalError("Cannot append non-scalars to lists");
}
return PrependRlist(start,scalar,type);
}
/*******************************************************************/
struct Rlist *AppendRlist(struct Rlist **start,void *item, char type)
/* Allocates new memory for objects - careful, could leak! */
{ struct Rlist *rp,*lp = *start;
struct FnCall *fp;
switch(type)
{
case CF_SCALAR:
Debug("Appending scalar to rval-list [%s]\n",(char *)item);
break;
case CF_FNCALL:
Debug("Appending function to rval-list function call: ");
fp = (struct FnCall *)item;
if (DEBUG)
{
ShowFnCall(stdout,fp);
}
Debug("\n");
break;
case CF_LIST:
Debug("Expanding and appending list object\n");
for (rp = (struct Rlist *)item; rp != NULL; rp=rp->next)
{
lp = AppendRlist(start,rp->item,rp->type);
}
return lp;
default:
Debug("Cannot append %c to rval-list [%s]\n",type,(char *)item);
return NULL;
}
if ((rp = (struct Rlist *)malloc(sizeof(struct Rlist))) == NULL)
{
CfOut(cf_error,"malloc","Unable to allocate Rlist");
FatalError("");
}
if (*start == NULL)
{
*start = rp;
}
else
{
for (lp = *start; lp->next != NULL; lp=lp->next)
{
}
lp->next = rp;
}
rp->item = CopyRvalItem(item,type);
rp->type = type; /* scalar, builtin function */
ThreadLock(cft_lock);
if (type == CF_LIST)
{
rp->state_ptr = rp->item;
}
else
{
rp->state_ptr = NULL;
}
rp->next = NULL;
ThreadUnlock(cft_lock);
return rp;
}
/*******************************************************************/
struct Rlist *PrependRlist(struct Rlist **start,void *item, char type)
/* heap memory for item must have already been allocated */
{ struct Rlist *rp,*lp = *start;
struct FnCall *fp;
switch(type)
{
case CF_SCALAR:
Debug("Prepending scalar to rval-list [%s]\n",item);
break;
case CF_LIST:
Debug("Expanding and prepending list (ends up in reverse)\n");
for (rp = (struct Rlist *)item; rp != NULL; rp=rp->next)
{
lp = PrependRlist(start,rp->item,rp->type);
}
return lp;
case CF_FNCALL:
Debug("Prepending function to rval-list function call: ");
fp = (struct FnCall *)item;
if (DEBUG)
{
ShowFnCall(stdout,fp);
}
Debug("\n");
break;
default:
Debug("Cannot prepend %c to rval-list [%s]\n",type,item);
return NULL;
}
ThreadLock(cft_system);
if ((rp = (struct Rlist *)malloc(sizeof(struct Rlist))) == NULL)
{
CfOut(cf_error,"malloc","Unable to allocate Rlist");
FatalError("");
}
ThreadUnlock(cft_system);
rp->next = *start;
rp->item = CopyRvalItem(item,type);
rp->type = type; /* scalar, builtin function */
if (type == CF_LIST)
{
rp->state_ptr = rp->item;
}
else
{
rp->state_ptr = NULL;
}
ThreadLock(cft_lock);
*start = rp;
ThreadUnlock(cft_lock);
return rp;
}
/*******************************************************************/
struct Rlist *OrthogAppendRlist(struct Rlist **start,void *item, char type)
/* Allocates new memory for objects - careful, could leak! */
{ struct Rlist *rp,*lp;
struct CfAssoc *cp;
Debug("OrthogAppendRlist\n");
switch(type)
{
case CF_LIST:
Debug("Expanding and appending list object, orthogonally\n");
break;
default:
Debug("Cannot append %c to rval-list [%s]\n",type,item);
return NULL;
}
if ((rp = (struct Rlist *)malloc(sizeof(struct Rlist))) == NULL)
{
CfOut(cf_error,"malloc","Unable to allocate Rlist");
FatalError("");
}
if (*start == NULL)
{
*start = rp;
}
else
{
for (lp = *start; lp->next != NULL; lp=lp->next)
{
}
lp->next = rp;
}
// This is item is in fact a struct CfAssoc pointing to a list
cp = (struct CfAssoc *)item;
// Note, we pad all iterators will a blank so the ptr arithmetic works
// else EndOfIteration will not see lists with only one element
lp = PrependRlist((struct Rlist **)&(cp->rval),CF_NULL_VALUE,CF_SCALAR);
rp->state_ptr = lp->next; // Always skip the null value
AppendRlist((struct Rlist **)&(cp->rval),CF_NULL_VALUE,CF_SCALAR);
rp->item = item;
rp->type = CF_LIST;
rp->next = NULL;
return rp;
}
/*******************************************************************/
int RlistLen(struct Rlist *start)
{ int count = 0;
struct Rlist *rp;
for (rp = start; rp != NULL; rp=rp->next)
{
count++;
}
return count;
}
/*******************************************************************/
struct Rlist *ParseShownRlist(char *string)
{ struct Rlist *newlist = NULL,*splitlist,*rp;
char value[CF_MAXVARSIZE];
/* Parse a string representation generated by ShowList and turn back into Rlist */
splitlist = SplitStringAsRList(string,',');
for (rp = splitlist; rp != NULL; rp = rp->next)
{
sscanf(rp->item,"%*[{ '\"]%255[^'\"]",value);
AppendRlist(&newlist,value,CF_SCALAR);
}
DeleteRlist(splitlist);
return newlist;
}
/*******************************************************************/
void ShowRlist(FILE *fp,struct Rlist *list)
{ struct Rlist *rp;
fprintf(fp," {");
for (rp = list; rp != NULL; rp=rp->next)
{
fprintf(fp,"\'");
ShowRval(fp,rp->item,rp->type);
fprintf(fp,"\'");
if (rp->next != NULL)
{
fprintf(fp,",");
}
}
fprintf(fp,"}");
}
/*******************************************************************/
int PrintRlist(char *buffer,int bufsize,struct Rlist *list)
{ struct Rlist *rp;
StartJoin(buffer,"{",bufsize);
for (rp = list; rp != NULL; rp=rp->next)
{
if(!JoinSilent(buffer,"'",bufsize))
{
EndJoin(buffer,"...TRUNCATED'}",bufsize);
return false;
}
if(!PrintRval(buffer,bufsize,rp->item,rp->type))
{
EndJoin(buffer,"...TRUNCATED'}",bufsize);
return false;
}
if(!JoinSilent(buffer,"'",bufsize))
{
EndJoin(buffer,"...TRUNCATED'}",bufsize);
return false;
}
if (rp->next != NULL)
{
if(!JoinSilent(buffer,",",bufsize))
{
EndJoin(buffer,"...TRUNCATED}",bufsize);
return false;
}
}
}
EndJoin(buffer,"}",bufsize);
return true;
}
/*******************************************************************/
int GetStringListElement(char *strList, int index, char *outBuf, int outBufSz)
/** Takes a string-parsed list "{'el1','el2','el3',..}" and writes
** "el1" or "el2" etc. based on index (starting on 0) in outBuf.
** returns true on success, false otherwise.
**/
{ char *sp,*elStart = strList,*elEnd;
int elNum = 0;
int minBuf;
memset(outBuf,0,outBufSz);
if (EMPTY(strList))
{
return false;
}
if(strList[0] != '{')
{
return false;
}
for(sp = strList; *sp != '\0'; sp++)
{
if((sp[0] == '{' || sp[0] == ',') && sp[1] == '\'')
{
elStart = sp + 2;
}
else if((sp[0] == '\'') && sp[1] == ',' || sp[1] == '}')
{
elEnd = sp;
if(elNum == index)
{
if(elEnd - elStart < outBufSz)
{
minBuf = elEnd - elStart;
}
else
{
minBuf = outBufSz - 1;
}
strncpy(outBuf,elStart,minBuf);
break;
}
elNum++;
}
}
return true;
}
/*******************************************************************/
int StripListSep(char *strList, char *outBuf, int outBufSz)
{
memset(outBuf,0,outBufSz);
if(EMPTY(strList))
{
return false;
}
if(strList[0] != '{')
{
return false;
}
snprintf(outBuf,outBufSz,"%s",strList + 1);
if(outBuf[strlen(outBuf) - 1] == '}')
{
outBuf[strlen(outBuf) - 1] = '\0';
}
return true;
}
/*******************************************************************/
int PrintRval(char *buffer,int bufsize,void *rval,char type)
{
if (rval == NULL)
{
return 0;
}
switch (type)
{
case CF_SCALAR:
return JoinSilent(buffer,(char *)rval,bufsize);
break;
case CF_LIST:
return PrintRlist(buffer,bufsize,(struct Rlist *)rval);
break;
case CF_FNCALL:
PrintFnCall(buffer,bufsize,(struct FnCall *)rval);
break;
case CF_NOPROMISEE:
// fprintf(fp,"(no-one)");
break;
}
return true;
}
/*******************************************************************/
static void ShowRlistState(FILE *fp,struct Rlist *list)
{
ShowRval(fp,list->state_ptr->item,list->type);
}
/*******************************************************************/
void ShowRval(FILE *fp,void *rval,char type)
{
char buf[CF_BUFSIZE];
if (rval == NULL)
{
return;
}
switch (type)
{
case CF_SCALAR:
EscapeQuotes((char *)rval,buf,sizeof(buf));
fprintf(fp,"%s",buf);
break;
case CF_LIST:
ShowRlist(fp,(struct Rlist *)rval);
break;
case CF_FNCALL:
ShowFnCall(fp,(struct FnCall *)rval);
break;
case CF_NOPROMISEE:
fprintf(fp,"(no-one)");
break;
}
}
/*******************************************************************/
void DeleteRvalItem(void *rval, char type)
{ struct Rlist *clist, *next = NULL;
Debug("DeleteRvalItem(%c)",type);
if (DEBUG)
{
ShowRval(stdout,rval,type);
}
Debug("\n");
if (rval == NULL)
{
Debug("DeleteRval NULL\n");
return;
}
switch(type)
{
case CF_SCALAR:
ThreadLock(cft_lock);
free((char *)rval);
ThreadUnlock(cft_lock);
break;
case CF_LIST:
/* rval is now a list whose first item is clist->item */
for(clist = (struct Rlist *)rval; clist != NULL; clist = next)
{
next = clist->next;
if (clist->item)
{
DeleteRvalItem(clist->item,clist->type);
}
free(clist);
}
break;
case CF_FNCALL:
if (rval)
{
DeleteFnCall((struct FnCall *)rval);
}
break;
default:
Debug("Nothing to do\n");
return;
}
}
/*********************************************************************/
void DeleteRlistEntry(struct Rlist **liststart,struct Rlist *entry)
{ struct Rlist *rp, *sp;
if (entry != NULL)
{
if (entry->item != NULL)
{
free(entry->item);
}
sp = entry->next;
if (entry == *liststart)
{
*liststart = sp;
}
else
{
for (rp = *liststart; rp->next != entry; rp=rp->next)
{
}
rp->next = sp;
}
free((char *)entry);
}
}
/*******************************************************************/
struct Rlist *AppendRlistAlien(struct Rlist **start,void *item)
/* Allocates new memory for objects - careful, could leak! */
{ struct Rlist *rp,*lp = *start;
if ((rp = (struct Rlist *)malloc(sizeof(struct Rlist))) == NULL)
{
CfOut(cf_error,"malloc","Unable to allocate Rlist");
FatalError("");
}
if (*start == NULL)
{
*start = rp;
}
else
{
for (lp = *start; lp->next != NULL; lp=lp->next)
{
}
lp->next = rp;
}
rp->item = item;
rp->type = CF_SCALAR;
ThreadLock(cft_lock);
rp->next = NULL;
ThreadUnlock(cft_lock);
return rp;
}
/*******************************************************************/
struct Rlist *PrependRlistAlien(struct Rlist **start,void *item)
/* Allocates new memory for objects - careful, could leak! */
{ struct Rlist *rp;
ThreadLock(cft_lock);
if ((rp = (struct Rlist *)malloc(sizeof(struct Rlist))) == NULL)
{
CfOut(cf_error,"malloc","Unable to allocate Rlist");
FatalError("");
}
rp->next = *start;
*start = rp;
ThreadUnlock(cft_lock);
rp->item = item;
rp->type = CF_SCALAR;
return rp;
}
/*******************************************************************/
/* Stack */
/*******************************************************************/
/*
char *sp1 = strdup("String 1\n");
char *sp2 = strdup("String 2\n");
char *sp3 = strdup("String 3\n");
PushStack(&stack,(void *)sp1);
PopStack(&stack,(void *)&sp,sizeof(sp));
*/
void PushStack(struct Rlist **liststart,void *item)
{ struct Rlist *rp;
/* Have to keep track of types personally */
if ((rp = (struct Rlist *)malloc(sizeof(struct Rlist))) == NULL)
{
CfOut(cf_error,"malloc","Unable to allocate Rlist");
FatalError("");
}
rp->next = *liststart;
rp->item = item;
rp->type = CF_STACK;
*liststart = rp;
}
/*******************************************************************/
void PopStack(struct Rlist **liststart, void **item,size_t size)
{ struct Rlist *rp = *liststart;
if (*liststart == NULL)
{
FatalError("Attempt to pop from empty stack");
}
*item = rp->item;
if (rp->next == NULL) /* only one left */
{
*liststart = (void *)NULL;
}
else
{
*liststart = rp->next;
}
free((char *)rp);
}
/*******************************************************************/
struct Rlist *SplitStringAsRList(char *string,char sep)
/* Splits a string containing a separator like ","
into a linked list of separate items, supports
escaping separators, e.g. \, */
{ struct Rlist *liststart = NULL;
char *sp;
char node[CF_MAXVARSIZE];
int maxlen = strlen(string);
Debug("SplitStringAsRList(%s)\n",string);
if (string == NULL)
{
return NULL;
}
for (sp = string; *sp != '\0'; sp++)
{
if (*sp == '\0' || sp > string+maxlen)
{
break;
}
memset(node,0,CF_MAXVARSIZE);
sp += SubStrnCopyChr(node,sp,CF_MAXVARSIZE,sep);
AppendRScalar(&liststart,node,CF_SCALAR);
}
return liststart;
}
/*******************************************************************/
struct Rlist *SplitRegexAsRList(char *string,char *regex,int max,int blanks)
/* Splits a string containing a separator like ","
into a linked list of separate items, */
{ struct Rlist *liststart = NULL;
char *sp;
char node[CF_MAXVARSIZE];
int start,end;
int delta, count = 0;
if (string == NULL)
{
return NULL;
}
Debug("\n\nSplit \"%s\" with regex \"%s\" (up to maxent %d)\n\n",string,regex,max);
sp = string;
while ((count < max) && BlockTextMatch(regex,sp,&start,&end))
{
if (end == 0)
{
break;
}
delta = end - start;
memset(node,0,CF_MAXVARSIZE);
strncpy(node,sp,start);
if (blanks || strlen(node) > 0)
{
AppendRScalar(&liststart,node,CF_SCALAR);
count++;
}
sp += end;
}
if (count < max)
{
memset(node,0,CF_MAXVARSIZE);
strncpy(node,sp,CF_MAXVARSIZE-1);
if (blanks || strlen(node) > 0)
{
AppendRScalar(&liststart,node,CF_SCALAR);
}
}
return liststart;
}
/*****************************************************************************/
int PrependPackageItem(struct CfPackageItem **list,char *name,char *version,char *arch,struct Attributes a,struct Promise *pp)
{ struct CfPackageItem *pi;
if (strlen(name) == 0 || strlen(version) == 0 || strlen(arch) == 0)
{
return false;
}
CfOut(cf_verbose,""," -> Package (%s,%s,%s) found",name,version,arch);
if ((pi = (struct CfPackageItem *)malloc(sizeof(struct CfPackageItem))) == NULL)
{
CfOut(cf_error,"malloc","Can't allocate new package\n");
return false;
}
if (list)
{
pi->next = *list;
}
else
{
pi->next = NULL;
}
pi->name = strdup(name);
pi->version = strdup(version);
pi->arch = strdup(arch);
*list = pi;
/* Finally we need these for later schedule exec, once this iteration context has gone */
pi->pp = DeRefCopyPromise("this",pp);
return true;
}
/*****************************************************************************/
int PrependListPackageItem(struct CfPackageItem **list,char *item,struct Attributes a,struct Promise *pp)
{ char name[CF_MAXVARSIZE];
char arch[CF_MAXVARSIZE];
char version[CF_MAXVARSIZE];
char vbuff[CF_MAXVARSIZE];
strncpy(vbuff,ExtractFirstReference(a.packages.package_list_name_regex,item),CF_MAXVARSIZE-1);
sscanf(vbuff,"%s",name); /* trim */
strncpy(vbuff,ExtractFirstReference(a.packages.package_list_version_regex,item),CF_MAXVARSIZE-1);
sscanf(vbuff,"%s",version); /* trim */
if (a.packages.package_list_arch_regex)
{
strncpy(vbuff,ExtractFirstReference(a.packages.package_list_arch_regex,item),CF_MAXVARSIZE-1);
sscanf(vbuff,"%s",arch); /* trim */
}
else
{
strncpy(arch,"default",CF_MAXVARSIZE-1);
}
if (strcmp(name,"CF_NOMATCH") == 0 || strcmp(version,"CF_NOMATCH") == 0 || strcmp(arch,"CF_NOMATCH") == 0)
{
return false;
}
Debug(" -? Package line \"%s\"\n",item);
Debug(" -? with name \"%s\"\n",name);
Debug(" -? with version \"%s\"\n",version);
Debug(" -? with architecture \"%s\"\n",arch);
return PrependPackageItem(list,name,version,arch,a,pp);
}
cfengine-3.2.4/src/sysinfo.c 0000644 0001750 0001750 00000144416 11715232734 012663 0000000 0000000 /*
Copyright (C) Cfengine AS
This file is part of Cfengine 3 - written and maintained by Cfengine 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 Commerical Open Source License
(COSL) may apply to this file if you as a licensee so wish it. See
included file COSL.txt.
*/
/*****************************************************************************/
/* */
/* File: sysinfo.c */
/* */
/* Created: Sun Sep 30 14:14:47 2007 */
/* */
/*****************************************************************************/
#include "cf3.defs.h"
#include "cf3.extern.h"
#ifdef IRIX
#include
#endif
static void FindDomainName(char *hostname);
static int Linux_Fedora_Version(void);
static int Linux_Redhat_Version(void);
static void Linux_Oracle_VM_Server_Version(void);
static void Linux_Oracle_Version(void);
static int Linux_Suse_Version(void);
static int Linux_Slackware_Version(char *filename);
static int Linux_Debian_Version(void);
static int Linux_Mandrake_Version(void);
static int Linux_Mandriva_Version(void);
static int Linux_Mandriva_Version_Real(char *filename, char *relstring, char *vendor);
static int VM_Version(void);
static int Xen_Domain(void);
static void Xen_Cpuid(uint32_t idx, uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx);
static int Xen_Hv_Check(void);
static FILE *ReadFirstLine(const char *filename, char *buf, int bufsize);
static bool ReadLine(const char *filename, char *buf, int bufsize);
/**********************************************************************/
void SetSignals()
{ int i;
SIGNALS[SIGHUP] = strdup("SIGHUP");
SIGNALS[SIGINT] = strdup("SIGINT");
SIGNALS[SIGTRAP] = strdup("SIGTRAP");
SIGNALS[SIGKILL] = strdup("SIGKILL");
SIGNALS[SIGPIPE] = strdup("SIGPIPE");
SIGNALS[SIGCONT] = strdup("SIGCONT");
SIGNALS[SIGABRT] = strdup("SIGABRT");
SIGNALS[SIGSTOP] = strdup("SIGSTOP");
SIGNALS[SIGQUIT] = strdup("SIGQUIT");
SIGNALS[SIGTERM] = strdup("SIGTERM");
SIGNALS[SIGCHLD] = strdup("SIGCHLD");
SIGNALS[SIGUSR1] = strdup("SIGUSR1");
SIGNALS[SIGUSR2] = strdup("SIGUSR2");
SIGNALS[SIGBUS] = strdup("SIGBUS");
SIGNALS[SIGSEGV] = strdup("SIGSEGV");
for (i = 0; i < highest_signal; i++)
{
if (SIGNALS[i] == NULL)
{
SIGNALS[i] = strdup("NOSIG");
}
}
}
/*******************************************************************/
void GetNameInfo3()
{ int i,found = false;
char *sp,workbuf[CF_BUFSIZE];
time_t tloc;
struct hostent *hp;
struct sockaddr_in cin;
unsigned char digest[EVP_MAX_MD_SIZE+1];
#ifdef AIX
char real_version[_SYS_NMLN];
#endif
#ifdef IRIX
char real_version[256]; /* see */
#endif
#if defined(HAVE_SYSINFO) && (defined(SI_ARCHITECTURE) || defined(SI_PLATFORM))
long sz;
#endif
char *components[] = { "cf-twin", "cf-agent", "cf-serverd", "cf-monitord", "cf-know",
"cf-report", "cf-key", "cf-runagent", "cf-execd", "cf-hub",
"cf-promises", NULL };
int have_component[11];
struct stat sb;
char name[CF_MAXVARSIZE],quoteName[CF_MAXVARSIZE],shortname[CF_MAXVARSIZE];
Debug("GetNameInfo()\n");
if (VSYSTEMHARDCLASS != unused1)
{
CfOut(cf_verbose,"","Already know our hard classes...\n");
/* Already have our name - so avoid memory leaks by recomputing */
return;
}
VFQNAME[0] = VUQNAME[0] = '\0';
if (uname(&VSYSNAME) == -1)
{
CfOut(cf_error, "uname", "!!! Couldn't get kernel name info!");
memset(&VSYSNAME, 0, sizeof(VSYSNAME));
}
#ifdef AIX
snprintf(real_version,_SYS_NMLN,"%.80s.%.80s", VSYSNAME.version, VSYSNAME.release);
strncpy(VSYSNAME.release, real_version, _SYS_NMLN);
#elif defined IRIX
/* This gets us something like `6.5.19m' rather than just `6.5'. */
syssgi (SGI_RELEASE_NAME, 256, real_version);
#endif
for (sp = VSYSNAME.sysname; *sp != '\0'; sp++)
{
*sp = ToLower(*sp);
}
for (sp = VSYSNAME.machine; *sp != '\0'; sp++)
{
*sp = ToLower(*sp);
}
#ifdef _AIX
switch (_system_configuration.architecture)
{
case POWER_RS:
strncpy(VSYSNAME.machine, "power", _SYS_NMLN);
break;
case POWER_PC:
strncpy(VSYSNAME.machine, "powerpc", _SYS_NMLN);
break;
case IA64:
strncpy(VSYSNAME.machine, "ia64", _SYS_NMLN);
break;
}
#endif
for (i = 0; CLASSATTRIBUTES[i][0] != '\0'; i++)
{
if (FullTextMatch(CLASSATTRIBUTES[i][0],ToLowerStr(VSYSNAME.sysname)))
{
if (FullTextMatch(CLASSATTRIBUTES[i][1],VSYSNAME.machine))
{
if (FullTextMatch(CLASSATTRIBUTES[i][2],VSYSNAME.release))
{
NewClass(CLASSTEXT[i]);
found = true;
VSYSTEMHARDCLASS = (enum classes) i;
NewScalar("sys","class",CLASSTEXT[i],cf_str);
break;
}
}
else
{
Debug2("Cfengine: I recognize %s but not %s\n",VSYSNAME.sysname,VSYSNAME.machine);
continue;
}
}
}
FindDomainName(VSYSNAME.nodename);
if (!StrStr(VSYSNAME.nodename,VDOMAIN))
{
strcpy(VUQNAME,ToLowerStr(VSYSNAME.nodename));
NewClass(ToLowerStr(VUQNAME));
snprintf(VFQNAME,CF_BUFSIZE,"%s.%s",VUQNAME,ToLowerStr(VDOMAIN));
NewClass(ToLowerStr(VFQNAME));
}
else
{
int n = 0;
strcpy(VFQNAME,ToLowerStr(VSYSNAME.nodename));
NewClass(VFQNAME);
while(VSYSNAME.nodename[n++] != '.' && VSYSNAME.nodename[n] != '\0')
{
}
strncpy(VUQNAME,ToLowerStr(VSYSNAME.nodename),n);
if (VUQNAME[n-1] == '.')
{
VUQNAME[n-1] = '\0';
}
else
{
VUQNAME[n] = '\0';
}
NewClass(VUQNAME);
}
if ((tloc = time((time_t *)NULL)) == -1)
{
printf("Couldn't read system clock\n");
}
snprintf(workbuf,CF_BUFSIZE,"%s",CLASSTEXT[i]);
CfOut(cf_verbose,"",NameVersion());
CfOut(cf_verbose,"","------------------------------------------------------------------------\n\n");
CfOut(cf_verbose,"","Host name is: %s\n",VSYSNAME.nodename);
CfOut(cf_verbose,"","Operating System Type is %s\n",VSYSNAME.sysname);
CfOut(cf_verbose,"","Operating System Release is %s\n",VSYSNAME.release);
CfOut(cf_verbose,"","Architecture = %s\n\n\n",VSYSNAME.machine);
CfOut(cf_verbose,"","Using internal soft-class %s for host %s\n\n",workbuf,VSYSNAME.nodename);
CfOut(cf_verbose,"","The time is now %s\n\n",cf_ctime(&tloc));
CfOut(cf_verbose,"","------------------------------------------------------------------------\n\n");
snprintf(workbuf,CF_MAXVARSIZE,"%s",cf_ctime(&tloc));
Chop(workbuf);
NewScalar("sys","date",workbuf,cf_str);
NewScalar("sys","cdate",CanonifyName(workbuf),cf_str);
NewScalar("sys","host",VSYSNAME.nodename,cf_str);
NewScalar("sys","uqhost",VUQNAME,cf_str);
NewScalar("sys","fqhost",VFQNAME,cf_str);
NewScalar("sys","os",VSYSNAME.sysname,cf_str);
NewScalar("sys","release",VSYSNAME.release,cf_str);
NewScalar("sys","version",VSYSNAME.version,cf_str);
NewScalar("sys","arch",VSYSNAME.machine,cf_str);
NewScalar("sys","workdir",CFWORKDIR,cf_str);
NewScalar("sys","fstab",VFSTAB[VSYSTEMHARDCLASS],cf_str);
NewScalar("sys","resolv",VRESOLVCONF[VSYSTEMHARDCLASS],cf_str);
NewScalar("sys","maildir",VMAILDIR[VSYSTEMHARDCLASS],cf_str);
NewScalar("sys","exports",VEXPORTS[VSYSTEMHARDCLASS],cf_str);
NewScalar("sys","expires",EXPIRY,cf_str);
/* FIXME: type conversion */
NewScalar("sys","cf_version",(char*)Version(),cf_str);
#ifdef HAVE_NOVA
/* FIXME: type conversion */
NewScalar("sys","nova_version",(char*)Nova_Version(),cf_str);
#endif
#ifdef HAVE_CONSTELLATION
/* FIXME: type conversion */
NewScalar("sys","constellation_version",(char*)Constellation_Version(),cf_str);
#endif
if (PUBKEY)
{
HashPubKey(PUBKEY,digest,CF_DEFAULT_DIGEST);
snprintf(PUBKEY_DIGEST, sizeof(PUBKEY_DIGEST), "%s", HashPrint(CF_DEFAULT_DIGEST,digest));
NewScalar("sys","key_digest",PUBKEY_DIGEST,cf_str);
snprintf(workbuf,CF_MAXVARSIZE-1,"PK_%s",CanonifyName(HashPrint(CF_DEFAULT_DIGEST,digest)));
NewClass(workbuf);
}
for (i = 0; components[i] != NULL; i++)
{
snprintf(shortname,CF_MAXVARSIZE-1,"%s",CanonifyName(components[i]));
if (VSYSTEMHARDCLASS == mingw || VSYSTEMHARDCLASS == cfnt)
{
// twin has own dir, and is named agent
if(i == 0)
{
snprintf(name,CF_MAXVARSIZE-1,"%s%cbin-twin%ccf-agent.exe",CFWORKDIR,FILE_SEPARATOR,FILE_SEPARATOR);
}
else
{
snprintf(name,CF_MAXVARSIZE-1,"%s%cbin%c%s.exe",CFWORKDIR,FILE_SEPARATOR,FILE_SEPARATOR,components[i]);
}
}
else
{
snprintf(name,CF_MAXVARSIZE-1,"%s%cbin%c%s",CFWORKDIR,FILE_SEPARATOR,FILE_SEPARATOR,components[i]);
}
have_component[i] = false;
if (cfstat(name, &sb) != -1)
{
snprintf(quoteName, sizeof(quoteName), "\"%s\"", name);
NewScalar("sys",shortname,quoteName,cf_str);
have_component[i] = true;
}
}
// If no twin, fail over the agent
if (!have_component[0])
{
snprintf(shortname,CF_MAXVARSIZE-1,"%s",CanonifyName(components[0]));
if (VSYSTEMHARDCLASS == mingw || VSYSTEMHARDCLASS == cfnt)
{
snprintf(name,CF_MAXVARSIZE-1,"%s%cbin%c%s.exe",CFWORKDIR,FILE_SEPARATOR,FILE_SEPARATOR,components[1]);
}
else
{
snprintf(name,CF_MAXVARSIZE-1,"%s%cbin%c%s",CFWORKDIR,FILE_SEPARATOR,FILE_SEPARATOR,components[1]);
}
if (cfstat(name, &sb) != -1)
{
snprintf(quoteName, sizeof(quoteName), "\"%s\"", name);
NewScalar("sys",shortname,quoteName,cf_str);
}
}
/* Windows special directories */
#ifdef MINGW
if(NovaWin_GetWinDir(workbuf, sizeof(workbuf)))
{
NewScalar("sys","windir",workbuf,cf_str);
}
if(NovaWin_GetSysDir(workbuf, sizeof(workbuf)))
{
NewScalar("sys","winsysdir",workbuf,cf_str);
}
if(NovaWin_GetProgDir(workbuf, sizeof(workbuf)))
{
NewScalar("sys","winprogdir",workbuf,cf_str);
}
# ifdef _WIN64
// only available on 64 bit windows systems
if(NovaWin_GetEnv("PROGRAMFILES(x86)", workbuf, sizeof(workbuf)))
{
NewScalar("sys","winprogdir86",workbuf,cf_str);
}
# else /* NOT _WIN64 */
NewScalar("sys","winprogdir86","",cf_str);
# endif
#else /* NOT MINGW */
// defs on Unix for manual-building purposes
NewScalar("sys","windir","/dev/null",cf_str);
NewScalar("sys","winsysdir","/dev/null",cf_str);
NewScalar("sys","winprogdir","/dev/null",cf_str);
NewScalar("sys","winprogdir86","/dev/null",cf_str);
#endif /* NOT MINGW */
LoadSlowlyVaryingObservations();
EnterpriseContext();
if (strlen(VDOMAIN) > 0)
{
NewScalar("sys","domain",VDOMAIN,cf_str);
}
else
{
NewScalar("sys","domain","undefined_domain",cf_str);
NewClass("undefined_domain");
}
sprintf(workbuf,"%d_bit",sizeof(long)*8);
NewClass(workbuf);
CfOut(cf_verbose,"","Additional hard class defined as: %s\n",CanonifyName(workbuf));
snprintf(workbuf,CF_BUFSIZE,"%s_%s",VSYSNAME.sysname,VSYSNAME.release);
NewClass(workbuf);
#ifdef IRIX
/* Get something like `irix64_6_5_19m' defined as well as
`irix64_6_5'. Just copying the latter into VSYSNAME.release
wouldn't be backwards-compatible. */
snprintf(workbuf,CF_BUFSIZE,"%s_%s",VSYSNAME.sysname,real_version);
NewClass(workbuf);
#endif
NewClass(VSYSNAME.machine);
CfOut(cf_verbose,"","Additional hard class defined as: %s\n",CanonifyName(workbuf));
snprintf(workbuf,CF_BUFSIZE,"%s_%s",VSYSNAME.sysname,VSYSNAME.machine);
NewClass(workbuf);
CfOut(cf_verbose,"","Additional hard class defined as: %s\n",CanonifyName(workbuf));
snprintf(workbuf,CF_BUFSIZE,"%s_%s_%s",VSYSNAME.sysname,VSYSNAME.machine,VSYSNAME.release);
NewClass(workbuf);
CfOut(cf_verbose,"","Additional hard class defined as: %s\n",CanonifyName(workbuf));
#ifdef HAVE_SYSINFO
#ifdef SI_ARCHITECTURE
sz = sysinfo(SI_ARCHITECTURE,workbuf,CF_BUFSIZE);
if (sz == -1)
{
CfOut(cf_verbose,"","cfengine internal: sysinfo returned -1\n");
}
else
{
NewClass(workbuf);
CfOut(cf_verbose,"","Additional hard class defined as: %s\n",workbuf);
}
#endif
#ifdef SI_PLATFORM
sz = sysinfo(SI_PLATFORM,workbuf,CF_BUFSIZE);
if (sz == -1)
{
CfOut(cf_verbose,"","cfengine internal: sysinfo returned -1\n");
}
else
{
NewClass(workbuf);
CfOut(cf_verbose,"","Additional hard class defined as: %s\n",workbuf);
}
#endif
#endif
snprintf(workbuf,CF_BUFSIZE,"%s_%s_%s_%s",VSYSNAME.sysname,VSYSNAME.machine,VSYSNAME.release,VSYSNAME.version);
if (strlen(workbuf) > CF_MAXVARSIZE-2)
{
CfOut(cf_verbose,"","cfengine internal: $(arch) overflows CF_MAXVARSIZE! Truncating\n");
}
sp = strdup(CanonifyName(workbuf));
NewScalar("sys","long_arch",sp,cf_str);
NewClass(sp);
free(sp);
snprintf(workbuf,CF_BUFSIZE,"%s_%s",VSYSNAME.sysname,VSYSNAME.machine);
sp = strdup(CanonifyName(workbuf));
NewScalar("sys","ostype",sp,cf_str);
NewClass(sp);
free(sp);
if (! found)
{
CfOut(cf_error,"","Cfengine: I don't understand what architecture this is!");
}
strcpy(workbuf,"compiled_on_");
strcat(workbuf,CanonifyName(AUTOCONF_SYSNAME));
NewClass(workbuf);
CfOut(cf_verbose,"","GNU autoconf class from compile time: %s",workbuf);
/* Get IP address from nameserver */
if ((hp = gethostbyname(VFQNAME)) == NULL)
{
CfOut(cf_verbose,"","Hostname lookup failed on node name \"%s\"\n",VSYSNAME.nodename);
return;
}
else
{
memset(&cin,0,sizeof(cin));
cin.sin_addr.s_addr = ((struct in_addr *)(hp->h_addr))->s_addr;
CfOut(cf_verbose,"","Address given by nameserver: %s\n",inet_ntoa(cin.sin_addr));
strcpy(VIPADDRESS,inet_ntoa(cin.sin_addr));
for (i = 0; hp->h_aliases[i]!= NULL; i++)
{
Debug("Adding alias %s..\n",hp->h_aliases[i]);
NewClass(hp->h_aliases[i]);
}
}
}
/*********************************************************************/
void CfGetInterfaceInfo(enum cfagenttype ag)
#ifdef MINGW
{
NovaWin_GetInterfaceInfo();
}
#else
{
Unix_GetInterfaceInfo(ag);
Unix_FindV6InterfaceInfo();
}
#endif /* NOT MINGW */
/*********************************************************************/
void Get3Environment()
{ char env[CF_BUFSIZE],class[CF_BUFSIZE],name[CF_MAXVARSIZE],value[CF_MAXVARSIZE];
FILE *fp;
struct stat statbuf;
time_t now = time(NULL);
CfOut(cf_verbose,"","Looking for environment from cf-monitord...\n");
snprintf(env,CF_BUFSIZE,"%s/state/%s",CFWORKDIR,CF_ENV_FILE);
MapName(env);
if (cfstat(env,&statbuf) == -1)
{
CfOut(cf_verbose,"","Unable to detect environment from cf-monitord\n\n");
return;
}
if (statbuf.st_mtime < (now - 60*60))
{
CfOut(cf_verbose,"","Environment data are too old - discarding\n");
unlink(env);
return;
}
snprintf(value,CF_MAXVARSIZE-1,"%s",cf_ctime(&statbuf.st_mtime));
Chop(value);
DeleteVariable("mon","env_time");
NewScalar("mon","env_time",value,cf_str);
CfOut(cf_verbose,"","Loading environment...\n");
if ((fp = fopen(env,"r")) == NULL)
{
CfOut(cf_verbose,"","\nUnable to detect environment from cf-monitord\n\n");
return;
}
while (!feof(fp))
{
class[0] = '\0';
name[0] = '\0';
value[0] = '\0';
fgets(class,CF_BUFSIZE-1,fp);
if (feof(fp))
{
break;
}
if (strstr(class,"="))
{
sscanf(class,"%255[^=]=%255[^\n]",name,value);
if (THIS_AGENT_TYPE != cf_executor)
{
DeleteVariable("mon",name);
NewScalar("mon",name,value,cf_str);
Debug(" -> Setting new monitoring scalar %s => %s",name,value);
}
}
else
{
NewClass(class);
}
}
fclose(fp);
CfOut(cf_verbose,"","Environment data loaded\n\n");
}
/*******************************************************************/
int IsInterfaceAddress(char *adr)
/* Does this address belong to a local interface */
{ struct Item *ip;
for (ip = IPADDRESSES; ip != NULL; ip=ip->next)
{
if (StrnCmp(adr,ip->name,strlen(adr)) == 0)
{
Debug("Identifying (%s) as one of my interfaces\n",adr);
return true;
}
}
Debug("(%s) is not one of my interfaces\n",adr);
return false;
}
/*********************************************************************/
static void FindDomainName(char *hostname)
{ char fqn[CF_MAXVARSIZE] = {0};
char *ptr;
char buffer[CF_BUFSIZE];
strcpy(VFQNAME,hostname); /* By default VFQNAME = hostname (nodename) */
if (strstr(VFQNAME,".") == 0)
{
/* The nodename is not full qualified - try to find the FQDN hostname */
if (gethostname(fqn, sizeof(fqn)) != -1)
{
struct hostent *hp;
if ((hp = gethostbyname(fqn)))
{
if (strstr(hp->h_name,"."))
{
/* We find a FQDN hostname So we change the VFQNAME variable */
strncpy(VFQNAME,hp->h_name,CF_MAXVARSIZE);
VFQNAME[CF_MAXVARSIZE-1]= '\0';
}
}
}
}
strcpy(buffer,VFQNAME);
NewClass(buffer);
NewClass(ToLowerStr(buffer));
if (strstr(VFQNAME,"."))
{
/* If VFQNAME is full qualified we can create VDOMAIN variable */
ptr = strchr(VFQNAME, '.');
strcpy(VDOMAIN, ++ptr);
DeleteClass("undefined_domain");
}
if (strstr(VFQNAME,".") == 0 && (strcmp(VDOMAIN,CF_START_DOMAIN) != 0))
{
strcat(VFQNAME,".");
strcat(VFQNAME,VDOMAIN);
}
if (strstr(VFQNAME,"."))
{
/* Add some domain hierarchy classes */
for (ptr=VFQNAME; *ptr != '\0'; ptr++)
{
if (*ptr == '.')
{
if (*(ptr+1) != '\0')
{
Debug("Defining domain #%s#\n",(ptr+1));
NewClass(ptr+1);
}
else
{
Debug("Domain rejected\n");
}
}
}
}
NewClass(VDOMAIN);
}
/*******************************************************************/
void BuiltinClasses(void)
{
char vbuff[CF_BUFSIZE];
char *sp;
NewClass("any"); /* This is a reserved word / wildcard */
snprintf(vbuff,CF_BUFSIZE,"cfengine_%s",CanonifyName(Version()));
NewClass(vbuff);
while ((sp = strrchr(vbuff, '_')))
{
*sp = 0;
NewClass(vbuff);
}
}
/*******************************************************************/
void OSClasses()
{ struct stat statbuf;
char vbuff[CF_BUFSIZE];
char *sp;
struct passwd *pw;
#ifndef LINUX
char class[CF_BUFSIZE];
#endif
#ifdef LINUX
/* Mandrake/Mandriva, Fedora and Oracle VM Server supply /etc/redhat-release, so
we test for those distributions first */
if (cfstat("/etc/mandriva-release",&statbuf) != -1)
{
Linux_Mandriva_Version();
}
else if (cfstat("/etc/mandrake-release",&statbuf) != -1)
{
Linux_Mandrake_Version();
}
else if (cfstat("/etc/fedora-release",&statbuf) != -1)
{
Linux_Fedora_Version();
}
else if (cfstat("/etc/ovs-release",&statbuf) != -1)
{
Linux_Oracle_VM_Server_Version();
}
else if (cfstat("/etc/redhat-release",&statbuf) != -1)
{
Linux_Redhat_Version();
}
/* Oracle Linux >= 6 supplies separate /etc/oracle-release alongside
/etc/redhat-release, use it to precisely identify version */
if (cfstat("/etc/oracle-release",&statbuf) != -1)
{
Linux_Oracle_Version();
}
if (cfstat("/etc/generic-release",&statbuf) != -1)
{
CfOut(cf_verbose,"","This appears to be a sun cobalt system.\n");
NewClass("SunCobalt");
}
if (cfstat("/etc/SuSE-release",&statbuf) != -1)
{
Linux_Suse_Version();
}
#define SLACKWARE_ANCIENT_VERSION_FILENAME "/etc/slackware-release"
#define SLACKWARE_VERSION_FILENAME "/etc/slackware-version"
if (cfstat(SLACKWARE_VERSION_FILENAME,&statbuf) != -1)
{
Linux_Slackware_Version(SLACKWARE_VERSION_FILENAME);
}
else if (cfstat(SLACKWARE_ANCIENT_VERSION_FILENAME,&statbuf) != -1)
{
Linux_Slackware_Version(SLACKWARE_ANCIENT_VERSION_FILENAME);
}
if (cfstat("/etc/generic-release",&statbuf) != -1)
{
CfOut(cf_verbose,"","This appears to be a sun cobalt system.\n");
NewClass("SunCobalt");
}
if (cfstat("/etc/debian_version",&statbuf) != -1)
{
Linux_Debian_Version();
}
if (cfstat("/usr/bin/aptitude",&statbuf) != -1)
{
CfOut(cf_verbose,"","This system seems to have the aptitude package system\n");
NewClass("have_aptitude");
}
if (cfstat("/etc/UnitedLinux-release",&statbuf) != -1)
{
CfOut(cf_verbose,"","This appears to be a UnitedLinux system.\n");
NewClass("UnitedLinux");
}
if (cfstat("/etc/gentoo-release",&statbuf) != -1)
{
CfOut(cf_verbose,"","This appears to be a gentoo system.\n");
NewClass("gentoo");
}
#else
strncpy(vbuff,VSYSNAME.release,CF_MAXVARSIZE);
for (sp = vbuff; *sp != '\0'; sp++)
{
if (*sp == '-')
{
*sp = '\0';
break;
}
}
snprintf(class,CF_BUFSIZE,"%s_%s",VSYSNAME.sysname,vbuff);
NewScalar("sys","flavour",class,cf_str);
NewScalar("sys","flavor",class,cf_str);
#endif
if (cfstat("/proc/vmware/version",&statbuf) != -1 ||
cfstat("/etc/vmware-release",&statbuf) != -1)
{
VM_Version();
}
else if (cfstat("/etc/vmware",&statbuf) != -1 && S_ISDIR(statbuf.st_mode))
{
VM_Version();
}
if (cfstat("/proc/xen/capabilities",&statbuf) != -1)
{
Xen_Domain();
}
#ifdef XEN_CPUID_SUPPORT
else if (Xen_Hv_Check())
{
CfOut(cf_verbose,"","This appears to be a xen hv system.\n");
NewClass("xen");
NewClass("xen_domu_hv");
}
#endif
#ifdef CFCYG
for (sp = VSYSNAME.sysname; *sp != '\0'; sp++)
{
if (*sp == '-')
{
sp++;
if (strncmp(sp,"5.0",3) == 0)
{
CfOut(cf_verbose,"","This appears to be Windows 2000\n");
NewClass("Win2000");
}
if (strncmp(sp,"5.1",3) == 0)
{
CfOut(cf_verbose,"","This appears to be Windows XP\n");
NewClass("WinXP");
}
if (strncmp(sp,"5.2",3) == 0)
{
CfOut(cf_verbose,"","This appears to be Windows Server 2003\n");
NewClass("WinServer2003");
}
if (strncmp(sp,"6.1",3) == 0)
{
CfOut(cf_verbose,"","This appears to be Windows Vista\n");
NewClass("WinVista");
}
if (strncmp(sp,"6.3",3) == 0)
{
CfOut(cf_verbose,"","This appears to be Windows Server 2008\n");
NewClass("WinServer2008");
}
}
}
NewScalar("sys","crontab","",cf_str);
#endif /* CFCYG */
#ifdef MINGW
NewClass(VSYSNAME.release); // code name - e.g. Windows Vista
NewClass(VSYSNAME.version); // service pack number - e.g. Service Pack 3
if (strstr(VSYSNAME.sysname, "workstation"))
{
NewClass("WinWorkstation");
}
else if(strstr(VSYSNAME.sysname, "server"))
{
NewClass("WinServer");
}
else if(strstr(VSYSNAME.sysname, "domain controller"))
{
NewClass("DomainController");
NewClass("WinServer");
}
else
{
NewClass("unknown_ostype");
}
NewScalar("sys","flavour","windows",cf_str);
NewScalar("sys","flavor","windows",cf_str);
#endif /* MINGW */
#ifndef NT
if ((pw = getpwuid(getuid())) == NULL)
{
CfOut(cf_error,"getpwuid"," !! Unable to get username for uid %d",getuid);
}
else
{
if (IsDefinedClass("SuSE"))
{
snprintf(vbuff,CF_BUFSIZE,"/var/spool/cron/tabs/%s",pw->pw_name);
}
else
{
snprintf(vbuff,CF_BUFSIZE,"/var/spool/cron/crontabs/%s",pw->pw_name);
}
}
NewScalar("sys","crontab",vbuff,cf_str);
#endif
#if defined(HAVE_NOVA)
Nova_SaveDocumentRoot();
#endif
}
/*********************************************************************************/
static void Linux_Oracle_VM_Server_Version(void)
{
char relstring[CF_MAXVARSIZE];
char *r;
int major, minor, patch;
int revcomps;
#define ORACLE_VM_SERVER_REL_FILENAME "/etc/ovs-release"
#define ORACLE_VM_SERVER_ID "Oracle VM server"
CfOut(cf_verbose,"","This appears to be Oracle VM Server");
NewClass("redhat");
NewClass("oraclevmserver");
if (!ReadLine(ORACLE_VM_SERVER_REL_FILENAME, relstring, sizeof(relstring)))
{
return;
}
if (strncmp(relstring, ORACLE_VM_SERVER_ID, strlen(ORACLE_VM_SERVER_ID)))
{
CfOut(cf_verbose, "", "Could not identify distribution from %s\n",
ORACLE_VM_SERVER_REL_FILENAME);
return;
}
if ((r = strstr(relstring, "release ")) == NULL)
{
CfOut(cf_verbose, "", "Could not find distribution version in %s\n",
ORACLE_VM_SERVER_REL_FILENAME);
return;
}
revcomps = sscanf(r + strlen("release "), "%d.%d.%d", &major, &minor, &patch);
if (revcomps > 0)
{
char buf[CF_BUFSIZE];
snprintf(buf, CF_BUFSIZE, "oraclevmserver_%d", major);
NewClass(buf);
NewScalar("sys", "flavour", buf, cf_str);
NewScalar("sys", "flavor", buf, cf_str);
}
if (revcomps > 1)
{
char buf[CF_BUFSIZE];
snprintf(buf, CF_BUFSIZE, "oraclevmserver_%d_%d", major, minor);
NewClass(buf);
}
if (revcomps > 2)
{
char buf[CF_BUFSIZE];
snprintf(buf, CF_BUFSIZE, "oraclevmserver_%d_%d_%d", major, minor, patch);
NewClass(buf);
}
}
/*********************************************************************************/
static void Linux_Oracle_Version(void)
{
char relstring[CF_MAXVARSIZE];
char *r;
int major, minor;
#define ORACLE_REL_FILENAME "/etc/oracle-release"
#define ORACLE_ID "Oracle Linux Server"
CfOut(cf_verbose,"","This appears to be Oracle Linux");
NewClass("oracle");
if (!ReadLine(ORACLE_REL_FILENAME, relstring, sizeof(relstring)))
{
return;
}
if (strncmp(relstring, ORACLE_ID, strlen(ORACLE_ID)))
{
CfOut(cf_verbose, "", "Could not identify distribution from %s\n", ORACLE_REL_FILENAME);
return;
}
if ((r = strstr(relstring, "release ")) == NULL)
{
CfOut(cf_verbose, "", "Could not find distribution version in %s\n", ORACLE_REL_FILENAME);
return;
}
if (sscanf(r + strlen("release "), "%d.%d", &major, &minor) == 2)
{
char buf[CF_BUFSIZE];
snprintf(buf, CF_BUFSIZE, "oracle_%d", major);
NewClass(buf);
NewScalar("sys", "flavour", buf, cf_str);
NewScalar("sys", "flavor", buf, cf_str);
snprintf(buf, CF_BUFSIZE, "oracle_%d_%d", major, minor);
NewClass(buf);
}
}
/*********************************************************************************/
static int Linux_Fedora_Version(void)
{
#define FEDORA_ID "Fedora"
#define RELEASE_FLAG "release "
/* We are looking for one of the following strings...
*
* Fedora Core release 1 (Yarrow)
* Fedora release 7 (Zodfoobar)
*/
#define FEDORA_REL_FILENAME "/etc/fedora-release"
/* The full string read in from fedora-release */
char relstring[CF_MAXVARSIZE];
char classbuf[CF_MAXVARSIZE];
char *vendor="";
char *release=NULL;
int major = -1;
char strmajor[CF_MAXVARSIZE];
CfOut(cf_verbose,"","This appears to be a fedora system.\n");
NewClass("redhat");
NewClass("fedora");
/* Grab the first line from the file and then close it. */
if (!ReadLine(FEDORA_REL_FILENAME, relstring, sizeof(relstring)))
{
return 1;
}
CfOut(cf_verbose,"","Looking for fedora core linux info...\n");
if (!strncmp(relstring, FEDORA_ID, strlen(FEDORA_ID)))
{
vendor = "fedora";
}
else
{
CfOut(cf_verbose,"","Could not identify OS distro from %s\n", FEDORA_REL_FILENAME);
return 2;
}
/* Now, grok the release. We assume that all the strings will
* have the word 'release' before the numerical release.
*/
release = strstr(relstring, RELEASE_FLAG);
if (release == NULL)
{
CfOut(cf_verbose,"","Could not find a numeric OS release in %s\n",FEDORA_REL_FILENAME);
return 2;
}
else
{
release += strlen(RELEASE_FLAG);
if (sscanf(release, "%d", &major) != 0)
{
sprintf(strmajor, "%d", major);
}
}
if (major != -1 && (strcmp(vendor,"") != 0))
{
classbuf[0] = '\0';
strcat(classbuf, vendor);
NewClass(classbuf);
strcat(classbuf, "_");
strcat(classbuf, strmajor);
NewClass(classbuf);
NewScalar("sys","flavour",classbuf,cf_str);
NewScalar("sys","flavor",classbuf,cf_str);
}
return 0;
}
/*********************************************************************************/
static int Linux_Redhat_Version(void)
{
#define REDHAT_ID "Red Hat Linux"
#define REDHAT_AS_ID "Red Hat Enterprise Linux AS"
#define REDHAT_AS21_ID "Red Hat Linux Advanced Server"
#define REDHAT_ES_ID "Red Hat Enterprise Linux ES"
#define REDHAT_WS_ID "Red Hat Enterprise Linux WS"
#define REDHAT_C_ID "Red Hat Enterprise Linux Client"
#define REDHAT_S_ID "Red Hat Enterprise Linux Server"
#define REDHAT_W_ID "Red Hat Enterprise Linux Workstation"
#define MANDRAKE_ID "Linux Mandrake"
#define MANDRAKE_10_1_ID "Mandrakelinux"
#define WHITEBOX_ID "White Box Enterprise Linux"
#define CENTOS_ID "CentOS"
#define SCIENTIFIC_SL_ID "Scientific Linux SL"
#define SCIENTIFIC_SL6_ID "Scientific Linux"
#define SCIENTIFIC_CERN_ID "Scientific Linux CERN"
#define RELEASE_FLAG "release "
#define ORACLE_4_5_ID "Enterprise Linux Enterprise Linux Server"
/* We are looking for one of the following strings...
*
* Red Hat Linux release 6.2 (Zoot)
* Red Hat Linux Advanced Server release 2.1AS (Pensacola)
* Red Hat Enterprise Linux AS release 3 (Taroon)
* Red Hat Enterprise Linux WS release 3 (Taroon)
* Red Hat Enterprise Linux Client release 5 (Tikanga)
* Red Hat Enterprise Linux Server release 5 (Tikanga)
* Linux Mandrake release 7.1 (helium)
* Red Hat Enterprise Linux ES release 2.1 (Panama)
* White Box Enterprise linux release 3.0 (Liberation)
* Scientific Linux SL Release 4.0 (Beryllium)
* CentOS release 4.0 (Final)
*/
#define RH_REL_FILENAME "/etc/redhat-release"
/* The full string read in from redhat-release */
char relstring[CF_MAXVARSIZE];
char classbuf[CF_MAXVARSIZE];
/* Red Hat, Mandrake */
char *vendor="";
/* as (Advanced Server, Enterprise) */
char *edition="";
/* Where the numerical release will be found */
char *release=NULL;
int i;
int major = -1;
char strmajor[CF_MAXVARSIZE];
int minor = -1;
char strminor[CF_MAXVARSIZE];
CfOut(cf_verbose,"","This appears to be a redhat (or redhat-based) system.\n");
NewClass("redhat");
/* Grab the first line from the file and then close it. */
if (!ReadLine(RH_REL_FILENAME, relstring, sizeof(relstring)))
{
return 1;
}
CfOut(cf_verbose,"","Looking for redhat linux info in \"%s\"\n",relstring);
/* First, try to grok the vendor and the edition (if any) */
if (!strncmp(relstring, REDHAT_ES_ID, strlen(REDHAT_ES_ID)))
{
vendor = "redhat";
edition = "es";
}
else if(!strncmp(relstring, REDHAT_WS_ID, strlen(REDHAT_WS_ID)))
{
vendor = "redhat";
edition = "ws";
}
else if(!strncmp(relstring, REDHAT_WS_ID, strlen(REDHAT_WS_ID)))
{
vendor = "redhat";
edition = "ws";
}
else if(!strncmp(relstring, REDHAT_AS_ID, strlen(REDHAT_AS_ID)) ||
!strncmp(relstring, REDHAT_AS21_ID, strlen(REDHAT_AS21_ID)))
{
vendor = "redhat";
edition = "as";
}
else if(!strncmp(relstring, REDHAT_S_ID, strlen(REDHAT_S_ID)))
{
vendor = "redhat";
edition = "s";
}
else if(!strncmp(relstring, REDHAT_C_ID, strlen(REDHAT_C_ID)) || !strncmp(relstring, REDHAT_W_ID, strlen(REDHAT_W_ID)))
{
vendor = "redhat";
edition = "c";
}
else if(!strncmp(relstring, REDHAT_ID, strlen(REDHAT_ID)))
{
vendor = "redhat";
}
else if(!strncmp(relstring, MANDRAKE_ID, strlen(MANDRAKE_ID)))
{
vendor = "mandrake";
}
else if(!strncmp(relstring, MANDRAKE_10_1_ID, strlen(MANDRAKE_10_1_ID)))
{
vendor = "mandrake";
}
else if(!strncmp(relstring, WHITEBOX_ID, strlen(WHITEBOX_ID)))
{
vendor = "whitebox";
}
else if(!strncmp(relstring, SCIENTIFIC_SL_ID, strlen(SCIENTIFIC_SL_ID)))
{
vendor = "scientific";
edition = "sl";
}
else if(!strncmp(relstring, SCIENTIFIC_CERN_ID, strlen(SCIENTIFIC_CERN_ID)))
{
vendor = "scientific";
edition = "cern";
}
else if(!strncmp(relstring, SCIENTIFIC_SL6_ID, strlen(SCIENTIFIC_SL6_ID)))
{
vendor = "scientific";
edition = "sl";
}
else if(!strncmp(relstring, CENTOS_ID, strlen(CENTOS_ID)))
{
vendor = "centos";
}
else if (!strncmp(relstring, ORACLE_4_5_ID, strlen(ORACLE_4_5_ID)))
{
vendor = "oracle";
edition = "s";
}
else
{
CfOut(cf_verbose,"","Could not identify OS distro from %s\n", RH_REL_FILENAME);
return 2;
}
/* Now, grok the release. For AS, we neglect the AS at the end of the
* numerical release because we already figured out that it *is* AS
* from the infomation above. We assume that all the strings will
* have the word 'release' before the numerical release.
*/
/* Convert relstring to lowercase so that vendors like
Scientific Linux don't fall through the cracks.
*/
for (i = 0; i < strlen(relstring); i++)
{
relstring[i] = tolower(relstring[i]);
}
release = strstr(relstring, RELEASE_FLAG);
if (release == NULL)
{
CfOut(cf_verbose,"","Could not find a numeric OS release in %s\n", RH_REL_FILENAME);
return 2;
}
else
{
release += strlen(RELEASE_FLAG);
if (sscanf(release, "%d.%d", &major, &minor) == 2)
{
sprintf(strmajor, "%d", major);
sprintf(strminor, "%d", minor);
}
/* red hat 9 is *not* red hat 9.0.
* and same thing with RHEL AS 3
*/
else if (sscanf(release, "%d", &major) == 1)
{
sprintf(strmajor, "%d", major);
minor = -2;
}
}
if (major != -1 && minor != -1 && (strcmp(vendor,"") != 0))
{
classbuf[0] = '\0';
strcat(classbuf, vendor);
NewClass(classbuf);
strcat(classbuf, "_");
if (strcmp(edition,"") != 0)
{
strcat(classbuf, edition);
NewClass(classbuf);
strcat(classbuf, "_");
}
strcat(classbuf, strmajor);
NewClass(classbuf);
if (minor != -2)
{
strcat(classbuf, "_");
strcat(classbuf, strminor);
NewClass(classbuf);
}
}
// Now a version without the edition
if (major != -1 && minor != -1 && (strcmp(vendor,"") != 0))
{
classbuf[0] = '\0';
strcat(classbuf, vendor);
NewClass(classbuf);
strcat(classbuf, "_");
strcat(classbuf, strmajor);
NewClass(classbuf);
NewScalar("sys","flavour",classbuf,cf_str);
NewScalar("sys","flavor",classbuf,cf_str);
if (minor != -2)
{
strcat(classbuf, "_");
strcat(classbuf, strminor);
NewClass(classbuf);
}
}
return 0;
}
/******************************************************************/
static int Linux_Suse_Version(void)
{
#define SUSE_REL_FILENAME "/etc/SuSE-release"
/* Check if it's a SuSE Enterprise version (all in lowercase) */
#define SUSE_SLES8_ID "suse sles-8"
#define SUSE_SLES_ID "suse linux enterprise server"
#define SUSE_SLED_ID "suse linux enterprise desktop"
#define SUSE_RELEASE_FLAG "linux "
/* The full string read in from SuSE-release */
char relstring[CF_MAXVARSIZE];
char classbuf[CF_MAXVARSIZE];
char vbuf[CF_BUFSIZE],strversion[CF_MAXVARSIZE],strpatch[CF_MAXVARSIZE];
/* Where the numerical release will be found */
char *release=NULL;
int i,version;
int major = -1;
char strmajor[CF_MAXVARSIZE];
int minor = -1;
char strminor[CF_MAXVARSIZE];
FILE *fp;
CfOut(cf_verbose,"","This appears to be a SuSE system.\n");
NewClass("SuSE");
/* Grab the first line from the file and then close it. */
fp = ReadFirstLine(SUSE_REL_FILENAME, relstring, sizeof(relstring));
if (fp == NULL)
{
return 1;
}
strversion[0] = '\0';
strpatch[0] = '\0';
while (!feof(fp))
{
fgets(vbuf,sizeof(vbuf),fp);
if (strncmp(vbuf,"VERSION",strlen("version")) == 0)
{
strncpy(strversion,vbuf,sizeof(strversion));
sscanf(strversion,"VERSION = %d",&major);
}
if (strncmp(vbuf,"PATCH",strlen("PATCH")) == 0)
{
strncpy(strpatch,vbuf,sizeof(strpatch));
sscanf(strpatch,"PATCHLEVEL = %d",&minor);
}
}
fclose(fp);
/* Check if it's a SuSE Enterprise version */
CfOut(cf_verbose,"","Looking for SuSE enterprise info in \"%s\"\n",relstring);
/* Convert relstring to lowercase to handle rename of SuSE to
* SUSE with SUSE 10.0.
*/
for (i = 0; i < strlen(relstring); i++)
{
relstring[i] = tolower(relstring[i]);
}
/* Check if it's a SuSE Enterprise version (all in lowercase) */
if (!strncmp(relstring, SUSE_SLES8_ID, strlen(SUSE_SLES8_ID)))
{
classbuf[0] = '\0';
strcat(classbuf, "SLES8");
NewClass(classbuf);
}
else if (strncmp(relstring,"sles",4) == 0)
{
struct Item *list, *ip;
sscanf(relstring,"%[-_a-zA-Z0-9]",vbuf);
NewClass(vbuf);
list = SplitString(vbuf,'-');
for (ip = list; ip != NULL; ip=ip->next)
{
NewClass(ip->name);
}
DeleteItemList(list);
}
else
{
for (version = 9; version < 13; version++)
{
snprintf(vbuf,CF_BUFSIZE,"%s %d ",SUSE_SLES_ID,version);
Debug("Checking for suse [%s]\n",vbuf);
if (!strncmp(relstring, vbuf, strlen(vbuf)))
{
snprintf(classbuf,CF_MAXVARSIZE,"SLES%d",version);
NewClass(classbuf);
}
else
{
snprintf(vbuf,CF_BUFSIZE,"%s %d ",SUSE_SLED_ID,version);
Debug("Checking for suse [%s]\n",vbuf);
if (!strncmp(relstring, vbuf, strlen(vbuf)))
{
snprintf(classbuf,CF_MAXVARSIZE,"SLED%d",version);
NewClass(classbuf);
}
}
}
}
/* Determine release version. We assume that the version follows
* the string "SuSE Linux" or "SUSE LINUX".
*/
release = strstr(relstring, SUSE_RELEASE_FLAG);
if (release == NULL)
{
release = strstr(relstring,"opensuse");
}
if (release == NULL)
{
release = strversion;
}
if (release == NULL)
{
CfOut(cf_verbose,"","Could not find a numeric OS release in %s\n",SUSE_REL_FILENAME);
return 2;
}
else
{
if (strchr(release,'.'))
{
sscanf(release, "%*s %d.%d", &major, &minor);
sprintf(strmajor, "%d", major);
sprintf(strminor, "%d", minor);
if (major != -1 && minor != -1)
{
strcpy(classbuf, "SuSE");
NewClass(classbuf);
strcat(classbuf, "_");
strcat(classbuf, strmajor);
NewClass(classbuf);
NewScalar("sys","flavour",classbuf,cf_str);
NewScalar("sys","flavor",classbuf,cf_str);
strcat(classbuf, "_");
strcat(classbuf, strminor);
NewClass(classbuf);
CfOut(cf_verbose,""," -> Discovered SuSE version %s",classbuf);
return 0;
}
}
else
{
sscanf(strversion,"VERSION = %s",strmajor);
sscanf(strpatch,"PATCHLEVEL = %s",strminor);
if (major != -1 && minor != -1)
{
strcpy(classbuf, "SLES");
NewClass(classbuf);
strcat(classbuf, "_");
strcat(classbuf, strmajor);
NewClass(classbuf);
strcat(classbuf, "_");
strcat(classbuf, strminor);
NewClass(classbuf);
snprintf(classbuf,CF_MAXVARSIZE,"SuSE_%d",major);
NewScalar("sys","flavour",classbuf,cf_str);
NewScalar("sys","flavor",classbuf,cf_str);
NewClass(classbuf);
CfOut(cf_verbose,""," -> Discovered SuSE version %s",classbuf);
return 0;
}
}
}
CfOut(cf_verbose,"","Could not find a numeric OS release in %s\n",SUSE_REL_FILENAME);
return 0;
}
/******************************************************************/
static int Linux_Slackware_Version(char *filename)
{
int major = -1;
int minor = -1;
int release = -1;
char classname[CF_MAXVARSIZE] = "";
char buffer[CF_MAXVARSIZE];
CfOut(cf_verbose,"","This appears to be a slackware system.\n");
NewClass("slackware");
if (!ReadLine(filename, buffer, sizeof(buffer)))
{
return 1;
}
CfOut(cf_verbose,"","Looking for Slackware version...\n");
switch (sscanf(buffer, "Slackware %d.%d.%d", &major, &minor, &release))
{
case 3:
CfOut(cf_verbose,"","This appears to be a Slackware %u.%u.%u system.", major, minor, release);
snprintf(classname, CF_MAXVARSIZE, "slackware_%u_%u_%u", major, minor, release);
NewClass(classname);
/* Fall-through */
case 2:
CfOut(cf_verbose,"","This appears to be a Slackware %u.%u system.", major, minor);
snprintf(classname, CF_MAXVARSIZE, "slackware_%u_%u", major, minor);
NewClass(classname);
/* Fall-through */
case 1:
CfOut(cf_verbose,"","This appears to be a Slackware %u system.", major);
snprintf(classname, CF_MAXVARSIZE, "slackware_%u", major);
NewClass(classname);
break;
case 0:
CfOut(cf_verbose,"","No Slackware version number found.\n");
return 2;
}
return 0;
}
/******************************************************************/
static int Linux_Debian_Version(void)
{
#define DEBIAN_VERSION_FILENAME "/etc/debian_version"
#define DEBIAN_ISSUE_FILENAME "/etc/issue"
int major = -1;
int release = -1;
int result;
char classname[CF_MAXVARSIZE],buffer[CF_MAXVARSIZE],os[CF_MAXVARSIZE],version[CF_MAXVARSIZE];
CfOut(cf_verbose,"","This appears to be a debian system.\n");
NewClass("debian");
buffer[0] = classname[0] = '\0';
CfOut(cf_verbose,"","Looking for Debian version...\n");
if (!ReadLine(DEBIAN_VERSION_FILENAME, buffer, sizeof(buffer)))
{
return 1;
}
result = sscanf(buffer,"%d.%d", &major, &release);
switch (result)
{
case 2:
CfOut(cf_verbose,"","This appears to be a Debian %u.%u system.", major, release);
snprintf(classname, CF_MAXVARSIZE, "debian_%u_%u", major, release);
NewClass(classname);
snprintf(classname, CF_MAXVARSIZE, "debian_%u",major);
NewClass(classname);
NewScalar("sys","flavour",classname,cf_str);
NewScalar("sys","flavor",classname,cf_str);
break;
/* Fall-through */
case 1:
CfOut(cf_verbose,"","This appears to be a Debian %u system.", major);
snprintf(classname, CF_MAXVARSIZE, "debian_%u", major);
NewClass(classname);
NewScalar("sys","flavour",classname,cf_str);
NewScalar("sys","flavor",classname,cf_str);
break;
default:
version[0] = '\0';
sscanf(buffer,"%25[^/]",version);
if (strlen(version) > 0)
{
snprintf(classname,CF_MAXVARSIZE, "debian_%s",version);
NewClass(classname);
}
break;
}
if (!ReadLine(DEBIAN_ISSUE_FILENAME, buffer, sizeof(buffer)))
{
return 1;
}
os[0] = '\0';
sscanf(buffer,"%250s",os);
if (strcmp(os,"Debian") == 0)
{
sscanf(buffer,"%*s %*s %[^/]",version);
snprintf(buffer,CF_MAXVARSIZE, "debian_%s",version);
NewClass("debian");
NewClass(buffer);
NewScalar("sys","flavour",buffer,cf_str);
NewScalar("sys","flavor",buffer,cf_str);
}
else if (strcmp(os,"Ubuntu") == 0)
{
sscanf(buffer,"%*s %[^.].%d",version,&release);
snprintf(buffer,CF_MAXVARSIZE, "ubuntu_%s",version);
NewScalar("sys","flavour",buffer,cf_str);
NewScalar("sys","flavor",buffer,cf_str);
NewClass("ubuntu");
NewClass(buffer);
if (release >= 0)
{
snprintf(buffer,CF_MAXVARSIZE, "ubuntu_%s_%d",version,release);
NewClass(buffer);
}
}
return 0;
}
/******************************************************************/
static int Linux_Mandrake_Version(void)
{
/* We are looking for one of the following strings... */
#define MANDRAKE_ID "Linux Mandrake"
#define MANDRAKE_REV_ID "Mandrake Linux"
#define MANDRAKE_10_1_ID "Mandrakelinux"
#define MANDRAKE_REL_FILENAME "/etc/mandrake-release"
char relstring[CF_MAXVARSIZE];
char *vendor=NULL;
CfOut(cf_verbose,"","This appears to be a mandrake system.\n");
NewClass("Mandrake");
if (!ReadLine(MANDRAKE_REL_FILENAME, relstring, sizeof(relstring)))
{
return 1;
}
CfOut(cf_verbose,"","Looking for Mandrake linux info in \"%s\"\n",relstring);
/* Older Mandrakes had the 'Mandrake Linux' string in reverse order */
if(!strncmp(relstring, MANDRAKE_ID, strlen(MANDRAKE_ID)))
{
vendor = "mandrake";
}
else if(!strncmp(relstring, MANDRAKE_REV_ID, strlen(MANDRAKE_REV_ID)))
{
vendor = "mandrake";
}
else if(!strncmp(relstring, MANDRAKE_10_1_ID, strlen(MANDRAKE_10_1_ID)))
{
vendor = "mandrake";
}
else
{
CfOut(cf_verbose,"","Could not identify OS distro from %s\n", MANDRAKE_REL_FILENAME);
return 2;
}
return Linux_Mandriva_Version_Real(MANDRAKE_REL_FILENAME, relstring, vendor);
}
/******************************************************************/
static int Linux_Mandriva_Version(void)
{
/* We are looking for the following strings... */
#define MANDRIVA_ID "Mandriva Linux"
#define MANDRIVA_REL_FILENAME "/etc/mandriva-release"
char relstring[CF_MAXVARSIZE];
char *vendor=NULL;
CfOut(cf_verbose,"","This appears to be a mandriva system.\n");
NewClass("Mandrake");
NewClass("Mandriva");
if (!ReadLine(MANDRIVA_REL_FILENAME, relstring, sizeof(relstring)))
{
return 1;
}
CfOut(cf_verbose,"","Looking for Mandriva linux info in \"%s\"\n",relstring);
if(!strncmp(relstring, MANDRIVA_ID, strlen(MANDRIVA_ID)))
{
vendor = "mandriva";
}
else
{
CfOut(cf_verbose,"","Could not identify OS distro from %s\n", MANDRIVA_REL_FILENAME);
return 2;
}
return Linux_Mandriva_Version_Real(MANDRIVA_REL_FILENAME, relstring, vendor);
}
/******************************************************************/
static int Linux_Mandriva_Version_Real(char *filename, char *relstring, char *vendor)
{
char *release=NULL;
char classbuf[CF_MAXVARSIZE];
int major = -1;
char strmajor[CF_MAXVARSIZE];
int minor = -1;
char strminor[CF_MAXVARSIZE];
#define RELEASE_FLAG "release "
release = strstr(relstring, RELEASE_FLAG);
if(release == NULL)
{
CfOut(cf_verbose,"","Could not find a numeric OS release in %s\n",filename);
return 2;
}
else
{
release += strlen(RELEASE_FLAG);
if (sscanf(release, "%d.%d", &major, &minor) == 2)
{
sprintf(strmajor, "%d", major);
sprintf(strminor, "%d", minor);
}
else
{
CfOut(cf_verbose,"","Could not break down release version numbers in %s\n",filename);
}
}
if (major != -1 && minor != -1 && strcmp(vendor, ""))
{
classbuf[0] = '\0';
strcat(classbuf, vendor);
NewClass(classbuf);
strcat(classbuf, "_");
strcat(classbuf, strmajor);
NewClass(classbuf);
if (minor != -2)
{
strcat(classbuf, "_");
strcat(classbuf, strminor);
NewClass(classbuf);
}
}
return 0;
}
/******************************************************************/
static int VM_Version(void)
{
char *sp,buffer[CF_BUFSIZE],classbuf[CF_BUFSIZE],version[CF_BUFSIZE];
int major,minor,bug;
int sufficient = 0;
CfOut(cf_verbose,"","This appears to be a VMware Server ESX/xSX system.\n");
NewClass("VMware");
/* VMware Server ESX >= 3 has version info in /proc */
if (ReadLine("/proc/vmware/version", buffer, sizeof(buffer)))
{
if (sscanf(buffer,"VMware ESX Server %d.%d.%d",&major,&minor,&bug) > 0)
{
snprintf(classbuf,CF_BUFSIZE,"VMware ESX Server %d",major);
NewClass(classbuf);
snprintf(classbuf,CF_BUFSIZE,"VMware ESX Server %d.%d",major,minor);
NewClass(classbuf);
snprintf(classbuf,CF_BUFSIZE,"VMware ESX Server %d.%d.%d",major,minor,bug);
NewClass(classbuf);
sufficient = 1;
}
else if (sscanf(buffer,"VMware ESX Server %s",version) > 0)
{
snprintf(classbuf,CF_BUFSIZE,"VMware ESX Server %s",version);
NewClass(classbuf);
sufficient = 1;
}
}
/* Fall back to checking for other files */
if (sufficient < 1 && (ReadLine("/etc/vmware-release", buffer, sizeof(buffer))
|| ReadLine("/etc/issue", buffer, sizeof(buffer))))
{
NewClass(buffer);
/* Strip off the release code name e.g. "(Dali)" */
if ((sp = strchr(buffer,'(')) != NULL)
{
*sp = 0;
Chop(buffer);
NewClass(buffer);
}
sufficient = 1;
}
return sufficient < 1 ? 1 : 0;
}
/******************************************************************/
static int Xen_Domain(void)
{
FILE *fp;
char buffer[CF_BUFSIZE];
int sufficient = 0;
CfOut(cf_verbose,"","This appears to be a xen pv system.\n");
NewClass("xen");
/* xen host will have "control_d" in /proc/xen/capabilities, xen guest will not */
if ((fp = fopen("/proc/xen/capabilities","r")) != NULL)
{
while (!feof(fp))
{
CfReadLine(buffer,CF_BUFSIZE,fp);
if (strstr(buffer,"control_d"))
{
NewClass("xen_dom0");
sufficient = 1;
}
}
if (!sufficient)
{
NewClass("xen_domu_pv");
sufficient = 1;
}
fclose(fp);
}
return sufficient < 1 ? 1 : 0;
}
/******************************************************************/
#ifdef XEN_CPUID_SUPPORT
/* borrowed from Xen source/tools/libxc/xc_cpuid_x86.c */
static void Xen_Cpuid(uint32_t idx, uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx)
{
asm (
/* %ebx register need to be saved before usage and restored thereafter
* for PIC-compliant code on i386 */
#ifdef __i386__
"push %%ebx; cpuid; mov %%ebx,%1; pop %%ebx"
#else
"push %%rbx; cpuid; mov %%ebx,%1; pop %%rbx"
#endif
: "=a" (*eax), "=r" (*ebx), "=c" (*ecx), "=d" (*edx)
: "0" (idx), "2" (0)
);
}
/******************************************************************/
static int Xen_Hv_Check(void)
{ uint32_t eax, ebx, ecx, edx;
char signature[13];
Xen_Cpuid(0x40000000, &eax, &ebx, &ecx, &edx);
*(uint32_t *)(signature + 0) = ebx;
*(uint32_t *)(signature + 4) = ecx;
*(uint32_t *)(signature + 8) = edx;
signature[12] = '\0';
if (strcmp("XenVMMXenVMM", signature) || (eax < 0x40000002))
{
return 0;
}
Xen_Cpuid(0x40000001, &eax, &ebx, &ecx, &edx);
return 1;
}
#endif
/******************************************************************/
static bool ReadLine(const char *filename, char *buf, int bufsize)
{
FILE *fp = ReadFirstLine(filename, buf, bufsize);
if (fp == NULL)
{
return false;
}
else
{
fclose(fp);
return true;
}
}
static FILE *ReadFirstLine(const char *filename, char *buf, int bufsize)
{
FILE *fp = fopen(filename, "r");
if (fp == NULL)
{
return NULL;
}
if (fgets(buf, bufsize, fp) == NULL)
{
free(fp);
return NULL;
}
StripTrailingNewline(buf);
return fp;
}
/******************************************************************/
/* User info */
/******************************************************************/
int GetCurrentUserName(char *userName, int userNameLen)
{
#ifdef MINGW
return NovaWin_GetCurrentUserName(userName, userNameLen);
#else
return Unix_GetCurrentUserName(userName, userNameLen);
#endif
}
/******************************************************************/
#ifndef MINGW
char *GetHome(uid_t uid)
{
struct passwd *mpw = getpwuid(uid);
return mpw->pw_dir;
}
#endif
cfengine-3.2.4/src/files_names.c 0000644 0001750 0001750 00000065477 11715232734 013467 0000000 0000000 /*
Copyright (C) Cfengine AS
This file is part of Cfengine 3 - written and maintained by Cfengine 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 Commerical Open Source License
(COSL) may apply to this file if you as a licensee so wish it. See
included file COSL.txt.
*/
/*****************************************************************************/
/* */
/* File: files_names.c */
/* */
/*****************************************************************************/
#include "cf3.defs.h"
#include "cf3.extern.h"
static void DeEscapeFilename(char *in,char *out);
static int JoinFast(char *path,char *leaf,char **nextFree,int bufsize);
static int StartJoinFast(char *path,char *leaf,char **nextFree,int bufsize);
/*****************************************************************************/
void LocateFilePromiserGroup(char *wildpath,struct Promise *pp,void (*fnptr)(char *path, struct Promise *ptr))
{ struct Item *path,*ip,*remainder = NULL;
char pbuffer[CF_BUFSIZE];
struct stat statbuf;
int count = 0,lastnode = false, expandregex = false;
uid_t agentuid = getuid();
int create = GetBooleanConstraint("create",pp);
char *pathtype = GetConstraint("pathtype",pp,CF_SCALAR);
Debug("LocateFilePromiserGroup(%s)\n",wildpath);
/* Do a search for promiser objects matching wildpath */
if (!IsPathRegex(wildpath) || (pathtype && (strcmp(pathtype,"literal") == 0)))
{
CfOut(cf_verbose,""," -> Using literal pathtype for %s\n",wildpath);
(*fnptr)(wildpath,pp);
return;
}
else
{
CfOut(cf_verbose,""," -> Using regex pathtype for %s (see pathtype)\n",wildpath);
}
pbuffer[0] = '\0';
path = SplitString(wildpath,'/'); // require forward slash in regex on all platforms
for (ip = path; ip != NULL; ip=ip->next)
{
if (ip->name == NULL || strlen(ip->name) == 0)
{
continue;
}
if (ip->next == NULL)
{
lastnode = true;
}
/* No need to chdir as in recursive descent, since we know about the path here */
if (IsRegex(ip->name))
{
remainder = ip->next;
expandregex = true;
break;
}
else
{
expandregex = false;
}
if (!JoinPath(pbuffer,ip->name))
{
CfOut(cf_error,"","Buffer has limited size in LocateFilePromiserGroup\n");
return;
}
if (cfstat(pbuffer,&statbuf) != -1)
{
if (S_ISDIR(statbuf.st_mode) && statbuf.st_uid != agentuid && statbuf.st_uid != 0)
{
CfOut(cf_inform,"","Directory %s in search path %s is controlled by another user (uid %d) - trusting its content is potentially risky (possible race)\n",pbuffer,wildpath,statbuf.st_uid);
PromiseRef(cf_inform,pp);
}
}
}
if (expandregex) /* Expand one regex link and hand down */
{
char nextbuffer[CF_BUFSIZE],nextbufferOrig[CF_BUFSIZE],regex[CF_BUFSIZE];
const struct dirent *dirp;
CFDIR *dirh;
struct Attributes dummyattr = {{0}};
memset(&dummyattr,0,sizeof(dummyattr));
memset(regex,0,CF_BUFSIZE);
strncpy(regex,ip->name,CF_BUFSIZE-1);
if ((dirh = OpenDirLocal(pbuffer)) == NULL)
{
// Could be a dummy directory to be created so this is not an error.
CfOut(cf_verbose,""," -> Using best-effort expanded (but non-existent) file base path %s\n",wildpath);
(*fnptr)(wildpath,pp);
DeleteItemList(path);
return;
}
else
{
count = 0;
for (dirp = ReadDir(dirh); dirp != NULL; dirp = ReadDir(dirh))
{
if (!ConsiderFile(dirp->d_name,pbuffer,dummyattr,pp))
{
continue;
}
if (!lastnode && !S_ISDIR(statbuf.st_mode))
{
Debug("Skipping non-directory %s\n",dirp->d_name);
continue;
}
if (FullTextMatch(regex,dirp->d_name))
{
Debug("Link %s matched regex %s\n",dirp->d_name,regex);
}
else
{
continue;
}
count++;
strncpy(nextbuffer,pbuffer,CF_BUFSIZE-1);
AddSlash(nextbuffer);
strcat(nextbuffer,dirp->d_name);
for (ip = remainder; ip != NULL; ip=ip->next)
{
AddSlash(nextbuffer);
strcat(nextbuffer,ip->name);
}
/* The next level might still contain regexs, so go again as long as expansion is not nullpotent */
if (!lastnode && (strcmp(nextbuffer,wildpath) != 0))
{
LocateFilePromiserGroup(nextbuffer,pp,fnptr);
}
else
{
struct Promise *pcopy;
CfOut(cf_verbose,""," -> Using expanded file base path %s\n",nextbuffer);
/* Now need to recompute any back references to get the complete path */
snprintf(nextbufferOrig, sizeof(nextbufferOrig), "%s", nextbuffer);
MapNameForward(nextbuffer);
if (!FullTextMatch(pp->promiser,nextbuffer))
{
Debug("Error recomputing references for \"%s\" in: %s",pp->promiser,nextbuffer);
}
/* If there were back references there could still be match.x vars to expand */
pcopy = ExpandDeRefPromise(CONTEXTID,pp);
(*fnptr)(nextbufferOrig,pcopy);
DeletePromise(pcopy);
}
}
CloseDir(dirh);
}
}
else
{
CfOut(cf_verbose,""," -> Using file base path %s\n",pbuffer);
(*fnptr)(pbuffer,pp);
}
if (count == 0)
{
CfOut(cf_verbose,"","No promiser file objects matched as regular expression %s\n",wildpath);
if (create)
{
VerifyFilePromise(pp->promiser,pp);
}
}
DeleteItemList(path);
}
/*********************************************************************/
int IsNewerFileTree(char *dir,time_t reftime)
{ const struct dirent *dirp;
char path[CF_BUFSIZE] = {0};
struct Attributes dummyattr = {{0}};
CFDIR *dirh;
struct stat sb;
// Assumes that race conditions on the file path are unlikely and unimportant
if (lstat(dir,&sb) == -1)
{
CfOut(cf_error,"stat"," !! Unable to stat directory %s in IsNewerFileTree",dir);
// return true to provoke update
return true;
}
if (S_ISDIR(sb.st_mode))
{
//CfOut(cf_verbose,""," ?? Looking at %s (%ld)",dir,sb.st_mtime-reftime);
if (sb.st_mtime > reftime)
{
CfOut(cf_verbose,""," >> Detected change in %s",dir);
return true;
}
}
if ((dirh = OpenDirLocal(dir)) == NULL)
{
CfOut(cf_error,"opendir"," !! Unable to open directory '%s' in IsNewerFileTree",dir);
return false;
}
else
{
for (dirp = ReadDir(dirh); dirp != NULL; dirp = ReadDir(dirh))
{
if (!ConsiderFile(dirp->d_name,dir,dummyattr,NULL))
{
continue;
}
strncpy(path,dir,CF_BUFSIZE-1);
if (!JoinPath(path,dirp->d_name))
{
CfOut(cf_error,"","Internal limit: Buffer ran out of space adding %s to %s in IsNewerFileTree",dir,path);
CloseDir(dirh);
return false;
}
if (lstat(path,&sb) == -1)
{
CfOut(cf_error,"stat"," !! Unable to stat directory %s in IsNewerFileTree",path);
CloseDir(dirh);
// return true to provoke update
return true;
}
if (S_ISDIR(sb.st_mode))
{
if (sb.st_mtime > reftime)
{
CfOut(cf_verbose,""," >> Detected change in %s",path);
CloseDir(dirh);
return true;
}
else
{
if (IsNewerFileTree(path,reftime))
{
CloseDir(dirh);
return true;
}
}
}
}
}
CloseDir(dirh);
return false;
}
/*********************************************************************/
int IsDir(char *path)
/*
Checks if the object pointed to by path exists and is a directory.
Returns true if so, false otherwise.
*/
{
#ifdef MINGW
return NovaWin_IsDir(path);
#else
struct stat sb;
if (cfstat(path, &sb) != -1)
{
if (S_ISDIR(sb.st_mode))
{
return true;
}
}
return false;
#endif /* NOT MINGW */
}
/*********************************************************************/
int EmptyString(char *s)
{ char *sp;
for (sp = s; *sp != '\0'; sp++)
{
if (!isspace(*sp))
{
return false;
}
}
return true;
}
/*********************************************************************/
char *JoinPath(char *path, const char *leaf)
{ int len = strlen(leaf);
Chop(path);
AddSlash(path);
if ((strlen(path)+len) > (CF_BUFSIZE - CF_BUFFERMARGIN))
{
CfOut(cf_error,"","Internal limit: Buffer ran out of space constructing string. Tried to add %s to %s\n",leaf,path);
return NULL;
}
strcat(path,leaf);
return path;
}
/*********************************************************************/
char *JoinSuffix(char *path,char *leaf)
{ int len = strlen(leaf);
Chop(path);
DeleteSlash(path);
if ((strlen(path)+len) > (CF_BUFSIZE - CF_BUFFERMARGIN))
{
CfOut(cf_error,"","Internal limit: Buffer ran out of space constructing string. Tried to add %s to %s\n",leaf,path);
return NULL;
}
strcat(path,leaf);
return path;
}
/*********************************************************************/
int StartJoin(char *path,char *leaf,int bufsize)
{
*path = '\0';
return JoinMargin(path,leaf,NULL,bufsize,CF_BUFFERMARGIN);
}
/*********************************************************************/
static int StartJoinFast(char *path,char *leaf,char **nextFree,int bufsize)
{
*path = '\0';
*nextFree = path;
return JoinMargin(path,leaf,nextFree,bufsize,CF_BUFFERMARGIN);
}
/*********************************************************************/
int Join(char *path, const char *leaf, int bufsize)
{
return JoinMargin(path,leaf,NULL,bufsize,CF_BUFFERMARGIN);
}
/*********************************************************************/
int JoinSilent(char *path, const char *leaf, int bufsize)
/* Don't warn on buffer limits - just return the value */
{
int len = strlen(leaf);
if ((strlen(path)+len) > (bufsize - CF_BUFFERMARGIN))
{
return false;
}
strcat(path,leaf);
return true;
}
/*********************************************************************/
static int JoinFast(char *path,char *leaf,char **nextFree,int bufsize)
/*
* Faster stringjoin by keeping track of where we last stopped
*/
{
return JoinMargin(path,leaf,nextFree,bufsize,CF_BUFFERMARGIN);
}
/*********************************************************************/
int EndJoin(char *path,char *leaf,int bufsize)
{
return JoinMargin(path,leaf,NULL,bufsize,0);
}
/*********************************************************************/
int JoinMargin(char *path, const char *leaf, char **nextFree, int bufsize, int margin)
{ int len = strlen(leaf);
if (margin < 0)
{
FatalError("Negative margin in JoinMargin()");
}
if(nextFree)
{
if ((*nextFree - path) + len > (bufsize - margin) )
{
CfOut(cf_error,"","Internal limit: Buffer ran out of space constructing string (using nextFree), len = %d > %d.\n",(strlen(path)+len),(bufsize - CF_BUFFERMARGIN));
return false;
}
strcpy(*nextFree, leaf);
*nextFree += len;
}
else
{
if ((strlen(path)+len) > (bufsize - margin))
{
CfOut(cf_error,"","Internal limit: Buffer ran out of space constructing string (%d > %d).\n",(strlen(path)+len),(bufsize - CF_BUFFERMARGIN));
return false;
}
strcat(path,leaf);
}
return true;
}
/*********************************************************************/
int IsAbsPath(char *path)
{
if (IsFileSep(*path))
{
return true;
}
else
{
return false;
}
}
/*******************************************************************/
void AddSlash(char *str)
{ char *sp, *sep = FILE_SEPARATOR_STR;
int f = false ,b = false;
if (str == NULL)
{
return;
}
// add root slash on Unix systems
if(strlen(str) == 0)
{
if((VSYSTEMHARDCLASS != mingw) && (VSYSTEMHARDCLASS != cfnt))
{
strcpy(str, "/");
}
return;
}
/* Try to see what convention is being used for filenames
in case this is a cross-system copy from Win/Unix */
for (sp = str; *sp != '\0'; sp++)
{
switch (*sp)
{
case '/':
f = true;
break;
case '\\':
b = true;
break;
default:
break;
}
}
if (f && !b)
{
sep = "/";
}
else if (b && !f)
{
sep = "\\";
}
if (!IsFileSep(str[strlen(str)-1]))
{
strcat(str,sep);
}
}
/*********************************************************************/
void DeleteSlash(char *str)
{
if ((strlen(str)== 0) || (str == NULL))
{
return;
}
if (strcmp(str,"/") == 0)
{
return;
}
if (IsFileSep(str[strlen(str)-1]))
{
str[strlen(str)-1] = '\0';
}
}
/*********************************************************************/
const char *LastFileSeparator(const char *str)
/* Return pointer to last file separator in string, or NULL if
string does not contains any file separtors */
{ const char *sp;
/* Walk through string backwards */
sp = str + strlen(str) - 1;
while (sp >= str)
{
if (IsFileSep(*sp))
{
return sp;
}
sp--;
}
return NULL;
}
/*********************************************************************/
int ChopLastNode(char *str)
/* Chop off trailing node name (possible blank) starting from
last character and removing up to the first / encountered
e.g. /a/b/c -> /a/b
/a/b/ -> /a/b */
{
char *sp;
int ret;
/* Here cast is necessary and harmless, str is modifiable */
if ((sp = (char *)LastFileSeparator(str)) == NULL)
{
ret = false;
}
else
{
*sp = '\0';
ret = true;
}
if (strlen(str) == 0)
{
AddSlash(str);
}
return ret;
}
/*********************************************************************/
void CanonifyNameInPlace(char *s)
{
for (; *s != '\0'; s++)
{
if (!isalnum(*s) || *s == '.')
{
*s = '_';
}
}
}
/*********************************************************************/
char *CanonifyName(const char *str)
{ static char buffer[CF_BUFSIZE];
strncpy(buffer,str,CF_BUFSIZE);
CanonifyNameInPlace(buffer);
return buffer;
}
/*********************************************************************/
char *CanonifyChar(const char *str,char ch)
{ static char buffer[CF_BUFSIZE];
char *sp;
strncpy(buffer,str,CF_BUFSIZE-1);
for (sp = buffer; *sp != '\0'; sp++)
{
if (*sp == ch)
{
*sp = '_';
}
}
return buffer;
}
/*********************************************************************/
int CompareCSVName(char *s1,char *s2)
{ char *sp1,*sp2;
char ch1,ch2;
for (sp1 = s1,sp2 = s2; *sp1 != '\0' || *sp2 != '\0'; sp1++,sp2++)
{
ch1 = (*sp1 == ',') ? '_' : *sp1;
ch2 = (*sp2 == ',') ? '_' : *sp2;
if (ch1 > ch2)
{
return 1;
}
else if (ch1 < ch2)
{
return -1;
}
}
return 0;
}
/*********************************************************************/
const char *ReadLastNode(const char *str)
/* Return the last node of a pathname string */
{ const char *sp;
if ((sp = LastFileSeparator(str)) == NULL)
{
return str;
}
else
{
return sp + 1;
}
}
/*****************************************************************************/
static void DeEscapeFilename(char *in,char *out)
{ char *sp_in,*sp_out = out;
*sp_out = '\0';
for (sp_in = in; *sp_in != '\0'; sp_in++)
{
if (*sp_in == '\\' && *(sp_in+1) == ' ')
{
sp_in++;
}
*sp_out++ = *sp_in;
}
*sp_out = '\0';
}
/*****************************************************************************/
int DeEscapeQuotedString(const char *from,char *to)
{ char *cp;
const char *sp;
char start = *from;
int len = strlen(from);
if (len == 0)
{
return 0;
}
for (sp=from+1,cp=to; (sp-from) < len; sp++,cp++)
{
if ((*sp == start))
{
*(cp) = '\0';
if (*(sp+1) != '\0')
{
return (2+(sp - from));
}
return 0;
}
if (*sp == '\n')
{
P.line_no++;
}
if (*sp == '\\')
{
switch (*(sp+1))
{
case '\n':
P.line_no++;
sp+=2;
break;
case ' ':
break;
case '\\':
case '\"':
case '\'': sp++;
break;
}
}
*cp = *sp;
}
yyerror("Runaway string");
*(cp) = '\0';
return 0;
}
/*********************************************************************/
void Chop(char *str) /* remove trailing spaces */
{ int i;
if ((str == NULL) || (strlen(str) == 0))
{
return;
}
if (strlen(str) > CF_EXPANDSIZE)
{
CfOut(cf_error,"","Chop was called on a string that seemed to have no terminator");
return;
}
for (i = strlen(str)-1; i >= 0 && isspace((int)str[i]); i--)
{
str[i] = '\0';
}
}
/*********************************************************************/
void StripTrailingNewline(char *str)
{ char *c = str + strlen(str);
if (c - str > CF_EXPANDSIZE)
{
CfOut(cf_error, "", "StripTrailingNewline was called on an overlong string");
return;
}
for (; c >= str && (*c == '\0' || *c == '\n'); --c)
{
*c = '\0';
}
}
/*********************************************************************/
int CompressPath(char *dest,char *src)
{ char *sp;
char node[CF_BUFSIZE];
int nodelen;
int rootlen;
Debug("CompressPath(%s,%s)\n",dest,src);
memset(dest,0,CF_BUFSIZE);
rootlen = RootDirLength(src);
strncpy(dest,src,rootlen);
for (sp = src+rootlen; *sp != '\0'; sp++)
{
if (IsFileSep(*sp))
{
continue;
}
for (nodelen = 0; sp[nodelen] != '\0' && !IsFileSep(sp[nodelen]); nodelen++)
{
if (nodelen > CF_MAXLINKSIZE)
{
CfOut(cf_error,"","Link in path suspiciously large");
return false;
}
}
strncpy(node,sp,nodelen);
node[nodelen] = '\0';
sp += nodelen - 1;
if (strcmp(node,".") == 0)
{
continue;
}
if (strcmp(node,"..") == 0)
{
if (!ChopLastNode(dest))
{
Debug("cfengine: used .. beyond top of filesystem!\n");
return false;
}
continue;
}
else
{
AddSlash(dest);
}
if (!JoinPath(dest,node))
{
return false;
}
}
return true;
}
/*********************************************************************/
bool IsStrIn(const char *str, const char **strs)
{
int i;
for (i = 0; strs[i]; ++i)
{
if (strcmp(str, strs[i]) == 0)
{
return true;
}
}
return false;
}
bool IsStrCaseIn(const char *str, const char **strs)
{
int i;
for (i = 0; strs[i]; ++i)
{
if (strcasecmp(str, strs[i]) == 0)
{
return true;
}
}
return false;
}
/*********************************************************************/
void FreeStringArray(char **strs)
{ int i;
if (strs == NULL)
{
return;
}
for(i = 0; strs[i] != NULL; i++)
{
free(strs[i]);
}
free(strs);
strs = NULL;
}
/*********************************************************************/
int IsAbsoluteFileName(const char *f)
{ int off = 0;
// Check for quoted strings
for (off = 0; f[off] == '\"'; off++)
{
}
#ifdef NT
if (IsFileSep(f[off]) && IsFileSep(f[off+1]))
{
return true;
}
if (isalpha(f[off]) && f[off+1] == ':' && IsFileSep(f[off+2]))
{
return true;
}
#endif
if (f[off] == '/')
{
return true;
}
return false;
}
bool IsFileOutsideDefaultRepository(const char *f)
{
return (*f == '.') || IsAbsoluteFileName(f);
}
/*******************************************************************/
static int UnixRootDirLength(char *f)
{
if (IsFileSep(*f))
{
return 1;
}
return 0;
}
#ifdef NT
static int NTRootDirLength(char *f)
{
int len;
if (IsFileSep(f[0]) && IsFileSep(f[1]))
{
/* UNC style path */
/* Skip over host name */
for (len=2; !IsFileSep(f[len]); len++)
{
if (f[len] == '\0')
{
return len;
}
}
/* Skip over share name */
for (len++; !IsFileSep(f[len]); len++)
{
if (f[len] == '\0')
{
return len;
}
}
/* Skip over file separator */
len++;
return len;
}
if (isalpha(f[0]) && f[1] == ':')
{
if(IsFileSep(f[2]))
{
return 3;
}
return 2;
}
return UnixRootDirLength(f);
}
#endif
int RootDirLength(char *f)
/* Return length of Initial directory in path - */
{
#ifdef NT
return NTRootDirLength(f);
#else
return UnixRootDirLength(f);
#endif
}
/*********************************************************************/
/* TOOLKIT : String */
/*********************************************************************/
char ToLower (char ch)
{
if (isupper((int)ch))
{
return(ch - 'A' + 'a');
}
else
{
return(ch);
}
}
/*********************************************************************/
char ToUpper (char ch)
{
if (isdigit((int)ch) || ispunct((int)ch))
{
return(ch);
}
if (isupper((int)ch))
{
return(ch);
}
else
{
return(ch - 'a' + 'A');
}
}
/*********************************************************************/
char *ToUpperStr (char *str)
{ static char buffer[CF_BUFSIZE];
int i;
memset(buffer,0,CF_BUFSIZE);
if (strlen(str) >= CF_BUFSIZE)
{
char *tmp;
tmp = malloc(40+strlen(str));
sprintf(tmp,"String too long in ToUpperStr: %s",str);
FatalError(tmp);
}
for (i = 0; (str[i] != '\0') && (i < CF_BUFSIZE-1); i++)
{
buffer[i] = ToUpper(str[i]);
}
buffer[i] = '\0';
return buffer;
}
/*********************************************************************/
char *ToLowerStr (char *str)
{ static char buffer[CF_BUFSIZE];
int i;
memset(buffer,0,CF_BUFSIZE);
if (strlen(str) >= CF_BUFSIZE-1)
{
char *tmp;
tmp = malloc(40+strlen(str));
snprintf(tmp,CF_BUFSIZE-1,"String too long in ToLowerStr: %s",str);
FatalError(tmp);
}
for (i = 0; (str[i] != '\0') && (i < CF_BUFSIZE-1); i++)
{
buffer[i] = ToLower(str[i]);
}
buffer[i] = '\0';
return buffer;
}
/*********************************************************************/
char *Titleize (char *str)
{ static char buffer[CF_BUFSIZE];
int i;
if (str == NULL)
{
return NULL;
}
strcpy(buffer,str);
if (strlen(buffer) > 1)
{
for (i = 1; buffer[i] != '\0'; i++)
{
buffer[i] = ToLower(str[i]);
}
}
*buffer = ToUpper(*buffer);
return buffer;
}
/*********************************************************************/
int SubStrnCopyChr(char *to,char *from,int len,char sep)
{ char *sp,*sto = to;
int count = 0;
memset(to,0,len);
if (from == NULL)
{
return 0;
}
if (from && strlen(from) == 0)
{
return 0;
}
for (sp = from; *sp != '\0'; sp++)
{
if (count > len-1)
{
break;
}
if (*sp == '\\' && *(sp+1) == sep)
{
*sto++ = *++sp;
}
else if (*sp == sep)
{
break;
}
else
{
*sto++ = *sp;
}
count++;
}
return count;
}
/*********************************************************************/
int CountChar(char *string,char sep)
{ char *sp;
int count = 0;
if (string == NULL)
{
return 0;
}
if (string && strlen(string) == 0)
{
return 0;
}
for (sp = string; *sp != '\0'; sp++)
{
if (*sp == '\\' && *(sp+1) == sep)
{
++sp;
}
else if (*sp == sep)
{
count++;
}
}
return count;
}
/*********************************************************************/
void ReplaceChar(char *in, char *out, int outSz, char from, char to)
/* Replaces all occurences of 'from' to 'to' in preallocated
* string 'out'. */
{
int len;
int i;
memset(out,0,outSz);
len = strlen(in);
for(i = 0; (i < len) && (i < outSz - 1); i++)
{
if (in[i] == from)
{
out[i] = to;
}
else
{
out[i] = in[i];
}
}
}
/*********************************************************************/
void ReplaceTrailingChar(char *str, char from, char to)
/* Replaces any unwanted last char in str. */
{
int strLen;
strLen = strlen(str);
if(strLen == 0)
{
return;
}
if(str[strLen - 1] == from)
{
str[strLen - 1] = to;
}
}
/*********************************************************************/
void ReplaceTrailingStr(char *str, char *from, char to)
/* Replaces any unwanted last chars in str. */
{
int strLen;
int fromLen;
strLen = strlen(str);
fromLen = strlen(from);
if(strLen == 0)
{
return;
}
char *startCmp = str + strLen - fromLen;
if(strcmp(startCmp, from) == 0)
{
memset(startCmp, to, fromLen);
}
}
/*********************************************************************/
int ReplaceStr(char *in, char *out, int outSz, char* from, char *to)
/* Replaces all occurences of strings 'from' to 'to' in preallocated
* string 'out'. Returns true on success, false otherwise. */
{
int inSz;
int outCount;
int inCount;
int fromSz, toSz;
memset(out,0,outSz);
inSz = strlen(in);
fromSz = strlen(from);
toSz = strlen(to);
inCount = 0;
outCount = 0;
while((inCount < inSz) && (outCount < outSz))
{
if (strncmp(in + inCount, from, fromSz) == 0)
{
if(outCount + toSz >= outSz)
{
CfOut(cf_error, "", "!! Out of buffer in ReplaceStr");
return false;
}
strcat(out,to);
inCount += fromSz;
outCount += toSz;
}
else
{
out[outCount] = in[inCount];
inCount++;
outCount++;
}
}
return true;
}
/*********************************************************************/
#if defined HAVE_PTHREAD_H && (defined HAVE_LIBPTHREAD || defined BUILDTIN_GCC_THREAD)
void *ThreadUniqueName(pthread_t tid)
/* pthread_t is an integer on Unix, but a structure on Windows
* Finds a unique name for a thread for both platforms. */
{
#ifdef MINGW
return tid.p; // pointer to thread structure
#else
return (void*)tid; // index into thread array ?
#endif /* NOT MINGW */
}
#endif /* HAVE PTHREAD */
cfengine-3.2.4/src/config.h 0000644 0001750 0001750 00000000072 11707771422 012433 0000000 0000000
/* Dummy file required for some malconfigured headers */
cfengine-3.2.4/src/comparray.c 0000644 0001750 0001750 00000006062 11715232734 013160 0000000 0000000 /*
Copyright (C) Cfengine AS
This file is part of Cfengine 3 - written and maintained by Cfengine 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 Commerical Open Source License
(COSL) may apply to this file if you as a licensee so wish it. See
included file COSL.txt.
*/
/*******************************************************************/
/* */
/* Compressed Arrays */
/* */
/*******************************************************************/
#include "cf3.defs.h"
#include "cf3.extern.h"
/*******************************************************************/
int FixCompressedArrayValue(int i,char *value,struct CompressedArray **start)
{ struct CompressedArray *ap;
char *sp;
for (ap = *start; ap != NULL; ap = ap->next)
{
if (ap->key == i)
{
/* value already fixed */
return false;
}
}
Debug("FixCompressedArrayValue(%d,%s)\n",i,value);
if ((ap = (struct CompressedArray *)malloc(sizeof(struct CompressedArray))) == NULL)
{
FatalError("Memory allocation in FixCompressedArray");
}
if ((sp = malloc(strlen(value)+2)) == NULL)
{
FatalError("Memory allocation in FixCompressedArray");
}
strcpy(sp,value);
ap->key = i;
ap->value = sp;
ap->next = *start;
*start = ap;
return true;
}
/*******************************************************************/
void DeleteCompressedArray(struct CompressedArray *start)
{
if (start != NULL)
{
DeleteCompressedArray(start->next);
start->next = NULL;
if (start->value != NULL)
{
free(start->value);
}
free(start);
}
}
/*******************************************************************/
int CompressedArrayElementExists(struct CompressedArray *start,int key)
{ struct CompressedArray *ap;
Debug("CompressedArrayElementExists(%d)\n",key);
for (ap = start; ap !=NULL; ap = ap->next)
{
if (ap->key == key)
{
return true;
}
}
return false;
}
/*******************************************************************/
char *CompressedArrayValue(struct CompressedArray *start,int key)
{ struct CompressedArray *ap;
for (ap = start; ap != NULL; ap = ap->next)
{
if (ap->key == key)
{
return ap->value;
}
}
return NULL;
}
cfengine-3.2.4/src/mod_storage.c 0000644 0001750 0001750 00000010673 11715232734 013471 0000000 0000000 /*
Copyright (C) Cfengine AS
This file is part of Cfengine 3 - written and maintained by Cfengine 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 Commerical Open Source License
(COSL) may apply to this file if you as a licensee so wish it. See
included file COSL.txt.
*/
/*****************************************************************************/
/* */
/* File: mod_storage.c */
/* */
/*****************************************************************************/
/*
This file can act as a template for adding functionality to cfengine 3.
All functionality can be added by extending the main array
CF_MOD_SUBTYPES[CF3_MODULES]
and its array dimension, in mod_common, in the manner shown here.
*/
#define CF3_MOD_STORAGE
#include "cf3.defs.h"
#include "cf3.extern.h"
/***********************************************************/
/* Read this module file backwards, as dependencies have */
/* to be defined first - these arrays declare pairs of */
/* constraints */
/* */
/* lval => rval */
/* */
/* in the form (lval,type,range) */
/* */
/* If the type is cf_body then the range is a pointer */
/* to another array of pairs, like in a body "sub-routine" */
/* */
/***********************************************************/
struct BodySyntax CF_CHECKVOL_BODY[] =
{
{"check_foreign",cf_opts,CF_BOOL,"true/false verify storage that is mounted from a foreign system on this host"},
{"freespace",cf_str,"[0-9]+[MBkKgGmb%]","Absolute or percentage minimum disk space that should be available before warning"},
{"sensible_size",cf_int,CF_VALRANGE,"Minimum size in bytes that should be used on a sensible-looking storage device"},
{"sensible_count",cf_int,CF_VALRANGE,"Minimum number of files that should be defined on a sensible-looking storage device"},
{"scan_arrivals",cf_opts,CF_BOOL,"true/false generate pseudo-periodic disk change arrival distribution"},
{NULL,cf_notype,NULL,NULL}
};
/**************************************************************/
struct BodySyntax CF_MOUNT_BODY[] =
{
{"edit_fstab",cf_opts,CF_BOOL,"true/false add or remove entries to the file system table (\"fstab\")"},
{"mount_type",cf_opts,"nfs,nfs2,nfs3,nfs4","Protocol type of remote file system"},
{"mount_source",cf_str,CF_ABSPATHRANGE,"Path of remote file system to mount"},
{"mount_server",cf_str,"","Hostname or IP or remote file system server"},
{"mount_options",cf_slist,"","List of option strings to add to the file system table (\"fstab\")"},
{"unmount",cf_opts,CF_BOOL,"true/false unmount a previously mounted filesystem"},
{NULL,cf_notype,NULL,NULL}
};
/***************************************************************/
struct BodySyntax CF_STORAGE_BODIES[] =
{
{"mount",cf_body,CF_MOUNT_BODY,"Criteria for mounting foreign file systems"},
{"volume",cf_body,CF_CHECKVOL_BODY,"Criteria for monitoring/probing mounted volumes"},
{NULL,cf_notype,NULL,NULL}
};
/***************************************************************/
/* This is the point of entry from mod_common.c */
/***************************************************************/
struct SubTypeSyntax CF_STORAGE_SUBTYPES[] =
{
{"agent","storage",CF_STORAGE_BODIES},
{NULL,NULL,NULL},
};
cfengine-3.2.4/src/files_links.c 0000644 0001750 0001750 00000042253 11715232734 013467 0000000 0000000 /*
Copyright (C) Cfengine AS
This file is part of Cfengine 3 - written and maintained by Cfengine 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 Commerical Open Source License
(COSL) may apply to this file if you as a licensee so wish it. See
included file COSL.txt.
*/
/*****************************************************************************/
/* */
/* File: files_links.c */
/* */
/*****************************************************************************/
#include "cf3.defs.h"
#include "cf3.extern.h"
static int MakeLink(char *from,char *to,struct Attributes attr,struct Promise *pp);
static char *AbsLinkPath(char *from,char *relto);
/*****************************************************************************/
char VerifyLink(char *destination,char *source,struct Attributes attr,struct Promise *pp)
#ifdef MINGW
{
CfOut(cf_verbose, "", "Windows does not support symbolic links (at VerifyLink())");
return CF_FAIL;
}
#else /* NOT MINGW */
{ char to[CF_BUFSIZE],linkbuf[CF_BUFSIZE],absto[CF_BUFSIZE];
int nofile = false;
struct stat sb;
Debug("Linkfiles(%s -> %s)\n",destination,source);
/*
if (MatchRlistItem(attr.link.copy_patterns,lastnode))
{
CfOut(cf_verbose,"","cfengine: link item %s marked for copying instead\n",sourcefile);
LinkCopy(sourcefile,destfile,&ssb,attr,pp);
attr.copy_backup = true;
CopyFile(source,destination,ssb,attr,pp);
return;
}
*/
memset(to,0,CF_BUFSIZE);
if (!IsAbsoluteFileName(source) && (*source != '.')) /* links without a directory reference */
{
snprintf(to,CF_BUFSIZE-1,"./%s",source);
}
else
{
strncpy(to,source,CF_BUFSIZE-1);
}
if (!IsAbsoluteFileName(to)) /* relative path, must still check if exists */
{
Debug("Relative link destination detected: %s\n",to);
strcpy(absto,AbsLinkPath(destination,to));
Debug("Absolute path to relative link = %s, destination %s\n",absto,destination);
}
else
{
strcpy(absto,to);
}
if (cfstat(absto,&sb) == -1)
{
Debug("No source file\n");
nofile = true;
}
if (nofile && (attr.link.when_no_file != cfa_force) && (attr.link.when_no_file != cfa_delete))
{
CfOut(cf_inform,"","Source %s for linking is absent",absto);
cfPS(cf_verbose,CF_FAIL,"",pp,attr," !! Unable to create link %s -> %s, no source",destination,to);
return CF_WARN;
}
if (nofile && attr.link.when_no_file == cfa_delete)
{
KillGhostLink(destination,attr,pp);
return CF_CHG;
}
memset(linkbuf,0,CF_BUFSIZE);
if (readlink(destination,linkbuf,CF_BUFSIZE-1) == -1)
{
if (!MakeParentDirectory(destination,attr.move_obstructions)) /* link doesn't exist */
{
cfPS(cf_verbose,CF_FAIL,"",pp,attr," !! Unable to create link %s -> %s",destination,to);
return CF_FAIL;
}
else
{
if (!MoveObstruction(destination,attr,pp))
{
cfPS(cf_verbose,CF_FAIL,"",pp,attr," !! Unable to create link %s -> %s",destination,to);
return CF_FAIL;
}
return MakeLink(destination,to,attr,pp)?CF_CHG:CF_FAIL;
}
}
else
{ int ok = false;
if (attr.link.link_type == cfa_symlink && strcmp(linkbuf,to) != 0 && strcmp(linkbuf,source) != 0)
{
ok = true;
}
else if (strcmp(linkbuf,source) != 0)
{
ok = true;
}
if (ok)
{
if (attr.move_obstructions)
{
if (!DONTDO)
{
cfPS(cf_inform,CF_CHG,"",pp,attr,"Overriding incorrect link %s\n",destination);
if (unlink(destination) == -1)
{
cfPS(cf_verbose,CF_FAIL,"",pp,attr," !! Link %s points to %s not %s - error removing link",destination,linkbuf,to);
return CF_FAIL;
}
return MakeLink(destination,to,attr,pp);
}
else
{
CfOut(cf_error,""," !! Must remove incorrect link %s\n",destination);
return CF_NOP;
}
}
else
{
cfPS(cf_verbose,CF_FAIL,"",pp,attr," !! Link %s points to %s not %s - not authorized to override",destination,linkbuf,to);
return true;
}
}
else
{
cfPS(cf_verbose,CF_NOP,"",pp,attr," -> Link %s points to %s - promise kept",destination,to);
return CF_NOP;
}
}
}
#endif /* NOT MINGW */
/*****************************************************************************/
char VerifyAbsoluteLink(char *destination,char *source,struct Attributes attr,struct Promise *pp)
{ char absto[CF_BUFSIZE];
char expand[CF_BUFSIZE];
char linkto[CF_BUFSIZE];
Debug("VerifyAbsoluteLink(%s,%s)\n",destination,source);
if (*source == '.')
{
strcpy(linkto,destination);
ChopLastNode(linkto);
AddSlash(linkto);
strcat(linkto,source);
}
else
{
strcpy(linkto,source);
}
CompressPath(absto,linkto);
expand[0] = '\0';
if (attr.link.when_no_file == cfa_force)
{
if (!ExpandLinks(expand,absto,0)) /* begin at level 1 and beam out at 15 */
{
CfOut(cf_error,""," !! Failed to make absolute link in\n");
PromiseRef(cf_error,pp);
return CF_FAIL;
}
else
{
Debug2("ExpandLinks returned %s\n",expand);
}
}
else
{
strcpy(expand,absto);
}
CompressPath(linkto,expand);
return VerifyLink(destination,linkto,attr,pp);
}
/*****************************************************************************/
char VerifyRelativeLink(char *destination,char *source,struct Attributes attr,struct Promise *pp)
{ char *sp, *commonto, *commonfrom;
char buff[CF_BUFSIZE],linkto[CF_BUFSIZE],add[CF_BUFSIZE];
int levels=0;
Debug("RelativeLink(%s,%s)\n",destination,source);
if (*source == '.')
{
return VerifyLink(destination,source,attr,pp);
}
if (!CompressPath(linkto,source))
{
cfPS(cf_error,CF_INTERPT,"",pp,attr," !! Failed to link %s to %s\n",destination,source);
return CF_FAIL;
}
commonto = linkto;
commonfrom = destination;
if (strcmp(commonto,commonfrom) == 0)
{
cfPS(cf_error,CF_INTERPT,"",pp,attr," !! Failed to link %s to %s - can't link file %s to itself\n",destination,source,commonto);
return CF_FAIL;
}
while (*commonto == *commonfrom)
{
commonto++;
commonfrom++;
}
while (!(IsAbsoluteFileName(commonto) && IsAbsoluteFileName(commonfrom)))
{
commonto--;
commonfrom--;
}
commonto++;
for (sp = commonfrom; *sp != '\0'; sp++)
{
if (IsFileSep(*sp))
{
levels++;
}
}
memset(buff,0,CF_BUFSIZE);
strcat(buff,".");
strcat(buff,FILE_SEPARATOR_STR);
while(--levels > 0)
{
snprintf(add,CF_BUFSIZE-1,"..%c",FILE_SEPARATOR);
if (!JoinPath(buff,add))
{
return CF_FAIL;
}
}
if (!JoinPath(buff,commonto))
{
return CF_FAIL;
}
return VerifyLink(destination,buff,attr,pp);
}
/*****************************************************************************/
char VerifyHardLink(char *destination,char *source,struct Attributes attr,struct Promise *pp)
{ char to[CF_BUFSIZE],absto[CF_BUFSIZE];
struct stat ssb,dsb;
memset(to,0,CF_BUFSIZE);
if (!IsAbsoluteFileName(source) && (*source != '.')) /* links without a directory reference */
{
snprintf(to,CF_BUFSIZE-1,".%c%s",FILE_SEPARATOR,source);
}
else
{
strncpy(to,source,CF_BUFSIZE-1);
}
if (!IsAbsoluteFileName(to)) /* relative path, must still check if exists */
{
Debug("Relative link destination detected: %s\n",to);
strcpy(absto,AbsLinkPath(destination,to));
Debug("Absolute path to relative link = %s, destination %s\n",absto,destination);
}
else
{
strcpy(absto,to);
}
if (cfstat(absto,&ssb) == -1)
{
cfPS(cf_inform,CF_INTERPT,"",pp,attr," !! Source file %s doesn't exist\n",source);
return CF_WARN;
}
if (!S_ISREG(ssb.st_mode))
{
cfPS(cf_inform,CF_FAIL,"",pp,attr," !! Source file %s is not a regular file, not appropriate to hard-link\n",to);
return CF_WARN;
}
Debug2("Trying to (hard) link %s -> %s\n",destination,to);
if (cfstat(destination,&dsb) == -1)
{
return MakeHardLink(destination,to,attr,pp)?CF_CHG:CF_FAIL;
}
/* both files exist, but are they the same file? POSIX says */
/* the files could be on different devices, but unix doesn't */
/* allow this behaviour so the tests below are theoretical...*/
if (dsb.st_ino != ssb.st_ino && dsb.st_dev != ssb.st_dev)
{
CfOut(cf_verbose,""," !! If this is POSIX, unable to determine if %s is hard link is correct\n",destination);
CfOut(cf_verbose,""," !! since it points to a different filesystem!\n");
if (dsb.st_mode == ssb.st_mode && dsb.st_size == ssb.st_size)
{
cfPS(cf_verbose,CF_NOP,"",pp,attr,"Hard link (%s->%s) on different device APPEARS okay\n",destination,to);
return CF_NOP;
}
}
if (dsb.st_ino == ssb.st_ino && dsb.st_dev == ssb.st_dev)
{
cfPS(cf_verbose,CF_NOP,"",pp,attr," -> Hard link (%s->%s) exists and is okay\n",destination,to);
return CF_NOP;
}
CfOut(cf_inform,""," !! %s does not appear to be a hard link to %s\n",destination,to);
if (!MoveObstruction(destination,attr,pp))
{
return CF_FAIL;
}
return MakeHardLink(destination,to,attr,pp)?CF_CHG:CF_FAIL;
}
/*****************************************************************************/
/* Level */
/*****************************************************************************/
int KillGhostLink(char *name,struct Attributes attr,struct Promise *pp)
#ifdef MINGW
{
CfOut(cf_verbose, "", "Windows does not support symbolic links (at KillGhostLink())");
cfPS(cf_error,CF_FAIL,"",pp,attr," !! Windows does not support killing link \"%s\"", name);
return false;
}
#else /* NOT MINGW */
{ char linkbuf[CF_BUFSIZE],tmp[CF_BUFSIZE];
char linkpath[CF_BUFSIZE],*sp;
struct stat statbuf;
Debug("KillGhostLink(%s)\n",name);
memset(linkbuf,0,CF_BUFSIZE);
memset(linkpath,0,CF_BUFSIZE);
if (readlink(name,linkbuf,CF_BUFSIZE-1) == -1)
{
CfOut(cf_verbose,""," !! (Can't read link %s while checking for deadlinks)\n",name);
return true; /* ignore */
}
if (!IsAbsoluteFileName(linkbuf))
{
strcpy(linkpath,name); /* Get path to link */
for (sp = linkpath+strlen(linkpath); (*sp != FILE_SEPARATOR) && (sp >= linkpath); sp-- )
{
*sp = '\0';
}
}
strcat(linkpath,linkbuf);
CompressPath(tmp,linkpath);
if (cfstat(tmp,&statbuf) == -1) /* link points nowhere */
{
if (attr.link.when_no_file == cfa_delete || attr.recursion.rmdeadlinks)
{
CfOut(cf_verbose,""," !! %s is a link which points to %s, but that file doesn't seem to exist\n",name,linkbuf);
if (!DONTDO)
{
unlink(name); /* May not work on a client-mounted system ! */
cfPS(cf_inform,CF_CHG,"",pp,attr," -> Removing ghost %s - reference to something that is not there\n",name);
return true;
}
}
}
return false;
}
#endif /* NOT MINGW */
/*****************************************************************************/
static int MakeLink (char *from,char *to,struct Attributes attr,struct Promise *pp)
#ifdef MINGW // TODO: Remove? Should never get called.
{
CfOut(cf_verbose, "", "Windows does not support symbolic links");
cfPS(cf_error,CF_FAIL,"symlink",pp,attr," !! Couldn't link %s to %s\n",to,from);
return false;
}
#else /* NOT MINGW */
{
if (DONTDO || attr.transaction.action == cfa_warn)
{
CfOut(cf_error,""," !! Need to link files %s -> %s\n",from,to);
return false;
}
else
{
if (symlink(to,from) == -1)
{
cfPS(cf_error,CF_FAIL,"symlink",pp,attr," !! Couldn't link %s to %s\n",to,from);
return false;
}
else
{
cfPS(cf_inform,CF_CHG,"",pp,attr," -> Linked files %s -> %s\n",from,to);
return true;
}
}
}
#endif /* NOT MINGW */
/*****************************************************************************/
int MakeHardLink (char *from,char *to,struct Attributes attr,struct Promise *pp)
#ifdef MINGW
{ // TODO: Implement ?
CfOut(cf_verbose, "", "Hard links are not yet supported on Windows");
cfPS(cf_error,CF_FAIL,"link",pp,attr," !! Couldn't (hard) link %s to %s\n",to,from);
return false;
}
#else /* NOT MINGW */
{
if (DONTDO)
{
CfOut(cf_error,""," !! Need to hard link files %s -> %s\n",from,to);
return false;
}
else
{
if (link(to,from) == -1)
{
cfPS(cf_error,CF_FAIL,"link",pp,attr," !! Couldn't (hard) link %s to %s\n",to,from);
return false;
}
else
{
cfPS(cf_inform,CF_CHG,"",pp,attr," -> (Hard) Linked files %s -> %s\n",from,to);
return true;
}
}
}
#endif /* NOT MINGW */
/*********************************************************************/
int ExpandLinks(char *dest,char *from,int level) /* recursive */
/* Expand a path contaning symbolic links, up to 4 levels */
/* of symbolic links and then beam out in a hurry ! */
#ifdef MINGW
{
CfOut(cf_error, "", "!! Windows does not support symbolic links (at ExpandLinks(%s,%s))", dest, from);
return false;
}
#else /* NOT MINGW */
{ char *sp, buff[CF_BUFSIZE];
char node[CF_MAXLINKSIZE];
struct stat statbuf;
int lastnode = false;
memset(dest,0,CF_BUFSIZE);
if (level >= CF_MAXLINKLEVEL)
{
CfOut(cf_error,""," !! Too many levels of symbolic links to evaluate absolute path\n");
return false;
}
sp = from;
while (*sp != '\0')
{
if (*sp == FILE_SEPARATOR)
{
sp++;
continue;
}
sscanf(sp,"%[^/]",node);
sp += strlen(node);
if (*sp == '\0')
{
lastnode = true;
}
if (strcmp(node,".") == 0)
{
continue;
}
if (strcmp(node,"..") == 0)
{
continue;
}
else
{
strcat(dest,"/");
}
strcat(dest,node);
if (lstat(dest,&statbuf) == -1) /* File doesn't exist so we can stop here */
{
CfOut(cf_error,"lstat"," !! Can't stat %s in ExpandLinks\n",dest);
return false;
}
if (S_ISLNK(statbuf.st_mode))
{
memset(buff,0,CF_BUFSIZE);
if (readlink(dest,buff,CF_BUFSIZE-1) == -1)
{
CfOut(cf_error,"readlink"," !! Expand links can't stat %s\n",dest);
return false;
}
else
{
if (buff[0] == '.')
{
ChopLastNode(dest);
AddSlash(dest);
if (!JoinPath(dest,buff))
{
return false;
}
}
else if (IsAbsoluteFileName(buff))
{
strcpy(dest,buff);
DeleteSlash(dest);
if (strcmp(dest,from) == 0)
{
Debug2("No links to be expanded\n");
return true;
}
if (!lastnode && !ExpandLinks(buff,dest,level+1))
{
return false;
}
}
else
{
ChopLastNode(dest);
AddSlash(dest);
strcat(dest,buff);
DeleteSlash(dest);
if (strcmp(dest,from) == 0)
{
Debug2("No links to be expanded\n");
return true;
}
memset(buff,0,CF_BUFSIZE);
if (!lastnode && !ExpandLinks(buff,dest,level+1))
{
return false;
}
}
}
}
}
return true;
}
#endif /* NOT MINGW */
/*********************************************************************/
static char *AbsLinkPath (char *from,char *relto)
/* Take an abolute source and a relative destination object
and find the absolute name of the to object */
{ char *sp;
int pop = 1;
static char destination[CF_BUFSIZE];
if (IsAbsoluteFileName(relto))
{
FatalError("Cfengine internal error: call to AbsLInkPath with absolute pathname\n");
}
strcpy(destination,from); /* reuse to save stack space */
for (sp = relto; *sp != '\0'; sp++)
{
if (strncmp(sp,"../",3) == 0)
{
pop++;
sp += 2;
continue;
}
if (strncmp(sp,"./",2) == 0)
{
sp += 1;
continue;
}
break; /* real link */
}
while (pop > 0)
{
ChopLastNode(destination);
pop--;
}
if (strlen(destination) == 0)
{
strcpy(destination,"/");
}
else
{
AddSlash(destination);
}
strcat(destination,sp);
Debug("Reconstructed absolute linkname = %s\n",destination);
return destination;
}
cfengine-3.2.4/src/mon_cpu.c 0000644 0001750 0001750 00000005617 11715232734 012630 0000000 0000000 /*
Copyright (C) Cfengine AS
This file is part of Cfengine 3 - written and maintained by Cfengine 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 Commerical Open Source License
(COSL) may apply to this file if you as a licensee so wish it. See
included file COSL.txt.
*/
#include "cf3.defs.h"
#include "cf3.extern.h"
#include "monitoring.h"
#if !defined(MINGW)
/* Constants */
#define MON_CPU_MAX 4
/* Globals */
static double LAST_CPU_Q[MON_CPU_MAX + 1];
static long LAST_CPU_T[MON_CPU_MAX + 1];
/* Implementation */
void MonCPUGatherData(double *cf_this)
{
double q,dq;
char name[CF_MAXVARSIZE],cpuname[CF_MAXVARSIZE],buf[CF_BUFSIZE];
long cpuidx,userticks=0,niceticks=0,systemticks=0,idle=0,iowait=0,irq=0,softirq=0;
long total_time = 1;
FILE *fp;
enum observables slot = ob_spare;
if ((fp=fopen("/proc/stat","r")) == NULL)
{
CfOut(cf_verbose,"","Didn't find proc data\n");
return;
}
CfOut(cf_verbose,"","Reading /proc/stat utilization data -------\n");
while (!feof(fp))
{
fgets(buf,CF_BUFSIZE,fp);
sscanf(buf,"%s%ld%ld%ld%ld%ld%ld%ld",cpuname,&userticks,&niceticks,&systemticks,&idle,&iowait,&irq,&softirq);
total_time = (userticks+niceticks+systemticks+idle);
q = 100.0 * (double)(total_time - idle);
if (strcmp(cpuname,"cpu") == 0)
{
CfOut(cf_verbose,"","Found aggregate CPU\n",cpuidx);
slot = ob_cpuall;
cpuidx = MON_CPU_MAX;
}
else if (strncmp(cpuname, "cpu", 3) == 0)
{
if (sscanf(cpuname, "cpu%d", &cpuidx) == 1)
{
if (cpuidx < 0 || cpuidx >= MON_CPU_MAX)
{
continue;
}
}
slot = ob_cpu0 + cpuidx;
}
else
{
CfOut(cf_verbose,"","Found nothing (%s)\n",cpuname);
slot = ob_spare;
fclose(fp);
return;
}
dq = (q - LAST_CPU_Q[cpuidx])/(double)(total_time-LAST_CPU_T[cpuidx]); /* % Utilization */
if (dq > 100 || dq < 0) // Counter wrap around
{
dq = 50;
}
cf_this[slot] = dq;
LAST_CPU_Q[cpuidx] = q;
LAST_CPU_T[cpuidx] = total_time;
CfOut(cf_verbose,"","Set %s=%d to %.1lf after %ld 100ths of a second \n",OBS[slot][1],slot,cf_this[slot],total_time);
}
fclose(fp);
}
#endif /* !MINGW */
cfengine-3.2.4/src/processes_select.c 0000644 0001750 0001750 00000027325 11715232734 014535 0000000 0000000 /*
Copyright (C) Cfengine AS
This file is part of Cfengine 3 - written and maintained by Cfengine 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 Commerical Open Source License
(COSL) may apply to this file if you as a licensee so wish it. See
included file COSL.txt.
*/
/*****************************************************************************/
/* */
/* File: processes_select.c */
/* */
/*****************************************************************************/
#include "cf3.defs.h"
#include "cf3.extern.h"
static int SelectProcRangeMatch(char *name1,char *name2,int min,int max,char **names,char **line);
static int SelectProcRegexMatch(char *name1,char *name2,char *regex,char **colNames,char **line);
static int SplitProcLine(char *proc,char **names,int *start,int *end,char **line);
static int SelectProcTimeCounterRangeMatch(char *name1,char *name2,time_t min,time_t max,char **names,char **line);
static int SelectProcTimeAbsRangeMatch(char *name1,char *name2,time_t min,time_t max,char **names,char **line);
static int GetProcColumnIndex(char *name1,char *name2,char **names);
/***************************************************************************/
int SelectProcess(char *procentry,char **names,int *start,int *end,struct Attributes a,struct Promise *pp)
{ struct AlphaList proc_attr;
int result = true,i;
char *column[CF_PROCCOLS];
struct Rlist *rp;
Debug("SelectProcess(%s)\n",procentry);
InitAlphaList(&proc_attr);
if (!a.haveselect)
{
return true;
}
if (!SplitProcLine(procentry,names,start,end,column))
{
return false;
}
if (DEBUG)
{
for (i = 0; names[i] != NULL; i++)
{
printf("COL[%s] = \"%s\"\n",names[i],column[i]);
}
}
for (rp = a.process_select.owner; rp != NULL; rp = rp->next)
{
if (SelectProcRegexMatch("USER","UID",(char *)rp->item,names,column))
{
PrependAlphaList(&proc_attr,"process_owner");
break;
}
}
if (SelectProcRangeMatch("PID","PID",a.process_select.min_pid,a.process_select.max_pid,names,column))
{
PrependAlphaList(&proc_attr,"pid");
}
if (SelectProcRangeMatch("PPID","PPID",a.process_select.min_ppid,a.process_select.max_ppid,names,column))
{
PrependAlphaList(&proc_attr,"ppid");
}
if (SelectProcRangeMatch("PGID","PGID",a.process_select.min_pgid,a.process_select.max_pgid,names,column))
{
PrependAlphaList(&proc_attr,"pgid");
}
if (SelectProcRangeMatch("VSZ","SZ",a.process_select.min_vsize,a.process_select.max_vsize,names,column))
{
PrependAlphaList(&proc_attr,"vsize");
}
if (SelectProcRangeMatch("RSS","RSS",a.process_select.min_rsize,a.process_select.max_rsize,names,column))
{
PrependAlphaList(&proc_attr,"rsize");
}
if (SelectProcTimeCounterRangeMatch("TIME","TIME",a.process_select.min_ttime,a.process_select.max_ttime,names,column))
{
PrependAlphaList(&proc_attr,"ttime");
}
if (SelectProcTimeAbsRangeMatch("STIME","START",a.process_select.min_stime,a.process_select.max_stime,names,column))
{
PrependAlphaList(&proc_attr,"stime");
}
if (SelectProcRangeMatch("NI","PRI",a.process_select.min_pri,a.process_select.max_pri,names,column))
{
PrependAlphaList(&proc_attr,"priority");
}
if (SelectProcRangeMatch("NLWP","NLWP",a.process_select.min_thread,a.process_select.max_thread,names,column))
{
PrependAlphaList(&proc_attr,"threads");
}
if (SelectProcRegexMatch("S","STAT",a.process_select.status,names,column))
{
PrependAlphaList(&proc_attr,"status");
}
if (SelectProcRegexMatch("CMD","COMMAND",a.process_select.command,names,column))
{
PrependAlphaList(&proc_attr,"command");
}
if (SelectProcRegexMatch("TTY","TTY",a.process_select.tty,names,column))
{
PrependAlphaList(&proc_attr,"tty");
}
if ((result = EvalProcessResult(a.process_select.process_result,&proc_attr)))
{
//ClassesFromString(fp->defines);
}
DeleteAlphaList(&proc_attr);
if (result)
{
if (a.transaction.action == cfa_warn)
{
CfOut(cf_error,""," !! Matched: %s\n",procentry);
}
else
{
CfOut(cf_inform,""," !! Matched: %s\n",procentry);
}
}
for (i = 0; column[i] != NULL; i++)
{
free(column[i]);
}
return result;
}
/***************************************************************************/
/* Level */
/***************************************************************************/
static int SelectProcRangeMatch(char *name1,char *name2,int min,int max,char **names,char **line)
{ int i;
long value;
if (min == CF_NOINT || max == CF_NOINT)
{
return false;
}
if ((i = GetProcColumnIndex(name1,name2,names)) != -1)
{
value = Str2Int(line[i]);
if (value == CF_NOINT)
{
CfOut(cf_inform,"","Failed to extract a valid integer from %s => \"%s\" in process list\n",names[i],line[i]);
return false;
}
if (min <= value && value <= max)
{
return true;
}
else
{
return false;
}
}
return false;
}
/***************************************************************************/
static int SelectProcTimeCounterRangeMatch(char *name1,char *name2,time_t min,time_t max,char **names,char **line)
{ int i;
time_t value;
if (min == CF_NOINT || max == CF_NOINT)
{
return false;
}
if ((i = GetProcColumnIndex(name1,name2,names)) != -1)
{
value = (time_t) TimeCounter2Int(line[i]);
if (value == CF_NOINT)
{
CfOut(cf_inform,"","Failed to extract a valid integer from %s => \"%s\" in process list\n",name1[i],line[i]);
return false;
}
if (min <= value && value <= max)
{
CfOut(cf_verbose,"","Selection filter matched counter range %s/%s = %s in [%ld,%ld] (= %ld secs)\n",name1,name2,line[i],min,max,value);
return true;
}
else
{
Debug("Selection filter REJECTED counter range %s/%s = %s in [%ld,%ld] (= %ld secs)\n",name1,name2,line[i],min,max,value);
return false;
}
}
return false;
}
/***************************************************************************/
static int SelectProcTimeAbsRangeMatch(char *name1,char *name2,time_t min,time_t max,char **names,char **line)
{ int i;
time_t value;
if (min == CF_NOINT || max == CF_NOINT)
{
return false;
}
if ((i = GetProcColumnIndex(name1,name2,names)) != -1)
{
value = (time_t)TimeAbs2Int(line[i]);
if (value == CF_NOINT)
{
CfOut(cf_inform,"","Failed to extract a valid integer from %s => \"%s\" in process list\n",name1[i],line[i]);
return false;
}
if (min <= value && value <= max)
{
CfOut(cf_verbose,"","Selection filter matched absolute %s/%s = %s in [%ld,%ld]\n",name1,name2,line[i],min,max);
return true;
}
else
{
return false;
}
}
return false;
}
/***************************************************************************/
static int SelectProcRegexMatch(char *name1,char *name2,char *regex,char **colNames,char **line)
{ int i;
if (regex == NULL)
{
return false;
}
if ((i = GetProcColumnIndex(name1,name2,colNames)) != -1)
{
if (FullTextMatch(regex,line[i]))
{
return true;
}
else
{
return false;
}
}
return false;
}
/*******************************************************************/
static int SplitProcLine(char *proc,char **names,int *start,int *end,char **line)
{ int i,s,e;
char *sp = NULL;
char cols1[CF_PROCCOLS][CF_SMALLBUF] = { "" };
char cols2[CF_PROCCOLS][CF_SMALLBUF] = { "" };
Debug("SplitProcLine(%s)\n",proc);
if (proc == NULL || strlen(proc) == 0)
{
return false;
}
memset(line, 0, sizeof(char *) * CF_PROCCOLS);
// First try looking at all the separable items
sp = proc;
for (i = 0; i < CF_PROCCOLS && names[i] != NULL; i++)
{
while(*sp == ' ')
{
sp++;
}
if (strcmp(names[i],"CMD") == 0 || strcmp(names[i],"COMMAND") == 0)
{
sscanf(sp,"%127[^\n]",cols1[i]);
sp += strlen(cols1[i]);
}
else
{
sscanf(sp,"%127s",cols1[i]);
sp += strlen(cols1[i]);
}
// Some ps stimes may contain spaces, e.g. "Jan 25"
if (strcmp(names[i],"STIME") == 0 && strlen(cols1[i]) == 3)
{
char s[CF_SMALLBUF] = {0};
sscanf(sp,"%127s",s);
strcat(cols1[i]," ");
strcat(cols1[i],s);
sp += strlen(s)+1;
}
}
// Now try looking at columne alignment
for (i = 0; i < CF_PROCCOLS && names[i] != NULL; i++)
{
// Start from the header/column tab marker and count backwards until we find 0 or space
for (s = start[i]; (s >= 0) && !isspace((int)*(proc+s)); s--)
{
}
if (s < 0)
{
s = 0;
}
// Make sure to strip off leading spaces
while (isspace((int)proc[s]))
{
s++;
}
if (strcmp(names[i],"CMD") == 0 || strcmp(names[i],"COMMAND") == 0)
{
e = strlen(proc);
}
else
{
for (e = end[i]; (e <= end[i]+10) && !isspace((int)*(proc+e)); e++)
{
}
while (isspace((int)proc[e]))
{
if (e > 0)
{
e--;
}
}
}
if (s <= e)
{
strncpy(cols2[i],(char *)(proc+s),MIN(CF_SMALLBUF-1,(e-s+1)));
}
else
{
cols2[i][0] = '\0';
}
Chop(cols2[i]);
if (strcmp(cols2[i],cols1[i]) != 0)
{
CfOut(cf_inform,""," !! Unacceptable model uncertainty examining processes");
}
line[i] = strdup(cols1[i]);
}
return true;
}
/*******************************************************************/
static int GetProcColumnIndex(char *name1,char *name2,char **names)
{ int i;
for (i = 0; names[i] != NULL; i++)
{
if ((strcmp(names[i],name1) == 0) || (strcmp(names[i],name2) == 0))
{
return i;
}
}
CfOut(cf_verbose,""," INFO - process column %s/%s was not supported on this system",name1,name2);
return -1;
}
/**********************************************************************************/
bool IsProcessNameRunning(char *procNameRegex)
{
char *colHeaders[CF_PROCCOLS];
struct Item *ip;
int start[CF_PROCCOLS] = {0};
int end[CF_PROCCOLS] = {0};
bool matched = false;
if (PROCESSTABLE == NULL)
{
CfOut(cf_error, "", "!! IsProcessNameRunning: PROCESSTABLE is empty");
return false;
}
GetProcessColumnNames(PROCESSTABLE->name,(char **)colHeaders,start,end);
for (ip = PROCESSTABLE->next; ip != NULL; ip=ip->next) // iterate over ps lines
{
if(EMPTY(ip->name))
{
continue;
}
char *lineSplit[CF_PROCCOLS];
if (!SplitProcLine(ip->name,colHeaders,start,end,lineSplit))
{
CfOut(cf_error, "", "!! IsProcessNameRunning: Could not split process line \"%s\"", ip->name);
continue;
}
if (SelectProcRegexMatch("CMD","COMMAND",procNameRegex,colHeaders,lineSplit))
{
matched = true;
break;
}
}
return matched;
}
cfengine-3.2.4/src/html.c 0000644 0001750 0001750 00000007002 11715232734 012122 0000000 0000000 /*
Copyright (C) Cfengine AS
This file is part of Cfengine 3 - written and maintained by Cfengine 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 Commerical Open Source License
(COSL) may apply to this file if you as a licensee so wish it. See
included file COSL.txt.
*/
/*****************************************************************************/
/* */
/* File: html.c */
/* */
/*****************************************************************************/
#include "cf3.defs.h"
#include "cf3.extern.h"
static char *URLControl(char *driver,char *url);
/*****************************************************************************/
void CfHtmlHeader(FILE *fp,char *title,char *css,char *webdriver,char *header)
{
if (title == NULL)
{
title = "Cfengine Knowledge";
}
fprintf(fp,"\n"
" \n"
" \n"
" \n"
" %s\n"
" \n"
" \n"
" \n"
" \n",title,css,css);
if (header && strlen(header) > 0)
{
if (strlen(LICENSE_COMPANY) > 0)
{
fprintf(fp,"
\n");
}
/*******************************************************************/
void ShowAllReservedWords()
{ int i,j,k,l;
struct Item *ip,*list = NULL;
struct SubTypeSyntax *ss;
struct BodySyntax *bs,*bs2;
for (i = 0; CF_ALL_BODIES[i].subtype != NULL; i++)
{
IdempPrependItem(&list,CF_ALL_BODIES[i].subtype,NULL);
bs = CF_ALL_BODIES[i].bs;
for (l = 0; bs[l].lval != NULL; l++)
{
IdempPrependItem(&list,bs[l].lval,NULL);
}
}
/* Now check the functional modules - extra level of indirection */
for (i = 0; i < CF3_MODULES; i++)
{
if ((ss = CF_ALL_SUBTYPES[i]) == NULL)
{
continue;
}
for (j = 0; ss[j].subtype != NULL; j++)
{
if ((bs = ss[j].bs) == NULL)
{
continue;
}
IdempPrependItem(&list,ss[j].subtype,NULL);
for (l = 0; bs[l].range != NULL; l++)
{
if (bs[l].dtype == cf_body)
{
bs2 = (struct BodySyntax *)(bs[l].range);
if (bs2 == NULL || bs2 == (void *)CF_BUNDLE)
{
continue;
}
for (k = 0; bs2[k].dtype != cf_notype; k++)
{
/* Either module defined or common */
IdempPrependItem(&list,bs2[k].lval,NULL);
}
}
}
}
}
for (ip = list; ip != NULL; ip=ip->next)
{
printf(" \"%s\",",ip->name);
}
DeleteItemList(list);
}
/*******************************************************************/
void ReportError(char *s)
{
if (PARSING)
{
yyerror(s);
}
else
{
Chop(s);
FatalError("Validation: %s\n",s);
}
}
cfengine-3.2.4/src/mod_files.c 0000644 0001750 0001750 00000050225 11715232734 013124 0000000 0000000 /*
Copyright (C) Cfengine AS
This file is part of Cfengine 3 - written and maintained by Cfengine 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 Commerical Open Source License
(COSL) may apply to this file if you as a licensee so wish it. See
included file COSL.txt.
*/
/*****************************************************************************/
/* */
/* File: mod_files.c */
/* */
/*****************************************************************************/
/*
This file can act as a template for adding functionality to cfengine 3.
All functionality can be added by extending the main array
CF_MOD_SUBTYPES[CF3_MODULES]
and its array dimension, in mod_common, in the manner shown here.
*/
#define CF3_MOD_FILES
#include "cf3.defs.h"
#include "cf3.extern.h"
/***********************************************************/
/* Read this module file backwards, as dependencies have */
/* to be defined first - these arrays declare pairs of */
/* constraints */
/* */
/* lval => rval */
/* */
/* in the form (lval,type,range) */
/* */
/* If the type is cf_body then the range is a pointer */
/* to another array of pairs, like in a body "sub-routine" */
/* */
/***********************************************************/
/**************************************************************/
/* editing */
/**************************************************************/
struct BodySyntax CF_LOCATION_BODY[] =
{
{"before_after",cf_opts,"before,after","Menu option, point cursor before of after matched line"},
{"first_last",cf_opts,"first,last","Menu option, choose first or last occurrence of match in file"},
{"select_line_matching",cf_str,CF_ANYSTRING,"Regular expression for matching file line location"},
{NULL,cf_notype,NULL,NULL}
};
/**************************************************************/
struct BodySyntax CF_EDITCOL_BODY[] =
{
{"allow_blank_fields",cf_opts,CF_BOOL,"true/false allow blank fields in a line (do not purge)"},
{"extend_fields",cf_opts,CF_BOOL,"true/false add new fields at end of line if necessary to complete edit"},
{"field_operation",cf_opts,"prepend,append,alphanum,delete,set","Menu option policy for editing subfields"},
{"field_separator",cf_str,CF_ANYSTRING,"The regular expression used to separate fields in a line"},
{"field_value",cf_str,CF_ANYSTRING,"Set field value to a fixed value"},
{"select_field",cf_int,"0,99999999","Integer index of the field required 0..n (default starts from 1)"},
{"start_fields_from_zero",cf_opts,CF_BOOL,"If set, the default field numbering starts from 0"},
{"value_separator",cf_str,CF_CHARRANGE,"Character separator for subfields inside the selected field"},
{NULL,cf_notype,NULL,NULL}
};
/**************************************************************/
struct BodySyntax CF_REPLACEWITH_BODY[] =
{
{"occurrences",cf_opts,"all,first","Menu option to replace all occurrences or just first (NB the latter is non-convergent)"},
{"replace_value",cf_str,CF_ANYSTRING,"Value used to replace regular expression matches in search"},
{NULL,cf_notype,NULL,NULL}
};
/**************************************************************/
struct BodySyntax CF_EDSCOPE_BODY[] =
{
{"include_start_delimiter",cf_opts,CF_BOOL,"Whether to include the section delimiter"},
{"include_end_delimiter",cf_opts,CF_BOOL,"Whether to include the section delimiter"},
{"select_start",cf_str,CF_ANYSTRING,"Regular expression matching start of edit region"},
{"select_end",cf_str,CF_ANYSTRING,"Regular expression matches end of edit region from start"},
{NULL,cf_notype,NULL,NULL}
};
/**************************************************************/
struct BodySyntax CF_DELETESELECT_BODY[] =
{
{"delete_if_startwith_from_list",cf_slist,CF_ANYSTRING,"Delete line if it starts with a string in the list"},
{"delete_if_not_startwith_from_list",cf_slist,CF_ANYSTRING,"Delete line if it DOES NOT start with a string in the list"},
{"delete_if_match_from_list",cf_slist,CF_ANYSTRING,"Delete line if it fully matches a regex in the list"},
{"delete_if_not_match_from_list",cf_slist,CF_ANYSTRING,"Delete line if it DOES NOT fully match a regex in the list"},
{"delete_if_contains_from_list",cf_slist,CF_ANYSTRING,"Delete line if a regex in the list match a line fragment"},
{"delete_if_not_contains_from_list",cf_slist,CF_ANYSTRING,"Delete line if a regex in the list DOES NOT match a line fragment"},
{NULL,cf_notype,NULL,NULL}
};
/**************************************************************/
struct BodySyntax CF_INSERTSELECT_BODY[] =
{
{"insert_if_startwith_from_list",cf_slist,CF_ANYSTRING,"Insert line if it starts with a string in the list"},
{"insert_if_not_startwith_from_list",cf_slist,CF_ANYSTRING,"Insert line if it DOES NOT start with a string in the list"},
{"insert_if_match_from_list",cf_slist,CF_ANYSTRING,"Insert line if it fully matches a regex in the list"},
{"insert_if_not_match_from_list",cf_slist,CF_ANYSTRING,"Insert line if it DOES NOT fully match a regex in the list"},
{"insert_if_contains_from_list",cf_slist,CF_ANYSTRING,"Insert line if a regex in the list match a line fragment"},
{"insert_if_not_contains_from_list",cf_slist,CF_ANYSTRING,"Insert line if a regex in the list DOES NOT match a line fragment"},
{NULL,cf_notype,NULL,NULL}
};
/**************************************************************/
struct BodySyntax CF_INSERTLINES_BODIES[] =
{
{"expand_scalars",cf_opts,CF_BOOL,"Expand any unexpanded variables"},
{"insert_type",cf_opts,"literal,string,file,preserve_block","Type of object the promiser string refers to"},
{"insert_select",cf_body,CF_INSERTSELECT_BODY,"Insert only if lines pass filter criteria"},
{"location",cf_body,CF_LOCATION_BODY,"Specify where in a file an insertion will be made"},
{"whitespace_policy",cf_olist,"ignore_leading,ignore_trailing,ignore_embedded,exact_match","Criteria for matching and recognizing existing lines"},
{NULL,cf_notype,NULL,NULL}
};
/**************************************************************/
struct BodySyntax CF_DELETELINES_BODIES[] =
{
{"delete_select",cf_body,CF_DELETESELECT_BODY,"Delete only if lines pass filter criteria"},
{"not_matching",cf_opts,CF_BOOL,"true/false negate match criterion"},
{NULL,cf_notype,NULL,NULL}
};
/**************************************************************/
struct BodySyntax CF_COLUMN_BODIES[] =
{
{"edit_field",cf_body,CF_EDITCOL_BODY,"Edit line-based file as matrix of fields"},
{NULL,cf_notype,NULL,NULL}
};
/**************************************************************/
struct BodySyntax CF_REPLACE_BODIES[] =
{
{"replace_with",cf_body,CF_REPLACEWITH_BODY,"Search-replace pattern"},
{NULL,cf_notype,NULL,NULL}
};
/**************************************************************/
/* Common to all edit_line promises */
/**************************************************************/
struct BodySyntax CF_COMMON_EDITBODIES[] =
{
{"select_region",cf_body,CF_EDSCOPE_BODY,"Limit edits to a demarked region of the file"},
{NULL,cf_notype,NULL,NULL}
};
/**************************************************************/
/* Main files */
/**************************************************************/
struct BodySyntax CF_ACL_BODY[] =
{
{"aces",cf_slist,"((user|group):[^:]+:[-=+,rwx()dtTabBpcoD]*(:(allow|deny))?)|((all|mask):[-=+,rwx()]*(:(allow|deny))?)","Native settings for access control entry"},
{"acl_directory_inherit",cf_opts,"nochange,parent,specify,clear","Access control list type for the affected file system"},
{"acl_method",cf_opts,"append,overwrite","Editing method for access control list"},
{"acl_type",cf_opts,"generic,posix,ntfs","Access control list type for the affected file system"},
{"specify_inherit_aces",cf_slist,"((user|group):[^:]+:[-=+,rwx()dtTabBpcoD]*(:(allow|deny))?)|((all|mask):[-=+,rwx()]*(:(allow|deny))?)","Native settings for access control entry"},
{NULL,cf_notype,NULL,NULL}
};
/**************************************************************/
struct BodySyntax CF_CHANGEMGT_BODY[] =
{
{"hash",cf_opts,"md5,sha1,sha224,sha256,sha384,sha512,best","Hash files for change detection"},
{"report_changes",cf_opts,"all,stats,content,none","Specify criteria for change warnings"},
{"update_hashes",cf_opts,CF_BOOL,"Update hash values immediately after change warning"},
{"report_diffs",cf_opts,CF_BOOL,"Generate reports summarizing the major differences between individual text files"},
{NULL,cf_notype,NULL,NULL}
};
/**************************************************************/
struct BodySyntax CF_RECURSION_BODY[] =
{
{"depth",cf_int,CF_VALRANGE,"Maximum depth level for search"},
{"exclude_dirs",cf_slist,".*","List of regexes of directory names NOT to include in depth search"},
{"include_basedir",cf_opts,CF_BOOL,"true/false include the start/root dir of the search results"},
{"include_dirs",cf_slist,".*","List of regexes of directory names to include in depth search"},
{"rmdeadlinks",cf_opts,CF_BOOL,"true/false remove links that point to nowhere"},
{"traverse_links",cf_opts,CF_BOOL,"true/false traverse symbolic links to directories (false)"},
{"xdev",cf_opts,CF_BOOL,"true/false exclude directories that are on different devices"},
{NULL,cf_notype,NULL,NULL}
};
/**************************************************************/
struct BodySyntax CF_EDITS_BODY[] =
{
{"edit_backup",cf_opts,"true,false,timestamp,rotate","Menu option for backup policy on edit changes"},
{"empty_file_before_editing",cf_opts,CF_BOOL,"Baseline memory model of file to zero/empty before commencing promised edits"},
{"max_file_size",cf_int,CF_VALRANGE,"Do not edit files bigger than this number of bytes"},
{"recognize_join",cf_opts,CF_BOOL,"Join together lines that end with a backslash, up to 4kB limit"},
{NULL,cf_notype,NULL,NULL}
};
/**************************************************************/
struct BodySyntax CF_TIDY_BODY[] =
{
{"dirlinks",cf_opts,"delete,tidy,keep","Menu option policy for dealing with symbolic links to directories during deletion"},
{"rmdirs",cf_opts,CF_BOOL,"true/false whether to delete empty directories during recursive deletion"},
{NULL,cf_notype,NULL,NULL}
};
/**************************************************************/
struct BodySyntax CF_RENAME_BODY[] =
{
{"disable",cf_opts,CF_BOOL,"true/false automatically rename and remove permissions"},
{"disable_mode",cf_str,CF_MODERANGE,"The permissions to set when a file is disabled"},
{"disable_suffix",cf_str,"","The suffix to add to files when disabling (.cfdisabled)"},
{"newname",cf_str,"","The desired name for the current file"},
{"rotate",cf_int,"0,99","Maximum number of file rotations to keep"},
{NULL,cf_notype,NULL,NULL}
};
/**************************************************************/
struct BodySyntax CF_ACCESS_BODIES[] =
{
{"bsdflags",cf_slist,CF_BSDFLAGRANGE,"List of menu options for bsd file system flags to set"},
{"groups",cf_slist,CF_USERRANGE,"List of acceptable groups of group ids, first is change target"},
{"mode",cf_str,CF_MODERANGE,"File permissions (like posix chmod)"},
{"owners",cf_slist,CF_USERRANGE,"List of acceptable owners or user ids, first is change target"},
{"rxdirs",cf_opts,CF_BOOL,"true/false add execute flag for directories if read flag is set"},
{NULL,cf_notype,NULL,NULL}
};
/**************************************************************/
struct BodySyntax CF_FILEFILTER_BODY[] =
{
{"leaf_name",cf_slist,"","List of regexes that match an acceptable name"},
{"path_name",cf_slist,CF_ABSPATHRANGE,"List of pathnames to match acceptable target"},
{"search_mode",cf_slist,CF_MODERANGE,"A list of mode masks for acceptable file permissions"},
{"search_size",cf_irange,"0,inf","Integer range of file sizes"},
{"search_owners",cf_slist,"","List of acceptable user names or ids for the file, or regexes to match"},
{"search_groups",cf_slist,"","List of acceptable group names or ids for the file, or regexes to match"},
{"search_bsdflags",cf_slist,CF_BSDFLAGRANGE,"String of flags for bsd file system flags expected set"},
{"ctime",cf_irange,CF_TIMERANGE,"Range of change times (ctime) for acceptable files"},
{"mtime",cf_irange,CF_TIMERANGE,"Range of modification times (mtime) for acceptable files"},
{"atime",cf_irange,CF_TIMERANGE,"Range of access times (atime) for acceptable files"},
{"exec_regex",cf_str,CF_ANYSTRING,"Matches file if this regular expression matches any full line returned by the command"},
{"exec_program",cf_str,CF_ABSPATHRANGE,"Execute this command on each file and match if the exit status is zero"},
{"file_types",cf_olist,"plain,reg,symlink,dir,socket,fifo,door,char,block","List of acceptable file types from menu choices"},
{"issymlinkto",cf_slist,"","List of regular expressions to match file objects"},
{"file_result",cf_str,"[!*(leaf_name|path_name|file_types|mode|size|owner|group|atime|ctime|mtime|issymlinkto|exec_regex|exec_program|bsdflags)[|&.]*]*","Logical expression combining classes defined by file search criteria"},
{NULL,cf_notype,NULL,NULL}
};
/**************************************************************/
/* Copy and link are really the same body and should have
non-overlapping patterns so that they are XOR but it's
okay that some names overlap (like source) as there is
no ambiguity in XOR */
struct BodySyntax CF_LINKTO_BODY[] =
{
{"copy_patterns",cf_slist,"","A set of patterns that should be copied ansd synchronized instead of linked"},
{"link_children",cf_opts,CF_BOOL,"true/false whether to link all directory's children to source originals"},
{"link_type",cf_opts,CF_LINKRANGE,"The type of link used to alias the file"},
{"source",cf_str,CF_PATHRANGE,"The source file to which the link should point"},
{"when_linking_children",cf_opts,"override_file,if_no_such_file","Policy for overriding existing files when linking directories of children"},
{"when_no_source",cf_opts,"force,delete,nop","Behaviour when the source file to link to does not exist"},
{NULL,cf_notype,NULL,NULL}
};
/**************************************************************/
struct BodySyntax CF_COPYFROM_BODY[] =
{
/* We use CF_PATHRANGE due to collision with LINKTO_BODY and a bug lurking in
* a verification stage -- this attribute gets picked instead of another
* 'source'
*/
{"source",cf_str,CF_PATHRANGE,"Reference source file from which to copy"},
{"servers",cf_slist,"[A-Za-z0-9_.:-]+","List of servers in order of preference from which to copy"},
{"collapse_destination_dir",cf_opts,CF_BOOL,"true/false Place files in subdirectories into the root destination directory during copy"},
{"compare",cf_opts,"atime,mtime,ctime,digest,hash,exists,binary","Menu option policy for comparing source and image file attributes"},
{"copy_backup",cf_opts,"true,false,timestamp","Menu option policy for file backup/version control"},
{"encrypt",cf_opts,CF_BOOL,"true/false use encrypted data stream to connect to remote host"},
{"check_root",cf_opts,CF_BOOL,"true/false check permissions on the root directory when depth_search"},
{"copylink_patterns",cf_slist,"","List of patterns matching files that should be copied instead of linked"},
{"copy_size",cf_irange,"0,inf","Integer range of file sizes that may be copied"},
{"findertype",cf_opts,"MacOSX","Menu option for default finder type on MacOSX"},
{"linkcopy_patterns",cf_slist,"","List of patterns matching files that should be replaced with symbolic links"},
{"link_type",cf_opts,CF_LINKRANGE,"Menu option for type of links to use when copying"},
{"force_update",cf_opts,CF_BOOL,"true/false force copy update always"},
{"force_ipv4",cf_opts,CF_BOOL,"true/false force use of ipv4 on ipv6 enabled network"},
{"portnumber",cf_int,"1024,99999","Port number to connect to on server host"},
{"preserve",cf_opts,CF_BOOL,"true/false whether to preserve file permissions on copied file"},
{"purge",cf_opts,CF_BOOL,"true/false purge files on client that do not match files on server when a depth_search is used"},
{"stealth",cf_opts,CF_BOOL,"true/false whether to preserve time stamps on copied file"},
{"timeout",cf_int,"1,3600","Connection timeout, seconds"},
{"trustkey",cf_opts,CF_BOOL,"true/false trust public keys from remote server if previously unknown"},
{"type_check",cf_opts,CF_BOOL,"true/false compare file types before copying and require match"},
{"verify",cf_opts,CF_BOOL,"true/false verify transferred file by hashing after copy (resource penalty)"},
{NULL,cf_notype,NULL,NULL}
};
/***************************************************************/
/* This is the primary set of constraints for a file object */
struct BodySyntax CF_FILES_BODIES[] =
{
{"acl",cf_body,CF_ACL_BODY,"Criteria for access control lists on file"},
{"changes",cf_body,CF_CHANGEMGT_BODY,"Criteria for change management"},
{"copy_from",cf_body,CF_COPYFROM_BODY,"Criteria for copying file from a source"},
{"create",cf_opts,CF_BOOL,"true/false whether to create non-existing file"},
{"delete",cf_body,CF_TIDY_BODY,"Criteria for deleting files"},
{"depth_search",cf_body,CF_RECURSION_BODY,"Criteria for file depth searches"},
{"edit_line",cf_bundle,CF_BUNDLE,"Line editing model for file"},
{"edit_xml",cf_bundle,CF_BUNDLE,"XML editing model for file"},
{"edit_defaults",cf_body,CF_EDITS_BODY,"Default promise details for file edits"},
{"file_select",cf_body,CF_FILEFILTER_BODY,"Choose which files select in a search"},
{"link_from",cf_body,CF_LINKTO_BODY,"Criteria for linking file from a source"},
{"move_obstructions",cf_opts,CF_BOOL,"true/false whether to move obstructions to file-object creation"},
{"pathtype",cf_opts,"literal,regex,guess","Menu option for interpreting promiser file object"},
{"perms",cf_body,CF_ACCESS_BODIES,"Criteria for setting permissions on a file"},
{"rename",cf_body,CF_RENAME_BODY,"Criteria for renaming files"},
{"repository",cf_str,CF_ABSPATHRANGE,"Name of a repository for versioning"},
{"touch",cf_opts,CF_BOOL,"true/false whether to touch time stamps on file"},
{"transformer",cf_str,CF_ABSPATHRANGE,"Command (with full path) used to transform current file (no shell wrapper used)"},
{NULL,cf_notype,NULL,NULL}
};
/***************************************************************/
/* This is the point of entry from mod_common.c */
/***************************************************************/
struct SubTypeSyntax CF_FILES_SUBTYPES[] =
{
/* Body lists belonging to "files:" type in Agent */
{"agent","files",CF_FILES_BODIES},
/* Body lists belonging to th edit_line sub-bundle of files: */
{"edit_line","*",CF_COMMON_EDITBODIES},
{"edit_line","delete_lines",CF_DELETELINES_BODIES},
{"edit_line","insert_lines",CF_INSERTLINES_BODIES},
{"edit_line","field_edits",CF_COLUMN_BODIES},
{"edit_line","replace_patterns",CF_REPLACE_BODIES},
{NULL,NULL,NULL},
};
cfengine-3.2.4/src/net.c 0000644 0001750 0001750 00000011376 11715232734 011755 0000000 0000000 /*
Copyright (C) Cfengine AS
This file is part of Cfengine 3 - written and maintained by Cfengine 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 Commerical Open Source License
(COSL) may apply to this file if you as a licensee so wish it. See
included file COSL.txt.
*/
/*********************************************************************/
/* */
/* TOOLKITS: network library */
/* */
/*********************************************************************/
#include "cf3.defs.h"
#include "cf3.extern.h"
/*************************************************************************/
int SendTransaction(int sd,char *buffer,int len,char status)
{ char work[CF_BUFSIZE];
int wlen;
memset(work, 0, sizeof(work));
if (len == 0)
{
wlen = strlen(buffer);
}
else
{
wlen = len;
}
if (wlen > CF_BUFSIZE-CF_INBAND_OFFSET)
{
CfOut(cf_error, "", "SenTransaction: wlen (%d) > %d - %d", wlen, CF_BUFSIZE, CF_INBAND_OFFSET);
FatalError("SendTransaction software failure");
}
snprintf(work,CF_INBAND_OFFSET,"%c %d",status,wlen);
memcpy(work+CF_INBAND_OFFSET,buffer,wlen);
Debug("Transaction Send[%s][Packed text]\n",work);
if (SendSocketStream(sd,work,wlen+CF_INBAND_OFFSET,0) == -1)
{
return -1;
}
return 0;
}
/*************************************************************************/
int ReceiveTransaction(int sd,char *buffer,int *more)
{ char proto[CF_INBAND_OFFSET+1];
char status = 'x';
unsigned int len = 0;
memset(proto,0,CF_INBAND_OFFSET+1);
if (RecvSocketStream(sd,proto,CF_INBAND_OFFSET,0) == -1) /* Get control channel */
{
return -1;
}
sscanf(proto,"%c %u",&status,&len);
Debug("Transaction Receive [%s][%s]\n",proto,proto+CF_INBAND_OFFSET);
if (len > CF_BUFSIZE - CF_INBAND_OFFSET)
{
CfOut(cf_error,"","Bad transaction packet -- too long (%c %d) Proto = %s ",status,len,proto);
return -1;
}
if (strncmp(proto,"CAUTH",5) == 0)
{
Debug("Version 1 protocol connection attempted - no you don't!!\n");
return -1;
}
if (more != NULL)
{
switch(status)
{
case 'm': *more = true;
break;
default: *more = false;
}
}
return RecvSocketStream(sd,buffer,len,0);
}
/*************************************************************************/
int RecvSocketStream(int sd,char buffer[CF_BUFSIZE],int toget,int nothing)
{ int already, got;
static int fraction;
Debug("RecvSocketStream(%d)\n",toget);
if (toget > CF_BUFSIZE-1)
{
CfOut(cf_error,"","Bad software request for overfull buffer");
return -1;
}
for (already = 0; already != toget; already += got)
{
got = recv(sd,buffer+already,toget-already,0);
if (got == -1 && errno == EINTR)
{
continue;
}
if (got == -1)
{
CfOut(cf_verbose,"recv","Couldn't recv");
return -1;
}
if (got == 0) /* doesn't happen unless sock is closed */
{
Debug("Transmission empty or timed out...\n");
fraction = 0;
buffer[already] = '\0';
return already;
}
Debug(" (Concatenated %d from stream)\n",got);
if (strncmp(buffer,"AUTH",4) == 0 && (already == CF_BUFSIZE))
{
fraction = 0;
buffer[already] = '\0';
return already;
}
}
buffer[toget] = '\0';
return toget;
}
/*************************************************************************/
int SendSocketStream(int sd,char buffer[CF_BUFSIZE],int tosend,int flags)
{ int sent,already=0;
do
{
Debug("Attempting to send %d bytes\n",tosend-already);
sent = send(sd,buffer+already,tosend-already,flags);
if (sent == -1 && errno == EINTR)
{
continue;
}
if (sent == -1)
{
CfOut(cf_verbose,"send","Couldn't send");
return -1;
}
Debug("SendSocketStream, sent %d\n",sent);
already += sent;
}
while (already < tosend);
return already;
}
/*************************************************************************/
cfengine-3.2.4/src/storage_tools.c 0000644 0001750 0001750 00000011076 11715232734 014050 0000000 0000000 /*
Copyright (C) Cfengine AS
This file is part of Cfengine 3 - written and maintained by Cfengine 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 Commerical Open Source License
(COSL) may apply to this file if you as a licensee so wish it. See
included file COSL.txt.
*/
/*****************************************************************************/
/* */
/* File: storage_tools.c */
/* */
/*****************************************************************************/
#include "cf3.defs.h"
#include "cf3.extern.h"
#ifdef HAVE_SYS_STATFS_H
#include
#endif
#ifdef HAVE_SYS_VFS_H
#include
#endif
#ifdef HAVE_SYS_STATVFS_H
#include
#endif
#ifndef MINGW
static off_t Unix_GetDiskUsage(char *file, enum cfsizes type);
#endif /* NOT MINGW */
/************************************************************************/
off_t GetDiskUsage(char *file,enum cfsizes type)
{
#ifdef MINGW
return NovaWin_GetDiskUsage(file, type);
#else
return Unix_GetDiskUsage(file, type);
#endif
}
/************************************************************************/
/* Unix implementations */
/************************************************************************/
#ifndef MINGW
static off_t Unix_GetDiskUsage(char *file,enum cfsizes type)
{
#if defined SOLARIS || defined OSF || defined UNIXWARE || defined OPENBSD || (defined(__NetBSD__) && __NetBSD_Version__ >= 200040000)
struct statvfs buf;
#elif defined ULTRIX
struct fs_data buf;
#else
struct statfs buf;
#endif
off_t used = 0, avail = 0;
int capacity = 0;
memset(&buf,0,sizeof(buf));
#if defined ULTRIX
if (getmnt(NULL,&buf, sizeof(struct fs_data), STAT_ONE, file) == -1)
{
CfOut(cf_error,"getmnt","Couldn't get filesystem info for %s\n",file);
return CF_INFINITY;
}
#elif defined SOLARIS || defined OSF || defined UNIXWARE || (defined(__NetBSD__) && __NetBSD_Version__ >= 200040000)
if (statvfs(file,&buf) != 0)
{
CfOut(cf_error,"statvfs","Couldn't get filesystem info for %s\n",file);
return CF_INFINITY;
}
#elif defined IRIX || defined SCO || defined CFCRAY || (defined(__NetBSD__) && __NetBSD_Version__ >= 200040000)
if (statfs (file, &buf, sizeof (struct statfs), 0) != 0)
{
CfOut(cf_error,"statfs","Couldn't get filesystem info for %s\n",file);
return CF_INFINITY;
}
#else
if (statfs(file, &buf) != 0)
{
CfOut(cf_error,"statfs","Couldn't get filesystem info for %s\n",file);
return CF_INFINITY;
}
#endif
#if defined ULTRIX
used = buf.fd_btot - buf.fd_bfree;
avail = buf.fd_bfreen;
#endif
#if defined SOLARIS
used = (buf.f_blocks - buf.f_bfree) * buf.f_frsize;
avail = buf.f_bavail * buf.f_frsize;
#endif
#if defined NETBSD || defined FREEBSD || defined OPENBSD || defined SUNOS || defined HPuUX || defined DARWIN
used = (buf.f_blocks - buf.f_bfree) * buf.f_bsize;
avail = buf.f_bavail * buf.f_bsize;
#endif
#if defined OSF
used = (buf.f_blocks - buf.f_bfree) * buf.f_frsize;
avail = buf.f_bavail * buf.f_frsize;
#endif
#if defined AIX || defined SCO || defined CFCRAY
used = (buf.f_blocks - buf.f_bfree) * (float)buf.f_bsize;
avail = buf.f_bfree * (float)buf.f_bsize;
#endif
#if defined LINUX
used = (buf.f_blocks - buf.f_bfree) * (float)buf.f_bsize;
avail = buf.f_bavail * (float)buf.f_bsize;
#endif
#if defined IRIX
/* Float fix by arjen@sara.nl */
used = (buf.f_blocks - buf.f_bfree) * (float)buf.f_bsize;
avail = buf.f_bfree * (float)buf.f_bsize;
#endif
capacity = (double) (avail) / (double) (avail + used) * 100;
Debug2("GetDiskUsage(%s) = %d/%d\n",file,avail,capacity);
/* Free kilobytes */
if (type == cfabs)
{
return avail;
}
else
{
return capacity;
}
}
#endif /* NOT MINGW */
cfengine-3.2.4/src/files_edit.c 0000644 0001750 0001750 00000021767 11715232734 013303 0000000 0000000 /*
Copyright (C) Cfengine AS
This file is part of Cfengine 3 - written and maintained by Cfengine 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 Commerical Open Source License
(COSL) may apply to this file if you as a licensee so wish it. See
included file COSL.txt.
*/
/*****************************************************************************/
/* */
/* File: files_edit.c */
/* */
/*****************************************************************************/
#include "cf3.defs.h"
#include "cf3.extern.h"
/*****************************************************************************/
struct edit_context *NewEditContext(char *filename,struct Attributes a,struct Promise *pp)
{ struct edit_context *ec;
if (!IsAbsoluteFileName(filename))
{
CfOut(cf_error,"","Relative file name %s was marked for editing but has no invariant meaning\n",filename);
return NULL;
}
if ((ec = malloc(sizeof(struct edit_context))) == NULL)
{
return NULL;
}
ec->filename = filename;
ec->file_start = NULL;
ec->file_classes = NULL;
ec->num_edits = 0;
ec->empty_first = a.edits.empty_before_use;
if (!LoadFileAsItemList(&(ec->file_start),filename,a,pp))
{
free(ec);
return NULL;
}
if (a.edits.empty_before_use)
{
CfOut(cf_verbose,""," -> Build file model from a blank slate (emptying)\n");
DeleteItemList(ec->file_start);
ec->file_start = NULL;
}
EDIT_MODEL = true;
return ec;
}
/*****************************************************************************/
void FinishEditContext(struct edit_context *ec,struct Attributes a,struct Promise *pp)
{
struct Item *ip;
EDIT_MODEL = false;
if (DONTDO || a.transaction.action == cfa_warn)
{
if (ec && !CompareToFile(ec->file_start,ec->filename,a,pp) && ec->num_edits > 0)
{
cfPS(cf_error,CF_WARN,"",pp,a," -> Should edit file %s but only a warning promised",ec->filename);
}
return;
}
else if (ec && ec->num_edits > 0)
{
if (CompareToFile(ec->file_start,ec->filename,a,pp))
{
if (ec)
{
cfPS(cf_verbose,CF_NOP,"",pp,a," -> No edit changes to file %s need saving",ec->filename);
}
}
else
{
SaveItemListAsFile(ec->file_start,ec->filename,a,pp);
}
}
else
{
if (ec)
{
cfPS(cf_verbose,CF_NOP,"",pp,a," -> No edit changes to file %s need saving",ec->filename);
}
}
if (ec != NULL)
{
for (ip = ec->file_classes; ip != NULL; ip = ip->next)
{
NewClass(ip->name);
}
DeleteItemList(ec->file_classes);
DeleteItemList(ec->file_start);
}
}
/*********************************************************************/
/* Level */
/*********************************************************************/
int LoadFileAsItemList(struct Item **liststart,char *file,struct Attributes a,struct Promise *pp)
{ FILE *fp;
struct stat statbuf;
char line[CF_BUFSIZE],concat[CF_BUFSIZE];
int join = false;
if (cfstat(file,&statbuf) == -1)
{
CfOut(cf_verbose,"stat"," ** Information: the proposed file \"%s\" could not be loaded",file);
return false;
}
if (a.edits.maxfilesize != 0 && statbuf.st_size > a.edits.maxfilesize)
{
CfOut(cf_inform,""," !! File %s is bigger than the limit edit.max_file_size = %d > %d bytes\n",file,statbuf.st_size,a.edits.maxfilesize);
return(false);
}
if (! S_ISREG(statbuf.st_mode))
{
cfPS(cf_inform,CF_INTERPT,"",pp,a,"%s is not a plain file\n",file);
return false;
}
if ((fp = fopen(file,"r")) == NULL)
{
cfPS(cf_inform,CF_INTERPT,"fopen",pp,a,"Couldn't read file %s for editing\n",file);
return false;
}
memset(line,0,CF_BUFSIZE);
memset(concat,0,CF_BUFSIZE);
while(!feof(fp))
{
CfReadLine(line,CF_BUFSIZE-1,fp);
if (a.edits.joinlines && *(line+strlen(line)-1) == '\\')
{
join = true;
}
else
{
join = false;
}
if (join)
{
*(line+strlen(line)-1) = '\0';
JoinSuffix(concat,line);
}
else
{
JoinSuffix(concat,line);
if (!feof(fp) || (strlen(concat) != 0))
{
AppendItem(liststart,concat,NULL);
}
concat[0] = '\0';
join = false;
}
line[0] = '\0';
}
fclose(fp);
return (true);
}
/*********************************************************************/
int SaveItemListAsFile(struct Item *liststart,char *file,struct Attributes a,struct Promise *pp)
{ struct Item *ip;
struct stat statbuf;
char new[CF_BUFSIZE],backup[CF_BUFSIZE];
FILE *fp;
mode_t mask;
char stamp[CF_BUFSIZE];
time_t stamp_now;
#ifdef WITH_SELINUX
int selinux_enabled=0;
security_context_t scontext=NULL;
selinux_enabled = (is_selinux_enabled() > 0);
if (selinux_enabled)
{
/* get current security context */
getfilecon(file, &scontext);
}
#endif
stamp_now = time((time_t *)NULL);
if (cfstat(file,&statbuf) == -1)
{
cfPS(cf_error,CF_FAIL,"stat",pp,a," !! Can no longer access file %s, which needed editing!\n",file);
return false;
}
strcpy(backup,file);
if (a.edits.backup == cfa_timestamp)
{
snprintf(stamp,CF_BUFSIZE,"_%d_%s", CFSTARTTIME,CanonifyName(cf_ctime(&stamp_now)));
strcat(backup,stamp);
}
strcat(backup,".cf-before-edit");
strcpy(new,file);
strcat(new,".cf-after-edit");
unlink(new); /* Just in case of races */
if ((fp = fopen(new,"w")) == NULL)
{
cfPS(cf_error,CF_FAIL,"fopen",pp,a,"Couldn't write file %s after editing\n",new);
return false;
}
for (ip = liststart; ip != NULL; ip=ip->next)
{
fprintf(fp,"%s\n",ip->name);
}
if (fclose(fp) == -1)
{
cfPS(cf_error,CF_FAIL,"fclose",pp,a,"Unable to close file while writing","fclose");
return false;
}
cfPS(cf_inform,CF_CHG,"",pp,a," -> Edited file %s \n",file);
if (cf_rename(file,backup) == -1)
{
cfPS(cf_error,CF_FAIL,"cf_rename",pp,a," !! Can't rename %s to %s - so promised edits could not be moved into place\n",file,backup);
return false;
}
if (a.edits.backup != cfa_nobackup)
{
if (ArchiveToRepository(backup,a,pp))
{
unlink(backup);
}
}
else
{
unlink(backup);
}
if (cf_rename(new,file) == -1)
{
cfPS(cf_error,CF_FAIL,"cf_rename",pp,a," !! Can't rename %s to %s - so promised edits could not be moved into place\n",new,file);
return false;
}
mask = umask(0);
cf_chmod(file,statbuf.st_mode); /* Restore file permissions etc */
chown(file,statbuf.st_uid,statbuf.st_gid);
umask(mask);
#ifdef WITH_SELINUX
if (selinux_enabled)
{
/* restore file context */
setfilecon(file,scontext);
}
#endif
return true;
}
/*********************************************************************/
int AppendIfNoSuchLine(char *filename, char *line)
/* Appends line to the file with path filename if it is not already
there. line should not contain newline.
Returns true if the line is there on exit, false on error. */
{
FILE *fread,*fappend;
char lineCp[CF_MAXVARSIZE], lineBuf[CF_MAXVARSIZE];
int lineExists = false;
int result = false;
size_t written = 0;
if ((fread = fopen(filename,"rw")) == NULL)
{
CfOut(cf_error,"fopen","!! Cannot open the file \"%s\" for read", filename);
return false;
}
while(CfReadLine(lineBuf,sizeof(lineBuf),fread)) // strips newlines automatically
{
if(strcmp(line,lineBuf) == 0)
{
lineExists = true;
result = true;
break;
}
}
fclose(fread);
if(!lineExists)
// we are at EOF and line does not exist already
{
if((fappend = fopen(filename,"a")) == NULL)
{
CfOut(cf_error,"fopen","!! Cannot open the file \"%s\" for append", filename);
return false;
}
if(line[strlen(line) - 1] == '\n')
{
snprintf(lineCp,sizeof(lineCp),"%s",line);
}
else
{
snprintf(lineCp,sizeof(lineCp),"%s\n",line);
}
written = fwrite(lineCp, sizeof(char), strlen(lineCp), fappend);
if(written == strlen(lineCp))
{
result = true;
}
else
{
CfOut(cf_error, "fwrite", "!! Could not write %d characters to \"%s\" (wrote %d)", strlen(lineCp), filename, written);
result = false;
}
fclose(fappend);
}
return result;
}
cfengine-3.2.4/src/unix.c 0000644 0001750 0001750 00000046105 11715232734 012150 0000000 0000000 /*
Copyright (C) Cfengine AS
This file is part of Cfengine 3 - written and maintained by Cfengine 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 Commerical Open Source License
(COSL) may apply to this file if you as a licensee so wish it. See
included file COSL.txt.
*/
/*****************************************************************************/
/* */
/* File: unix.c */
/* */
/*****************************************************************************/
#include "cf3.defs.h"
#include "cf3.extern.h"
#ifdef HAVE_SYS_UIO_H
# include
#endif
#ifndef MINGW
#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
# ifdef _SIZEOF_ADDR_IFREQ
# define SIZEOF_IFREQ(x) _SIZEOF_ADDR_IFREQ(x)
# else
# define SIZEOF_IFREQ(x) \
((x).ifr_addr.sa_len > sizeof(struct sockaddr) ? \
(sizeof(struct ifreq) - sizeof(struct sockaddr) + \
(x).ifr_addr.sa_len) : sizeof(struct ifreq))
# endif
#else
# define SIZEOF_IFREQ(x) sizeof(struct ifreq)
#endif
/*****************************************************************************/
/* newly created, used in timeout.c and transaction.c */
int Unix_GracefulTerminate(pid_t pid)
{ int res;
if ((res = kill(pid,SIGINT)) == -1)
{
sleep(1);
res = 0;
if ((res = kill(pid,SIGTERM)) == -1)
{
sleep(5);
res = 0;
if ((res = kill(pid,SIGKILL)) == -1)
{
sleep(1);
}
}
}
return (res == 0);
}
/*************************************************************/
int Unix_GetCurrentUserName(char *userName, int userNameLen)
{
struct passwd *user_ptr;
memset(userName, 0, userNameLen);
user_ptr = getpwuid(getuid());
if(user_ptr == NULL)
{
CfOut(cf_error,"getpwuid","Could not get user name of current process, using \"UNKNOWN\"");
strncpy(userName, "UNKNOWN", userNameLen - 1);
return false;
}
strncpy(userName, user_ptr->pw_name, userNameLen - 1);
return true;
}
/*************************************************************/
char *Unix_GetErrorStr(void)
{
return strerror(errno);
}
/*************************************************************/
/* from exec_tools.c */
int Unix_IsExecutable(const char *file)
{ struct stat sb;
gid_t grps[NGROUPS];
int i,n;
if (cfstat(file,&sb) == -1)
{
CfOut(cf_error,"","Proposed executable file \"%s\" doesn't exist",file);
return false;
}
if (sb.st_mode & 02)
{
CfOut(cf_error,""," !! SECURITY ALERT: promised executable \"%s\" is world writable! ",file);
CfOut(cf_error,""," !! SECURITY ALERT: cfengine will not execute this - requires human inspection");
return false;
}
if (getuid() == sb.st_uid || getuid() == 0)
{
if (sb.st_mode & 0100)
{
return true;
}
}
else if (getgid() == sb.st_gid)
{
if (sb.st_mode & 0010)
{
return true;
}
}
else
{
if (sb.st_mode & 0001)
{
return true;
}
if ((n = getgroups(NGROUPS,grps)) > 0)
{
for (i = 0; i < n; i++)
{
if (grps[i] == sb.st_gid)
{
if (sb.st_mode & 0010)
{
return true;
}
}
}
}
}
return false;
}
/*******************************************************************/
/* from exec_tools.c */
int Unix_ShellCommandReturnsZero(char *comm,int useshell)
{ int status, i, argc = 0;
pid_t pid;
char arg[CF_MAXSHELLARGS][CF_BUFSIZE];
char **argv;
char esc_command[CF_BUFSIZE];
if (!useshell)
{
/* Build argument array */
for (i = 0; i < CF_MAXSHELLARGS; i++)
{
memset (arg[i],0,CF_BUFSIZE);
}
argc = ArgSplitCommand(comm,arg);
if (argc == -1)
{
CfOut(cf_error,"","Too many arguments in %s\n",comm);
return false;
}
}
if ((pid = fork()) < 0)
{
FatalError("Failed to fork new process");
}
else if (pid == 0) /* child */
{
ALARM_PID = -1;
if (useshell)
{
strncpy(esc_command,ShEscapeCommand(comm),CF_BUFSIZE-1);
if (execl("/bin/sh","sh","-c",esc_command,NULL) == -1)
{
CfOut(cf_error,"execl","Command %s failed",esc_command);
exit(1);
}
}
else
{
argv = (char **) malloc((argc+1)*sizeof(char *));
if (argv == NULL)
{
FatalError("Out of memory");
}
for (i = 0; i < argc; i++)
{
argv[i] = arg[i];
}
argv[i] = (char *) NULL;
if (execv(arg[0],argv) == -1)
{
CfOut(cf_error,"execv","Command %s failed (%d args)",argv[0],argc - 1);
exit(1);
}
free((char *)argv);
}
}
else /* parent */
{
#ifndef HAVE_WAITPID
pid_t wait_result;
#endif
ALARM_PID = pid;
#ifdef HAVE_WAITPID
while(waitpid(pid,&status,0) < 0)
{
if (errno != EINTR)
{
return -1;
}
}
return (WEXITSTATUS(status) == 0);
#else
while ((wait_result = wait(&status)) != pid)
{
if (wait_result <= 0)
{
CfOut(cf_inform,"wait"," !! Wait for child failed\n");
return false;
}
}
if (WIFSIGNALED(status))
{
return false;
}
if (! WIFEXITED(status))
{
return false;
}
return (WEXITSTATUS(status) == 0);
#endif
}
return false;
}
/**********************************************************************************/
/* from verify_processes.c */
int Unix_DoAllSignals(struct Item *siglist,struct Attributes a,struct Promise *pp)
{ struct Item *ip;
struct Rlist *rp;
pid_t pid;
int killed = false;
Debug("DoSignals(%s)\n",pp->promiser);
if (siglist == NULL)
{
return 0;
}
if (a.signals == NULL)
{
CfOut(cf_verbose,""," -> No signals to send for %s\n",pp->promiser);
return 0;
}
for (ip = siglist; ip != NULL; ip=ip->next)
{
pid = ip->counter;
for (rp = a.signals; rp != NULL; rp=rp->next)
{
int signal = Signal2Int(rp->item);
if (!DONTDO)
{
if (signal == SIGKILL || signal == SIGTERM)
{
killed = true;
}
if (kill((pid_t)pid,signal) < 0)
{
cfPS(cf_verbose,CF_FAIL,"kill",pp,a," !! Couldn't send promised signal \'%s\' (%d) to pid %d (might be dead)\n",rp->item,signal,pid);
}
else
{
cfPS(cf_inform,CF_CHG,"",pp,a," -> Signalled '%s' (%d) to process %d (%s)\n", rp->item, signal, pid, ip->name);
}
}
else
{
CfOut(cf_error,""," -> Need to keep signal promise \'%s\' in process entry %s",rp->item,ip->name);
}
}
}
return killed;
}
/*******************************************************************/
/* from verify_processes.c */
int Unix_LoadProcessTable(struct Item **procdata)
{ FILE *prp;
char pscomm[CF_MAXLINKSIZE], vbuff[CF_BUFSIZE], *sp;
struct Item *rootprocs = NULL;
struct Item *otherprocs = NULL;
const char *psopts = GetProcessOptions();
snprintf(pscomm,CF_MAXLINKSIZE,"%s %s",VPSCOMM[VSYSTEMHARDCLASS],psopts);
CfOut(cf_verbose,"","Observe process table with %s\n",pscomm);
if ((prp = cf_popen(pscomm,"r")) == NULL)
{
CfOut(cf_error,"popen","Couldn't open the process list with command %s\n",pscomm);
return false;
}
while (!feof(prp))
{
memset(vbuff,0,CF_BUFSIZE);
CfReadLine(vbuff,CF_BUFSIZE,prp);
for (sp = vbuff+strlen(vbuff)-1; sp > vbuff && isspace(*sp); sp--)
{
*sp = '\0';
}
if (ForeignZone(vbuff))
{
continue;
}
AppendItem(procdata,vbuff,"");
}
cf_pclose(prp);
/* Now save the data */
snprintf(vbuff,CF_MAXVARSIZE,"%s/state/cf_procs",CFWORKDIR);
RawSaveItemList(*procdata,vbuff);
CopyList(&rootprocs,*procdata);
CopyList(&otherprocs,*procdata);
while (DeleteItemNotContaining(&rootprocs,"root"))
{
}
while (DeleteItemContaining(&otherprocs,"root"))
{
}
if (otherprocs)
{
PrependItem(&rootprocs,otherprocs->name,NULL);
}
snprintf(vbuff,CF_MAXVARSIZE,"%s/state/cf_rootprocs",CFWORKDIR);
RawSaveItemList(rootprocs,vbuff);
DeleteItemList(rootprocs);
snprintf(vbuff,CF_MAXVARSIZE,"%s/state/cf_otherprocs",CFWORKDIR);
RawSaveItemList(otherprocs,vbuff);
DeleteItemList(otherprocs);
return true;
}
/*********************************************************************/
/* from files_operators.c */
void Unix_CreateEmptyFile(char *name)
{ int tempfd;
if (unlink(name) == -1)
{
Debug("Pre-existing object %s could not be removed or was not there\n",name);
}
if ((tempfd = open(name, O_CREAT|O_EXCL|O_WRONLY,0600)) < 0)
{
CfOut(cf_error,"open","Couldn't open a file %s\n",name);
}
close(tempfd);
}
/******************************************************************/
static bool IgnoreInterface(int ifaceidx, struct sockaddr_in *inaddr)
{
/* FreeBSD jails */
#ifdef HAVE_JAIL_GET
struct iovec fbsd_jparams[4];
struct in_addr fbsd_jia;
int fbsd_lastjid = 0;
*(const void **)&fbsd_jparams[0].iov_base = "lastjid";
fbsd_jparams[0].iov_len = sizeof("lastjid");
fbsd_jparams[1].iov_base = &fbsd_lastjid;
fbsd_jparams[1].iov_len = sizeof(fbsd_lastjid);
*(const void **)&fbsd_jparams[2].iov_base = "ip4.addr";
fbsd_jparams[2].iov_len = sizeof("ip4.addr");
fbsd_jparams[3].iov_len = sizeof(struct in_addr);
fbsd_jparams[3].iov_base = &fbsd_jia;
while ((fbsd_lastjid = jail_get(fbsd_jparams, 4, 0)) > 0)
{
if (fbsd_jia.s_addr == inaddr->sin_addr.s_addr)
{
CfOut(cf_verbose,"","Interface %d belongs to a FreeBSD jail %s\n",
ifaceidx, inet_ntoa(fbsd_jia));
return true;
}
}
#endif
return false;
}
/******************************************************************/
void Unix_GetInterfaceInfo(enum cfagenttype ag)
{ int fd,len,i,j,first_address = false,ipdefault = false;
struct ifreq ifbuf[CF_IFREQ],ifr, *ifp;
struct ifconf list;
struct sockaddr_in *sin;
struct hostent *hp;
char *sp, workbuf[CF_BUFSIZE];
char ip[CF_MAXVARSIZE];
char name[CF_MAXVARSIZE];
char last_name[CF_BUFSIZE];
Debug("Unix_GetInterfaceInfo()\n");
memset(ifbuf, 0, sizeof(ifbuf));
last_name[0] = '\0';
if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
{
CfOut(cf_error,"socket","Couldn't open socket");
exit(1);
}
list.ifc_len = sizeof(ifbuf);
list.ifc_req = ifbuf;
#ifdef SIOCGIFCONF
if (ioctl(fd, SIOCGIFCONF, &list) == -1 || (list.ifc_len < (sizeof(struct ifreq))))
#else
if (ioctl(fd, OSIOCGIFCONF, &list) == -1 || (list.ifc_len < (sizeof(struct ifreq))))
#endif
{
CfOut(cf_error,"ioctl","Couldn't get interfaces - old kernel? Try setting CF_IFREQ to 1024");
exit(1);
}
last_name[0] = '\0';
for (j = 0,len = 0,ifp = list.ifc_req; len < list.ifc_len; len+=SIZEOF_IFREQ(*ifp),j++,ifp=(struct ifreq *)((char *)ifp+SIZEOF_IFREQ(*ifp)))
{
if (ifp->ifr_addr.sa_family == 0)
{
continue;
}
if (ifp->ifr_name == NULL || strlen(ifp->ifr_name) == 0)
{
continue;
}
/* Skip virtual network interfaces for Linux, which seems to be a problem */
if (strstr(ifp->ifr_name,":"))
{
if (VSYSTEMHARDCLASS == linuxx)
{
CfOut(cf_verbose,"","Skipping apparent virtual interface %d: %s\n",j+1,ifp->ifr_name);
continue;
}
}
else
{
CfOut(cf_verbose,"","Interface %d: %s\n",j+1,ifp->ifr_name);
}
// Ignore the loopback
if (strcmp(ifp->ifr_name,"lo") == 0)
{
continue;
}
if (strncmp(last_name,ifp->ifr_name,sizeof(ifp->ifr_name)) == 0)
{
first_address = false;
}
else
{
strncpy(last_name,ifp->ifr_name,sizeof(ifp->ifr_name));
if (!first_address)
{
NewScalar("sys","interface",last_name,cf_str);
first_address = true;
}
}
snprintf(workbuf,CF_BUFSIZE, "net_iface_%s", CanonifyName(ifp->ifr_name));
NewClass(workbuf);
if (ifp->ifr_addr.sa_family == AF_INET)
{
strncpy(ifr.ifr_name,ifp->ifr_name,sizeof(ifp->ifr_name));
if (ioctl(fd,SIOCGIFFLAGS,&ifr) == -1)
{
CfOut(cf_error,"ioctl","No such network device");
//close(fd);
//return;
continue;
}
if ((ifr.ifr_flags & IFF_BROADCAST) && !(ifr.ifr_flags & IFF_LOOPBACK))
{
sin=(struct sockaddr_in *)&ifp->ifr_addr;
if (IgnoreInterface(j + 1, sin))
{
CfOut(cf_verbose, "", "Ignoring interface %d", j + 1);
continue;
}
Debug("Adding hostip %s..\n",inet_ntoa(sin->sin_addr));
NewClass(inet_ntoa(sin->sin_addr));
if ((hp = gethostbyaddr((char *)&(sin->sin_addr.s_addr),sizeof(sin->sin_addr.s_addr),AF_INET)) == NULL)
{
Debug("No hostinformation for %s not found\n", inet_ntoa(sin->sin_addr));
}
else
{
if (hp->h_name != NULL)
{
Debug("Adding hostname %s..\n",hp->h_name);
NewClass(hp->h_name);
if (hp->h_aliases != NULL)
{
for (i=0; hp->h_aliases[i] != NULL; i++)
{
CfOut(cf_verbose,"","Adding alias %s..\n",hp->h_aliases[i]);
NewClass(hp->h_aliases[i]);
}
}
}
}
if (strcmp(inet_ntoa(sin->sin_addr),"0.0.0.0") == 0)
{
// Maybe we need to do something windows specific here?
CfOut(cf_verbose,""," !! Cannot discover hardware IP, using DNS value");
strcpy(ip,"ipv4_");
strcat(ip,VIPADDRESS);
AppendItem(&IPADDRESSES,VIPADDRESS,"");
for (sp = ip+strlen(ip)-1; (sp > ip); sp--)
{
if (*sp == '.')
{
*sp = '\0';
NewClass(ip);
}
}
strcpy(ip,VIPADDRESS);
i = 3;
for (sp = ip+strlen(ip)-1; (sp > ip); sp--)
{
if (*sp == '.')
{
*sp = '\0';
snprintf(name,CF_MAXVARSIZE-1,"ipv4_%d[%s]",i--,CanonifyName(VIPADDRESS));
NewScalar("sys",name,ip,cf_str);
}
}
//close(fd);
//return;
continue;
}
strncpy(ip,"ipv4_",CF_MAXVARSIZE);
strncat(ip,inet_ntoa(sin->sin_addr),CF_MAXVARSIZE-6);
NewClass(ip);
if (!ipdefault)
{
ipdefault = true;
NewScalar("sys","ipv4",inet_ntoa(sin->sin_addr),cf_str);
strcpy(VIPADDRESS,inet_ntoa(sin->sin_addr));
}
AppendItem(&IPADDRESSES,inet_ntoa(sin->sin_addr),"");
for (sp = ip+strlen(ip)-1; (sp > ip); sp--)
{
if (*sp == '.')
{
*sp = '\0';
NewClass(ip);
}
}
strcpy(ip,inet_ntoa(sin->sin_addr));
if (ag != cf_know)
{
snprintf(name,CF_MAXVARSIZE-1,"ipv4[%s]",CanonifyName(ifp->ifr_name));
}
else
{
snprintf(name,CF_MAXVARSIZE-1,"ipv4[interface_name]");
}
NewScalar("sys",name,ip,cf_str);
i = 3;
for (sp = ip+strlen(ip)-1; (sp > ip); sp--)
{
if (*sp == '.')
{
*sp = '\0';
if (ag != cf_know)
{
snprintf(name,CF_MAXVARSIZE-1,"ipv4_%d[%s]",i--,CanonifyName(ifp->ifr_name));
}
else
{
snprintf(name,CF_MAXVARSIZE-1,"ipv4_%d[interface_name]",i--);
}
NewScalar("sys",name,ip,cf_str);
}
}
}
}
}
close(fd);
}
/*******************************************************************/
void Unix_FindV6InterfaceInfo(void)
{ FILE *pp = NULL;
char buffer[CF_BUFSIZE];
/* Whatever the manuals might say, you cannot get IPV6
interface configuration from the ioctls. This seems
to be implemented in a non standard way across OSes
BSDi has done getifaddrs(), solaris 8 has a new ioctl, Stevens
book shows the suggestion which has not been implemented...
*/
CfOut(cf_verbose,"","Trying to locate my IPv6 address\n");
switch (VSYSTEMHARDCLASS)
{
case cfnt:
/* NT cannot do this */
return;
case irix:
case irix4:
case irix64:
if ((pp = cf_popen("/usr/etc/ifconfig -a","r")) == NULL)
{
CfOut(cf_verbose,"","Could not find interface info\n");
return;
}
break;
case hp:
if ((pp = cf_popen("/usr/sbin/ifconfig -a","r")) == NULL)
{
CfOut(cf_verbose,"","Could not find interface info\n");
return;
}
break;
case aix:
if ((pp = cf_popen("/etc/ifconfig -a","r")) == NULL)
{
CfOut(cf_verbose,"","Could not find interface info\n");
return;
}
break;
default:
if ((pp = cf_popen("/sbin/ifconfig -a","r")) == NULL)
{
CfOut(cf_verbose,"","Could not find interface info\n");
return;
}
}
/* Don't know the output format of ifconfig on all these .. hope for the best*/
while (!feof(pp))
{
fgets(buffer,CF_BUFSIZE-1,pp);
if (ferror(pp)) /* abortable */
{
break;
}
if (StrStr(buffer,"inet6"))
{
struct Item *ip,*list = NULL;
char *sp;
list = SplitStringAsItemList(buffer,' ');
for (ip = list; ip != NULL; ip=ip->next)
{
for (sp = ip->name; *sp != '\0'; sp++)
{
if (*sp == '/') /* Remove CIDR mask */
{
*sp = '\0';
}
}
if (IsIPV6Address(ip->name) && (strcmp(ip->name,"::1") != 0))
{
CfOut(cf_verbose,"","Found IPv6 address %s\n",ip->name);
AppendItem(&IPADDRESSES,ip->name,"");
NewClass(ip->name);
}
}
DeleteItemList(list);
}
}
cf_pclose(pp);
}
#endif /* NOT MINGW */
cfengine-3.2.4/src/cfknow.c 0000644 0001750 0001750 00000070627 11715232734 012462 0000000 0000000 /*
Copyright (C) Cfengine AS
This file is part of Cfengine 3 - written and maintained by Cfengine 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 Commerical Open Source License
(COSL) may apply to this file if you as a licensee so wish it. See
included file COSL.txt.
*/
/*****************************************************************************/
/* */
/* File: cfknow.c */
/* */
/*****************************************************************************/
#include "cf3.defs.h"
#include "cf3.extern.h"
int main (int argc,char *argv[]);
void CheckOpts(int argc,char **argv);
void ThisAgentInit(void);
void KeepKnowControlPromises(void);
void KeepKnowledgePromise(struct Promise *pp);
void VerifyTopicPromise(struct Promise *pp);
void VerifyThingsPromise(struct Promise *pp);
void VerifyOccurrencePromises(struct Promise *pp);
void VerifyInferencePromise(struct Promise *pp);
void WriteKMDB(void);
void GenerateManual(void);
void CfGenerateStories(char *query,enum storytype type);
void VerifyOccurrenceGroup(char *file,struct Promise *pp);
void CfGenerateTestData(int count);
void CfRemoveTestData(void);
void CfUpdateTestData(void);
void ShowSingletons(void);
void ShowWords(void);
/*******************************************************************/
/* GLOBAL VARIABLES */
/*******************************************************************/
extern struct BodySyntax CFK_CONTROLBODY[];
enum typesequence
{
kp_classes,
kp_things,
kp_topics,
kp_occur,
kp_reports,
kp_none
};
char *TYPESEQUENCE[] =
{
"classes",
"things",
"topics",
"occurrences",
"reports",
NULL
};
char BUILD_DIR[CF_BUFSIZE];
char TOPIC_CMD[CF_MAXVARSIZE];
int WORDS = false;
int HTML = false;
int WRITE_KMDB = false;
int GENERATE_MANUAL = false;
char MANDIR[CF_BUFSIZE];
struct Occurrence *OCCURRENCES = NULL;
struct Inference *INFERENCES = NULL;
/*******************************************************************/
/* Command line options */
/*******************************************************************/
const char *ID = "The knowledge management agent is capable of building\n"
"and analysing a semantic knowledge network. It can\n"
"configure a relational database to contain an ISO\n"
"standard topic map and permit regular-expression based\n"
"searching of the map. Analysis of the semantic network\n"
"can be performed providing graphical output of the data,\n"
"and cf-know can assemble and converge the reference manual\n"
"for the current version of the Cfengine software.";
const struct option OPTIONS[15] =
{
{ "help",no_argument,0,'h' },
{ "build",no_argument,0,'b'},
{ "debug",optional_argument,0,'d' },
{ "verbose",no_argument,0,'v' },
{ "version",no_argument,0,'V' },
{ "file",required_argument,0,'f' },
{ "manual",no_argument,0,'m'},
{ "manpage",no_argument,0,'M'},
{ "stories",required_argument,0,'z'},
{ "syntax",required_argument,0,'S'},
{ "topics",no_argument,0,'T'},
{ "test",required_argument,0,'t'},
{ "removetest",no_argument,0,'r'},
{ "updatetest",no_argument,0,'u'},
{ NULL,0,0,'\0' }
};
const char *HINTS[15] =
{
"Print the help message",
"Build and store topic map in the CFDB",
"Set debugging level 0,1,2,3",
"Output verbose information about the behaviour of the agent",
"Output the version of the software",
"Specify an alternative input file than the default",
"Generate reference manual from internal data",
"Generate reference manpage from internal data",
"Look up stories for a given topic on the command line",
"Print a syntax summary of the optional keyword or this cfengine version",
"Show all topic names in CFEngine",
"Generate test data",
"Remove test data",
"Update test data",
NULL
};
/*****************************************************************************/
int main(int argc,char *argv[])
{
CheckOpts(argc,argv);
GenericInitialize(argc,argv,"knowledge");
ThisAgentInit();
KeepKnowControlPromises();
if (strlen(TOPIC_CMD) == 0)
{
int complete;
double percent;
KeepPromiseBundles();
WriteKMDB();
GenerateManual();
ShowWords();
ShowSingletons();
complete = (double)CF_TOPICS*(CF_TOPICS-1);
percent = 100.0 * (double)CF_EDGES/(double)complete;
CfOut(cf_inform,""," -> Association density yields %d/%d = %.4lf%%\n",CF_EDGES,complete,percent);
percent = 100.0 * (double)CF_OCCUR/(double)CF_TOPICS;
CfOut(cf_inform,""," -> Hit probability (efficiency) yields %d/%d = %.4lf%%\n",CF_OCCUR,CF_TOPICS,percent);
}
return 0;
}
/*****************************************************************************/
/* Level 1 */
/*****************************************************************************/
void CheckOpts(int argc,char **argv)
{ extern char *optarg;
char arg[CF_BUFSIZE];
int optindex = 0;
int c;
LOOKUP = false;
while ((c=getopt_long(argc,argv,"hbd:vVf:mMz:St:ruT",OPTIONS,&optindex)) != EOF)
{
switch ((char) c)
{
case 'f':
if (optarg && strlen(optarg) < 5)
{
snprintf(arg,CF_MAXVARSIZE," -f used but argument \"%s\" incorrect",optarg);
FatalError(arg);
}
strncpy(VINPUTFILE,optarg,CF_BUFSIZE-1);
VINPUTFILE[CF_BUFSIZE-1] = '\0';
MINUSF = true;
break;
case 'd':
switch ((optarg==NULL) ? '3' : *optarg)
{
case '1':
D1 = true;
DEBUG = true;
break;
case '2':
D2 = true;
DEBUG = true;
break;
default:
DEBUG = true;
break;
}
break;
case 'z':
#ifdef HAVE_CONSTELLATION
strcpy(TOPIC_CMD,optarg);
CfGenerateStories(TOPIC_CMD,cfi_cause);
#endif
exit(0);
break;
case 'b':
WRITE_KMDB = true;
break;
case 'v':
VERBOSE = true;
break;
case 'V':
PrintVersionBanner("cf-know");
exit(0);
case 'h':
Syntax("cf-know - cfengine's knowledge agent",OPTIONS,HINTS,ID);
exit(0);
case 'M':
ManPage("cf-know - cfengine's knowledge agent",OPTIONS,HINTS,ID);
exit(0);
case 'H':
HTML = 1;
break;
case 'S':
if (optarg)
{
SyntaxCompletion(optarg);
exit(0);
}
break;
case 'm':
GENERATE_MANUAL = true;
break;
case 't':
if (atoi(optarg))
{
CfGenerateTestData(atoi(optarg));
exit(0);
}
break;
case 'r':
CfRemoveTestData();
exit(0);
case 'u':
CfUpdateTestData();
exit(0);
case 'T':
WORDS = true;
break;
default: Syntax("cf-know - knowledge agent",OPTIONS,HINTS,ID);
exit(1);
}
}
if (argv[optind] != NULL)
{
CfOut(cf_error,"","Unexpected argument with no preceding option: %s\n",argv[optind]);
}
}
/*****************************************************************************/
void ThisAgentInit()
{
strcpy(WEBDRIVER,"");
strcpy(LICENSE_COMPANY,"");
strcpy(MANDIR,".");
strcpy(SQL_DATABASE,"cf_kmdb");
strcpy(GRAPHDIR,"");
SHOWREPORTS = false;
if (InsertTopic("any","any"))
{
struct Rlist *list = NULL;
PrependRScalar(&list,"Description",CF_SCALAR);
AddOccurrence(&OCCURRENCES,"The generic knowledge context - any time, any place, anywhere",list,cfk_literal,"any");
DeleteRlist(list);
}
}
/*****************************************************************************/
void KeepKnowControlPromises()
{ struct Constraint *cp;
struct Rlist *rp;
char rettype;
void *retval;
for (cp = ControlBodyConstraints(cf_know); cp != NULL; cp=cp->next)
{
if (IsExcluded(cp->classes))
{
continue;
}
if (GetVariable("control_knowledge",cp->lval,&retval,&rettype) == cf_notype)
{
CfOut(cf_error,""," !! Unknown lval %s in knowledge control body",cp->lval);
continue;
}
if (strcmp(cp->lval,CFK_CONTROLBODY[cfk_tm_prefix].lval) == 0)
{
CfOut(cf_error,"","The topic map prefix has been deprecated");
continue;
}
if (strcmp(cp->lval,CFK_CONTROLBODY[cfk_builddir].lval) == 0)
{
strncpy(BUILD_DIR,retval,CF_BUFSIZE);
if (strlen(MANDIR) < 2) /* MANDIR defaults to BUILDDIR */
{
strncpy(MANDIR,retval,CF_BUFSIZE);
}
continue;
}
if (strcmp(cp->lval,CFK_CONTROLBODY[cfk_sql_type].lval) == 0)
{
SQL_TYPE = Str2dbType(retval);
CfOut(cf_verbose,""," -> Option %s has been deprecated in this release",cp->lval);
continue;
}
if (strcmp(cp->lval,CFK_CONTROLBODY[cfk_sql_database].lval) == 0)
{
strncpy(SQL_DATABASE,retval,CF_MAXVARSIZE);
CfOut(cf_verbose,""," -> Option %s has been deprecated in this release",cp->lval);
continue;
}
if (strcmp(cp->lval,CFK_CONTROLBODY[cfk_sql_owner].lval) == 0)
{
strncpy(SQL_OWNER,retval,CF_MAXVARSIZE);
CfOut(cf_verbose,""," -> Option %s has been deprecated in this release",cp->lval);
continue;
}
if (strcmp(cp->lval,CFK_CONTROLBODY[cfk_sql_passwd].lval) == 0)
{
strncpy(SQL_PASSWD,retval,CF_MAXVARSIZE);
CfOut(cf_verbose,""," -> Option %s has been deprecated in this release",cp->lval);
continue;
}
if (strcmp(cp->lval,CFK_CONTROLBODY[cfk_sql_server].lval) == 0)
{
strncpy(SQL_SERVER,retval,CF_MAXVARSIZE);
CfOut(cf_verbose,""," -> Option %s has been deprecated in this release",cp->lval);
continue;
}
if (strcmp(cp->lval,CFK_CONTROLBODY[cfk_sql_connect_db].lval) == 0)
{
strncpy(SQL_CONNECT_NAME,retval,CF_MAXVARSIZE);
CfOut(cf_verbose,""," -> Option %s has been deprecated in this release",cp->lval);
continue;
}
if (strcmp(cp->lval,CFK_CONTROLBODY[cfk_query_engine].lval) == 0)
{
CfOut(cf_verbose,""," -> Option %s has been deprecated in this release",cp->lval);
continue;
}
if (strcmp(cp->lval,CFK_CONTROLBODY[cfk_htmlbanner].lval) == 0)
{
CfOut(cf_verbose,""," -> Option %s has been deprecated in this release",cp->lval);
continue;
}
if (strcmp(cp->lval,CFK_CONTROLBODY[cfk_htmlfooter].lval) == 0)
{
CfOut(cf_verbose,""," -> Option %s has been deprecated in this release",cp->lval);
continue;
}
if (strcmp(cp->lval,CFK_CONTROLBODY[cfk_stylesheet].lval) == 0)
{
CfOut(cf_verbose,""," -> Option %s has been deprecated in this release",cp->lval);
continue;
}
if (strcmp(cp->lval,CFK_CONTROLBODY[cfk_query_output].lval) == 0)
{
CfOut(cf_verbose,""," -> Option %s has been deprecated in this release",cp->lval);
continue;
}
if (strcmp(cp->lval,CFK_CONTROLBODY[cfk_graph_output].lval) == 0)
{
CfOut(cf_verbose,""," -> Option %s has been deprecated in this release",cp->lval);
continue;
}
if (strcmp(cp->lval,CFK_CONTROLBODY[cfk_views].lval) == 0)
{
CfOut(cf_verbose,""," -> Option %s has been deprecated in this release",cp->lval);
continue;
}
if (strcmp(cp->lval,CFK_CONTROLBODY[cfk_graph_dir].lval) == 0)
{
strncpy(GRAPHDIR,retval,CF_MAXVARSIZE);
CfOut(cf_verbose,"","SET graph_directory = %s\n",GRAPHDIR);
continue;
}
if (strcmp(cp->lval,CFK_CONTROLBODY[cfk_genman].lval) == 0)
{
GENERATE_MANUAL = GetBoolean(retval);
CfOut(cf_verbose,"","SET generate_manual = %d\n",GENERATE_MANUAL);
continue;
}
if (strcmp(cp->lval,CFK_CONTROLBODY[cfk_mandir].lval) == 0)
{
strncpy(MANDIR,retval,CF_MAXVARSIZE);
CfOut(cf_verbose,"","SET manual_source_directory = %s\n",MANDIR);
continue;
}
if (strcmp(cp->lval,CFK_CONTROLBODY[cfk_docroot].lval) == 0)
{
CfOut(cf_verbose,""," -> Option %s has been deprecated in this release",cp->lval);
continue;
}
}
}
/*****************************************************************************/
void KeepPromiseBundles()
{ struct Bundle *bp;
struct SubType *sp;
struct Promise *pp;
struct Rlist *rp,*params;
struct FnCall *fp;
char rettype,*name;
void *retval;
int ok = true;
enum typesequence type;
if (GetVariable("control_common","bundlesequence",&retval,&rettype) == cf_notype)
{
CfOut(cf_error,""," !! No bundlesequence in the common control body");
exit(1);
}
for (rp = (struct Rlist *)retval; rp != NULL; rp=rp->next)
{
switch (rp->type)
{
case CF_SCALAR:
name = (char *)rp->item;
params = NULL;
break;
case CF_FNCALL:
fp = (struct FnCall *)rp->item;
name = (char *)fp->name;
params = (struct Rlist *)fp->args;
break;
default:
name = NULL;
params = NULL;
CfOut(cf_error,""," !! Illegal item found in bundlesequence: ");
ShowRval(stdout,rp->item,rp->type);
printf(" = %c\n",rp->type);
ok = false;
break;
}
if (!(GetBundle(name,"knowledge")||(GetBundle(name,"common"))))
{
CfOut(cf_error,""," !! Bundle \"%s\" listed in the bundlesequence was not found\n",name);
ok = false;
}
}
if (!ok)
{
FatalError("Errors in knowledge bundles");
}
/* If all is okay, go ahead and evaluate */
for (type = 0; TYPESEQUENCE[type] != NULL; type++)
{
for (rp = (struct Rlist *)retval; rp != NULL; rp=rp->next)
{
switch (rp->type)
{
case CF_FNCALL:
fp = (struct FnCall *)rp->item;
name = (char *)fp->name;
params = (struct Rlist *)fp->args;
break;
default:
name = (char *)rp->item;
params = NULL;
break;
}
if ((bp = GetBundle(name,"knowledge")) || (bp = GetBundle(name,"common")))
{
BannerBundle(bp,params);
AugmentScope(bp->name,bp->args,params);
DeletePrivateClassContext(); // Each time we change bundle
}
if ((sp = GetSubTypeForBundle(TYPESEQUENCE[type],bp)) == NULL)
{
continue;
}
BannerSubType(bp->name,sp->name,1);
for (pp = sp->promiselist; pp != NULL; pp=pp->next)
{
ExpandPromise(cf_know,bp->name,pp,KeepKnowledgePromise);
}
}
}
}
/*********************************************************************/
/* Level */
/*********************************************************************/
void KeepKnowledgePromise(struct Promise *pp)
{
if (pp->done)
{
return;
}
if (strcmp("classes",pp->agentsubtype) == 0)
{
CfOut(cf_verbose,""," ! Class promises do not have any effect here.\n");
return;
}
if (strcmp("inferences",pp->agentsubtype) == 0)
{
VerifyInferencePromise(pp);
return;
}
if (strcmp("things",pp->agentsubtype) == 0)
{
VerifyThingsPromise(pp);
return;
}
if (strcmp("topics",pp->agentsubtype) == 0)
{
VerifyTopicPromise(pp);
return;
}
if (strcmp("occurrences",pp->agentsubtype) == 0)
{
VerifyOccurrencePromises(pp);
return;
}
if (strcmp("reports",pp->agentsubtype) == 0)
{
VerifyReportPromise(pp);
return;
}
}
/*********************************************************************/
void CfGenerateStories(char *query,enum storytype type)
{
#ifdef HAVE_CONSTELLATION
Constellation_CfGenerateStories(query,type);
#endif
}
/*********************************************************************/
void CfGenerateTestData(int count)
{
#ifdef HAVE_NOVA
Nova_GenerateTestData(count);
#endif
}
/*********************************************************************/
void CfUpdateTestData(void)
{
#ifdef HAVE_NOVA
Nova_UpdateTestData();
#endif
}
/*********************************************************************/
void CfRemoveTestData(void)
{
#ifdef HAVE_NOVA
Nova_RemoveTestData();
#endif
}
/*********************************************************************/
void ShowWords()
{ struct Topic *tp;
struct Item *ip,*list = NULL;
int slot;
if (!WORDS)
{
return;
}
for (slot = 0; slot < CF_HASHTABLESIZE; slot++)
{
for (tp = TOPICHASH[slot]; tp != NULL; tp=tp->next)
{
IdempPrependItem(&list,tp->topic_name,tp->topic_context);
}
}
list = SortItemListNames(list);
for (ip = list; ip != NULL; ip=ip->next)
{
printf("%s::%s\n",ip->classes,ip->name);
}
}
/*********************************************************************/
void ShowSingletons()
{ struct Topic *tp;
struct Item *ip,*list = NULL;
int slot;
if (VERBOSE || DEBUG)
{
for (slot = 0; slot < CF_HASHTABLESIZE; slot++)
{
for (tp = TOPICHASH[slot]; tp != NULL; tp=tp->next)
{
if (tp->associations == NULL)
{
PrependItem(&list,tp->topic_name,tp->topic_context);
}
}
}
list = SortItemListNames(list);
for (ip = list; ip != NULL; ip=ip->next)
{
printf(" ! Warning, topic \"%s::%s\" is a singleton with no connection to the map\n",ip->classes,ip->name);
}
}
}
/*********************************************************************/
/* Level */
/*********************************************************************/
void VerifyInferencePromise(struct Promise *pp)
{ struct Attributes a = {0};
struct Rlist *rpp,*rpq;
if (!IsDefinedClass(pp->classes))
{
CfOut(cf_verbose,""," -> Skipping inference for \"%s\" as class \"%s\" is not defined",pp->promiser,pp->classes);
return;
}
a = GetInferencesAttributes(pp);
for (rpp = a.precedents; rpp != NULL; rpp=rpp->next)
{
for (rpq = a.qualifiers; rpq != NULL; rpq=rpq->next)
{
CfOut(cf_verbose,""," -> Add inference: (%s,%s,%s)\n",rpp->item,rpq->item,pp->promiser);
AddInference(&INFERENCES,pp->promiser,rpp->item,rpq->item);
}
}
}
/*********************************************************************/
void VerifyThingsPromise(struct Promise *pp)
{ char id[CF_BUFSIZE];
struct Attributes a = {0};
struct Topic *tp = NULL, *otp;
struct Rlist *rp,*rps,*contexts;
char *handle = (char *)GetConstraint("handle",pp,CF_SCALAR);
a = GetThingsAttributes(pp);
CfOut(cf_verbose,""," -> Attempting to install thing-topic %s::%s \n",pp->classes,pp->promiser);
// Add a standard reserved word
contexts = SplitContextExpression(pp->classes,pp);
for (rp = contexts; rp != NULL; rp = rp->next)
{
if ((tp = InsertTopic(pp->promiser,rp->item)) == NULL)
{
return;
}
CfOut(cf_verbose,""," -> New thing \"%s\" about context \"%s\"",pp->promiser,rp->item);
if (a.fwd_name && a.bwd_name)
{
CfOut(cf_verbose,""," -> New thing \"%s\" has a relation \"%s/%s\"",pp->promiser,a.fwd_name,a.bwd_name);
AddTopicAssociation(tp,&(tp->associations),a.fwd_name,a.bwd_name,a.associates,true,rp->item,pp->promiser);
}
// Handle all synonyms as associations
if (handle)
{
char synonym[CF_BUFSIZE];
snprintf(synonym,CF_BUFSIZE-1,"handles::%s",handle);
otp = IdempInsertTopic(synonym);
PrependRScalar(&(a.synonyms),otp->topic_name,CF_SCALAR);
}
// Handle all synonyms as associations
if (a.synonyms)
{
for (rps = a.synonyms; rps != NULL; rps=rps->next)
{
otp = IdempInsertTopic(rps->item);
CfOut(cf_verbose,""," ---> %s is a synonym for %s",rps->item,tp->topic_name);
}
AddTopicAssociation(tp,&(tp->associations),KM_SYNONYM,KM_SYNONYM,a.synonyms,true,rp->item,pp->promiser);
}
// Handle all generalizations as associations
if (a.general)
{
for (rps = a.general; rps != NULL; rps=rps->next)
{
otp = IdempInsertTopic(rps->item);
CfOut(cf_verbose,""," ---> %s is a generalization for %s",rps->item,tp->topic_name);
}
AddTopicAssociation(tp,&(tp->associations),KM_GENERALIZES_B,KM_GENERALIZES_F,a.general,true,rp->item,pp->promiser);
}
// Treat comments as occurrences of information.
if (pp->ref)
{
struct Rlist *list = NULL;
snprintf(id,CF_MAXVARSIZE,"%s.%s",pp->classes,CanonifyName(pp->promiser));
PrependRScalar(&list,"description",CF_SCALAR);
AddOccurrence(&OCCURRENCES,pp->ref,list,cfk_literal,id);
DeleteRlist(list);
}
if (handle)
{
struct Rlist *list = NULL;
PrependRScalar(&list,handle,CF_SCALAR);
AddTopicAssociation(tp,&(tp->associations),"is the promise of","stands for",list,true,rp->item,pp->promiser);
DeleteRlist(list);
list = NULL;
snprintf(id,CF_MAXVARSIZE,"%s.%s",pp->classes,handle);
PrependRScalar(&list,"description",CF_SCALAR);
AddOccurrence(&OCCURRENCES,pp->ref,list,cfk_literal,id);
DeleteRlist(list);
}
}
DeleteRlist(contexts);
}
/*********************************************************************/
void VerifyTopicPromise(struct Promise *pp)
{ char id[CF_BUFSIZE];
struct Attributes a = {0};
struct Topic *tp = NULL, *otp;
struct Rlist *rp,*rps,*contexts;
char *handle = (char *)GetConstraint("handle",pp,CF_SCALAR);
a = GetTopicsAttributes(pp);
CfOut(cf_verbose,""," -> Attempting to install topic %s::%s \n",pp->classes,pp->promiser);
// Add a standard reserved word
contexts = SplitContextExpression(pp->classes,pp);
for (rp = contexts; rp != NULL; rp = rp->next)
{
if ((tp = InsertTopic(pp->promiser,rp->item)) == NULL)
{
return;
}
CfOut(cf_verbose,""," -> New topic promise for \"%s\" about context \"%s\"",pp->promiser,rp->item);
if (a.fwd_name && a.bwd_name)
{
AddTopicAssociation(tp,&(tp->associations),a.fwd_name,a.bwd_name,a.associates,true,rp->item,pp->promiser);
}
// Handle all synonyms as associations
if (a.synonyms)
{
for (rps = a.synonyms; rps != NULL; rps=rps->next)
{
otp = IdempInsertTopic(rps->item);
CfOut(cf_verbose,""," ---> %s is a synonym for %s",rps->item,tp->topic_name);
}
AddTopicAssociation(tp,&(tp->associations),KM_SYNONYM,KM_SYNONYM,a.synonyms,true,rp->item,pp->promiser);
}
// Handle all generalizations as associations
if (a.general)
{
for (rps = a.general; rps != NULL; rps=rps->next)
{
otp = IdempInsertTopic(rps->item);
CfOut(cf_verbose,""," ---> %s is a generalization for %s",rps->item,tp->topic_name);
}
AddTopicAssociation(tp,&(tp->associations),KM_GENERALIZES_B,KM_GENERALIZES_F,a.general,true,rp->item,pp->promiser);
}
if (handle)
{
char synonym[CF_BUFSIZE];
snprintf(synonym,CF_BUFSIZE-1,"handles::%s",handle);
otp = IdempInsertTopic(synonym);
PrependRScalar(&(a.synonyms),otp->topic_name,CF_SCALAR);
}
// Treat comments as occurrences of information.
if (pp->ref)
{
struct Rlist *list = NULL;
snprintf(id,CF_MAXVARSIZE,"%s.%s",pp->classes,CanonifyName(pp->promiser));
PrependRScalar(&list,"description",CF_SCALAR);
AddOccurrence(&OCCURRENCES,pp->ref,list,cfk_literal,id);
DeleteRlist(list);
}
if (handle)
{
struct Rlist *list = NULL;
PrependRScalar(&list,handle,CF_SCALAR);
AddTopicAssociation(tp,&(tp->associations),"is the promise of","stands for",list,true,rp->item,pp->promiser);
DeleteRlist(list);
list = NULL;
snprintf(id,CF_MAXVARSIZE,"%s.%s",pp->classes,handle);
PrependRScalar(&list,"description",CF_SCALAR);
AddOccurrence(&OCCURRENCES,pp->ref,list,cfk_literal,id);
DeleteRlist(list);
}
}
DeleteRlist(contexts);
}
/*********************************************************************/
void VerifyOccurrencePromises(struct Promise *pp)
{ struct Attributes a = {0};
char name[CF_BUFSIZE];
enum representations rep_type;
struct Rlist *contexts,*rp;
a = GetOccurrenceAttributes(pp);
if (a.rep_type)
{
rep_type = String2Representation(a.rep_type);
}
else
{
rep_type = cfk_url;
}
if (a.represents == NULL)
{
if (rep_type == cfk_literal)
{
CfOut(cf_error,""," ! Occurrence of text information \"%s\" does not promise any topics to represent",pp->promiser);
}
else
{
CfOut(cf_error,""," ! Occurrence or reference to information \"%s\" does not promise any topics to represent",pp->promiser);
}
return;
}
contexts = SplitContextExpression(pp->classes,pp);
for (rp = contexts; rp != NULL; rp = rp->next)
{
CfOut(cf_verbose,""," -> New occurrence promise for \"%s\" about context \"%s\"",pp->promiser,rp->item);
switch (rep_type)
{
case cfk_file:
if (a.web_root == NULL || a.path_root == NULL)
{
CfOut(cf_error,""," !! File pattern but no complete url mapping path_root -> web_root");
return;
}
strncpy(name,a.path_root,CF_BUFSIZE-1);
if (!JoinPath(name,pp->promiser))
{
CfOut(cf_error,""," !! Unable to form pathname in search for local files");
return;
}
// FIXME - this should pass rp->item instead of pp->classes if we want to keep this
LocateFilePromiserGroup(name,pp,VerifyOccurrenceGroup);
break;
default:
AddOccurrence(&OCCURRENCES,pp->promiser,a.represents,rep_type,rp->item);
break;
}
}
DeleteRlist(contexts);
}
/*********************************************************************/
void WriteKMDB()
{
#ifdef HAVE_NOVA
if (WRITE_KMDB)
{
Nova_StoreKMDB(TOPICHASH,OCCURRENCES,INFERENCES);
}
#endif
}
/*********************************************************************/
void GenerateManual()
{
if (GENERATE_MANUAL)
{
TexinfoManual(MANDIR);
}
}
/*********************************************************************/
void VerifyOccurrenceGroup(char *file,struct Promise *pp)
{ struct Attributes a = {0};
enum representations rep_type;
struct stat sb;
char *sp,url[CF_BUFSIZE];
struct Rval retval;
a = GetOccurrenceAttributes(pp);
if (a.rep_type)
{
rep_type = String2Representation(a.rep_type);
}
else
{
rep_type = cfk_url;
}
if (cfstat(file,&sb) == -1)
{
CfOut(cf_verbose,""," !! File %s matched but could not be read",file);
return;
}
if (a.path_root == NULL || a.web_root == NULL)
{
CfOut(cf_error,""," !! No pathroot/webroot defined in representation");
PromiseRef(cf_error,pp);
return;
}
Chop(a.path_root);
DeleteSlash(a.path_root);
sp = file + strlen(a.path_root) + 1;
FullTextMatch(pp->promiser,sp);
retval = ExpandPrivateRval("this",a.represents,CF_LIST);
DeleteScope("match");
if (strlen(a.web_root) > 0)
{
snprintf(url,CF_BUFSIZE-1,"%s/%s",a.web_root,sp);
}
else
{
snprintf(url,CF_BUFSIZE-1,"%s",sp);
}
AddOccurrence(&OCCURRENCES,url,retval.item,cfk_url,pp->classes);
CfOut(cf_verbose,""," -> File %s matched and being logged at %s",file,url);
DeleteRlist((struct Rlist *)retval.item);
}
cfengine-3.2.4/src/verify_measurements.c 0000644 0001750 0001750 00000007673 11715232734 015270 0000000 0000000 /*
Copyright (C) Cfengine AS
This file is part of Cfengine 3 - written and maintained by Cfengine 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 Commerical Open Source License
(COSL) may apply to this file if you as a licensee so wish it. See
included file COSL.txt.
*/
/*****************************************************************************/
/* */
/* File: verify_measurements.c */
/* */
/*****************************************************************************/
#include "cf3.defs.h"
#include "cf3.extern.h"
static int CheckMeasureSanity(struct Attributes a,struct Promise *pp);
/*****************************************************************************/
void VerifyMeasurementPromise(double *this,struct Promise *pp)
{ struct Attributes a = {{0}};
if (pp->done)
{
if (pp->ref)
{
CfOut(cf_verbose,"","Skipping static observation %s (%s), already done",pp->promiser,pp->ref);
}
else
{
CfOut(cf_verbose,"","Skipping static observation %s, already done",pp->promiser);
}
return;
}
PromiseBanner(pp);
a = GetMeasurementAttributes(pp);
/*
if (strcmp(a.measure.history_type,"weekly") == 0)
{
*(pp->donep) = true;
}
*/
if (!CheckMeasureSanity(a,pp))
{
return;
}
VerifyMeasurement(this,a,pp);
}
/*****************************************************************************/
static int CheckMeasureSanity(struct Attributes a,struct Promise *pp)
{ int retval = true;
if (!IsAbsPath(pp->promiser))
{
cfPS(cf_error,CF_INTERPT,"",pp,a,"The promiser \"%s\" of a measurement was not an absolute path",pp->promiser);
PromiseRef(cf_error,pp);
retval = false;
}
if (a.measure.data_type == cf_notype)
{
cfPS(cf_error,CF_INTERPT,"",pp,a,"The promiser \"%s\" did not specify a data type\n",pp->promiser);
PromiseRef(cf_error,pp);
retval = false;
}
else
{
if (a.measure.history_type && strcmp(a.measure.history_type,"weekly") == 0)
{
switch (a.measure.data_type)
{
case cf_counter:
case cf_str:
case cf_int:
case cf_real:
break;
default:
cfPS(cf_error,CF_INTERPT,"",pp,a,"The promiser \"%s\" cannot have history type weekly as it is not a number\n",pp->promiser);
PromiseRef(cf_error,pp);
retval = false;
break;
}
}
}
if (a.measure.select_line_matching && a.measure.select_line_number != CF_NOINT)
{
cfPS(cf_error,CF_INTERPT,"",pp,a,"The promiser \"%s\" cannot select both a line by pattern and by number\n",pp->promiser);
PromiseRef(cf_error,pp);
retval = false;
}
if (!a.measure.extraction_regex)
{
CfOut(cf_verbose,"","No extraction regex, so assuming whole line is the value");
}
else
{
if (!strchr(a.measure.extraction_regex,'(') && !strchr(a.measure.extraction_regex,')'))
{
cfPS(cf_error,CF_INTERPT,"",pp,a,"The extraction_regex must contain a single backreference for the extraction\n");
retval = false;
}
}
return retval;
}
cfengine-3.2.4/src/conversion.c 0000644 0001750 0001750 00000076033 11715232734 013355 0000000 0000000 /*
Copyright (C) Cfengine AS
This file is part of Cfengine 3 - written and maintained by Cfengine 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 Commerical Open Source License
(COSL) may apply to this file if you as a licensee so wish it. See
included file COSL.txt.
*/
/*****************************************************************************/
/* */
/* File: conversion.c */
/* */
/*****************************************************************************/
#include "cf3.defs.h"
#include "cf3.extern.h"
static int IsSpace(char *remainder);
/*****************************************************************************/
void IPString2KeyDigest(char *ipv4,char *result)
{ CF_DB *dbp;
CF_DBC *dbcp;
char *key;
char name[CF_BUFSIZE];
void *value;
struct CfKeyHostSeen entry;
int ksize,vsize;
unsigned char digest[EVP_MAX_MD_SIZE+1];
result[0] = '\0';
if (strcmp(ipv4,"127.0.0.1") == 0 || strcmp(ipv4,"::1") == 0 || strcmp(ipv4,VIPADDRESS) == 0)
{
if (PUBKEY)
{
HashPubKey(PUBKEY,digest,CF_DEFAULT_DIGEST);
snprintf(result,CF_MAXVARSIZE,"%s",HashPrint(CF_DEFAULT_DIGEST,digest));
}
return;
}
snprintf(name,CF_BUFSIZE-1,"%s/%s",CFWORKDIR,CF_LASTDB_FILE);
MapName(name);
if (!OpenDB(name,&dbp))
{
return;
}
if (!NewDBCursor(dbp,&dbcp))
{
CfOut(cf_inform,""," !! Unable to scan last-seen database");
CloseDB(dbp);
return;
}
/* Initialize the key/data return pair. */
memset(&entry, 0, sizeof(entry));
/* Walk through the database and print out the key/data pairs. */
while(NextDB(dbp,dbcp,&key,&ksize,&value,&vsize))
{
if (value != NULL)
{
memcpy(&entry,value,sizeof(entry));
// Warning this is not 1:1
if (strcmp(ipv4,MapAddress((char *)entry.address)) == 0)
{
CfOut(cf_verbose,""," -> Matched IP %s to key %s",ipv4,key+1);
strncpy(result,key+1,CF_MAXVARSIZE-1);
break;
}
}
}
DeleteDBCursor(dbp,dbcp);
CloseDB(dbp);
if(EMPTY(result))
{
CfOut(cf_verbose, "", "!! Unable to find a key for ip %s", ipv4);
}
}
/***************************************************************/
char *MapAddress(char *unspec_address)
{ /* Is the address a mapped ipv4 over ipv6 address */
if (strncmp(unspec_address,"::ffff:",7) == 0)
{
return (char *)(unspec_address+7);
}
else
{
return unspec_address;
}
}
/***************************************************************************/
char *EscapeQuotes(char *s, char *out, int outSz)
{ char *spt,*spf;
int i = 0;
memset(out,0,outSz);
for (spf = s, spt = out; (i < outSz - 2) && (*spf != '\0'); spf++,spt++,i++)
{
switch (*spf)
{
case '\'':
case '\"':
*spt++ = '\\';
*spt = *spf;
i+=3;
break;
default:
*spt = *spf;
i++;
break;
}
}
return out;
}
/***************************************************************************/
char *EscapeJson(char *s, char *out, int outSz)
{ char *spt,*spf;
int i = 0;
memset(out,0,outSz);
for (spf = s, spt = out; (i < outSz - 2) && (*spf != '\0'); spf++,spt++,i++)
{
switch (*spf)
{
case '\"':
case '\\':
case '/':
*spt++ = '\\';
*spt = *spf;
i+=2;
break;
case '\n':
*spt++ = '\\';
*spt = 'n';
i+=2;
break;
case '\t':
*spt++ = '\\';
*spt = 't';
i+=2;
break;
case '\r':
*spt++ = '\\';
*spt = 'r';
i+=2;
break;
case '\b':
*spt++ = '\\';
*spt = 'b';
i+=2;
break;
case '\f':
*spt++ = '\\';
*spt = 'f';
i+=2;
break;
default:
*spt = *spf;
i++;
break;
}
}
return out;
}
/***************************************************************************/
char *EscapeRegex(char *s, char *out, int outSz)
{ char *spt,*spf;
int i = 0;
memset(out,0,outSz);
for (spf = s, spt = out; (i < outSz - 2) && (*spf != '\0'); spf++,spt++,i++)
{
switch (*spf)
{
case '\\':
case '.':
case '|':
case '*':
case '?':
case '+':
case '(':
case ')':
case '{':
case '}':
case '[':
case ']':
case '^':
case '$':
*spt++ = '\\';
*spt = *spf;
i+=2;
break;
default:
*spt = *spf;
i++;
break;
}
}
return out;
}
/***************************************************************************/
enum cfhypervisors Str2Hypervisors(char *s)
{ static char *names[] = { "xen", "kvm", "esx", "test",
"xen_net", "kvm_net", "esx_net", "test_net",
"zone", "ec2", "eucalyptus", NULL };
int i;
if (s == NULL)
{
return cfv_virt_test;
}
for (i = 0; names[i] != NULL; i++)
{
if (s && strcmp(s,names[i]) == 0)
{
return (enum cfhypervisors) i;
}
}
return (enum cfhypervisors) i;
}
/***************************************************************************/
enum cfenvironment_state Str2EnvState(char *s)
{ static char *names[] = { "create", "delete", "running", "suspended", "down", NULL };
int i;
if (s == NULL)
{
return cfvs_create;
}
for (i = 0; names[i] != NULL; i++)
{
if (s && strcmp(s,names[i]) == 0)
{
return (enum cfenvironment_state) i;
}
}
return (enum cfenvironment_state) i;
}
/***************************************************************************/
enum insert_match String2InsertMatch(char *s)
{ static char *names[] = { "ignore_leading","ignore_trailing","ignore_embedded",
"exact_match", NULL };
int i;
for (i = 0; names[i] != NULL; i++)
{
if (s && strcmp(s,names[i]) == 0)
{
return i;
}
}
return cf_exact_match;
}
/***************************************************************************/
int SyslogPriority2Int(char *s)
{ int i;
static char *types[] = { "emergency","alert","critical","error",
"warning","notice","info","debug", NULL };
for (i = 0; types[i] != NULL; i++)
{
if (s && strcmp(s,types[i]) == 0)
{
return i;
}
}
return 3;
}
/***************************************************************************/
enum cfdbtype Str2dbType(char *s)
{ int i;
static char *types[] = { "mysql","postgres", NULL };
for (i = 0; types[i] != NULL; i++)
{
if (s && strcmp(s,types[i]) == 0)
{
return (enum cfdbtype) i;
}
}
return cfd_notype;
}
/***************************************************************************/
enum package_actions Str2PackageAction(char *s)
{ int i;
static char *types[] = { "add","delete","reinstall","update","addupdate","patch","verify", NULL };
for (i = 0; types[i] != NULL; i++)
{
if (s && strcmp(s,types[i]) == 0)
{
return (enum package_actions) i;
}
}
return cfa_pa_none;
}
/***************************************************************************/
enum version_cmp Str2PackageSelect(char *s)
{ int i;
static char *types[] = { "==","!=",">","<",">=","<=", NULL};
for (i = 0; types[i] != NULL; i++)
{
if (s && strcmp(s,types[i]) == 0)
{
return (enum version_cmp) i;
}
}
return cfa_cmp_none;
}
/***************************************************************************/
enum action_policy Str2ActionPolicy(char *s)
{ int i;
static char *types[] = { "individual","bulk",NULL};
for (i = 0; types[i] != NULL; i++)
{
if (s && strcmp(s,types[i]) == 0)
{
return (enum version_cmp) i;
}
}
return cfa_no_ppolicy;
}
/***************************************************************************/
char *Rlist2String(struct Rlist *list,char *sep)
{ char line[CF_BUFSIZE];
struct Rlist *rp;
line[0] = '\0';
for(rp = list; rp != NULL; rp=rp->next)
{
strcat(line,(char *)rp->item);
if (rp->next)
{
strcat(line,sep);
}
}
return strdup(line);
}
/***************************************************************************/
int Signal2Int(char *s)
{ int i = 0;
struct Item *ip, *names = SplitString(CF_SIGNALRANGE,',');
for (ip = names; ip != NULL; ip=ip->next)
{
if (strcmp(s,ip->name) == 0)
{
break;
}
i++;
}
DeleteItemList(names);
switch (i)
{
case cfa_hup:
return SIGHUP;
case cfa_int:
return SIGINT;
case cfa_trap:
return SIGTRAP;
case cfa_kill:
return SIGKILL;
case cfa_pipe:
return SIGPIPE;
case cfa_cont:
return SIGCONT;
case cfa_abrt:
return SIGABRT;
case cfa_stop:
return SIGSTOP;
case cfa_quit:
return SIGQUIT;
case cfa_term:
return SIGTERM;
case cfa_child:
return SIGCHLD;
case cfa_usr1:
return SIGUSR1;
case cfa_usr2:
return SIGUSR2;
case cfa_bus:
return SIGBUS;
case cfa_segv:
return SIGSEGV;
default:
return -1;
}
}
/***************************************************************************/
enum cfreport String2ReportLevel(char *s)
{ int i;
static char *types[] = { "inform","verbose","error","log",NULL };
for (i = 0; types[i] != NULL; i++)
{
if (s && strcmp(s,types[i]) == 0)
{
return (enum cfreport) i;
}
}
return cf_noreport;
}
/***************************************************************************/
enum cfhashes String2HashType(char *typestr)
{ int i;
for (i = 0; CF_DIGEST_TYPES[i][0] != NULL; i++)
{
if (typestr && strcmp(typestr,CF_DIGEST_TYPES[i][0]) == 0)
{
return (enum cfhashes)i;
}
}
return cf_nohash;
}
/****************************************************************************/
enum cflinktype String2LinkType(char *s)
{ int i;
static char *types[] = { "symlink","hardlink","relative","absolute",NULL };
for (i = 0; types[i] != NULL; i++)
{
if (s && strcmp(s,types[i]) == 0)
{
return (enum cflinktype) i;
}
}
return cfa_symlink;
}
/****************************************************************************/
enum cfcomparison String2Comparison(char *s)
{ int i;
static char *types[] = {"atime","mtime","ctime","digest","hash","binary","exists",NULL};
for (i = 0; types[i] != NULL; i++)
{
if (s && strcmp(s,types[i]) == 0)
{
return (enum cfcomparison) i;
}
}
return cfa_nocomparison;
}
/****************************************************************************/
enum representations String2Representation(char *s)
{ int i;
static char *types[] = {"url","web","file","db","literal","image","portal",NULL};
for (i = 0; types[i] != NULL; i++)
{
if (s && strcmp(s,types[i]) == 0)
{
return (enum representations) i;
}
}
return cfk_none;
}
/****************************************************************************/
enum cfsbundle Type2Cfs(char *name)
{ int i;
for (i = 0; i < (int)cfs_nobtype; i++)
{
if (name && strcmp(CF_REMACCESS_SUBTYPES[i].subtype,name)==0)
{
break;
}
}
return (enum cfsbundle)i;
}
/****************************************************************************/
enum cfdatatype Typename2Datatype(char *name)
/* convert abstract data type names: int, ilist etc */
{ int i;
Debug("typename2type(%s)\n",name);
for (i = 0; i < (int)cf_notype; i++)
{
if (name && strcmp(CF_DATATYPES[i],name)==0)
{
break;
}
}
return (enum cfdatatype)i;
}
/****************************************************************************/
enum cfagenttype Agent2Type(char *name)
/* convert abstract data type names: int, ilist etc */
{ int i;
Debug("Agent2Type(%s)\n",name);
for (i = 0; i < (int)cf_notype; i++)
{
if (name && strcmp(CF_AGENTTYPES[i],name)==0)
{
break;
}
}
return (enum cfagenttype)i;
}
/****************************************************************************/
enum cfdatatype GetControlDatatype(char *varname,struct BodySyntax *bp)
{ int i = 0;
for (i = 0; bp[i].range != NULL; i++)
{
if (varname && strcmp(bp[i].lval,varname) == 0)
{
return bp[i].dtype;
}
}
return cf_notype;
}
/****************************************************************************/
int GetBoolean(char *s)
{ struct Item *list = SplitString(CF_BOOL,','), *ip;
int count = 0;
for (ip = list; ip != NULL; ip=ip->next)
{
if (strcmp(s,ip->name) == 0)
{
break;
}
count++;
}
DeleteItemList(list);
if (count % 2)
{
return false;
}
else
{
return true;
}
}
/****************************************************************************/
long Str2Int(char *s)
{ long a = CF_NOINT;
char c = 'X';
char remainder[CF_BUFSIZE];
char output[CF_BUFSIZE];
if (s == NULL)
{
return CF_NOINT;
}
if (strcmp(s,"inf") == 0)
{
return (long)CF_INFINITY;
}
if (strcmp(s,"now") == 0)
{
return (long)CFSTARTTIME;
}
remainder[0] = '\0';
sscanf(s,"%ld%c%s",&a,&c,remainder);
// Test whether remainder is space only
if (a == CF_NOINT || !IsSpace(remainder))
{
if (THIS_AGENT_TYPE == cf_common)
{
CfOut(cf_inform,""," !! Error reading assumed integer value \"%s\" => \"%s\" (found remainder \"%s\")\n",s,"non-value",remainder);
if (strchr(s,'$'))
{
CfOut(cf_inform,""," !! The variable might not yet be expandable - not necessarily an error");
}
}
}
else
{
switch (c)
{
case 'k':
a = 1000 * a;
break;
case 'K':
a = 1024 * a;
break;
case 'm':
a = 1000 * 1000 * a;
break;
case 'M':
a = 1024 * 1024 * a;
break;
case 'g':
a = 1000 * 1000 * 1000 * a;
break;
case 'G':
a = 1024 * 1024 * 1024 * a;
break;
case '%':
if (a < 0 || a > 100)
{
CfOut(cf_error,"","Percentage out of range (%d)",a);
return CF_NOINT;
}
else
{
/* Represent percentages internally as negative numbers */
a = -a;
}
break;
case ' ':
break;
default:
break;
}
}
return a;
}
/****************************************************************************/
long TimeCounter2Int(const char *s)
{
long d = 0, h = 0, m = 0;
char output[CF_BUFSIZE];
if (s == NULL)
{
return CF_NOINT;
}
if (strchr(s, '-'))
{
if (sscanf(s, "%ld-%ld:%ld", &d, &h, &m) != 3)
{
snprintf(output, CF_BUFSIZE, "Unable to parse TIME 'ps' field, expected dd-hh:mm, got '%s'", s);
ReportError(output);
}
}
else
{
if (sscanf(s, "%ld:%ld", &h, &m) != 2)
{
snprintf(output, CF_BUFSIZE, "Unable to parse TIME 'ps' field, expected hH:mm, got '%s'", s);
ReportError(output);
}
}
return 60 * (m + 60 * (h + 24 * d));
}
/****************************************************************************/
long TimeAbs2Int(char *s)
{ time_t cftime;
int i;
char mon[4],h[3],m[3];
long month = 0,day = 0,hour = 0,min = 0, year = 0;
static long days[] = {31,28,31,30,31,30,31,31,30,31,30,31};
if (s == NULL)
{
return CF_NOINT;
}
year = Str2Int(VYEAR);
if (year % 4 == 0) /* leap years */
{
days[1] = 29;
}
if (strstr(s,":")) /* Hr:Min */
{
sscanf(s,"%2[^:]:%2[^:]:",h,m);
month = Month2Int(VMONTH);
day = Str2Int(VDAY);
hour = Str2Int(h);
min = Str2Int(m);
}
else /* date Month */
{
sscanf(s,"%3[a-zA-Z] %ld",mon,&day);
month = Month2Int(mon);
if (Month2Int(VMONTH) < month)
{
/* Wrapped around */
year--;
}
}
Debug("(%s)\n%ld=%s,%ld=%s,%ld,%ld,%ld\n",s,year,VYEAR,month,VMONTH,day,hour,min);
cftime = 0;
cftime += min * 60;
cftime += hour * 3600;
cftime += (day - 1) * 24 * 3600;
cftime += 24 * 3600 * ((year-1970)/4); /* Leap years */
for (i = 0; i < month - 1; i++)
{
cftime += days[i] * 24 * 3600;
}
cftime += (year - 1970) * 365 * 24 * 3600;
Debug("Time %s CORRESPONDS %s\n",s,cf_ctime(&cftime));
return (long) cftime;
}
/****************************************************************************/
long Months2Seconds(int m)
{
static long days[] = {31,28,31,30,31,30,31,31,30,31,30,31};
long tot_days = 0;
int this_month,i,month,year;
if (m == 0)
{
return 0;
}
this_month = Month2Int(VMONTH);
year = Str2Int(VYEAR);
for (i = 0; i < m; i++)
{
month = (this_month - i) % 12;
while (month < 0)
{
month += 12;
year--;
}
if ((year % 4) && (month == 1))
{
tot_days += 29;
}
else
{
tot_days += days[month];
}
}
return (long) tot_days * 3600 * 24;
}
/*********************************************************************/
enum cfinterval Str2Interval(char *string)
{ static char *text[3] = { "hourly", "daily", NULL };
int i;
for (i = 0; text[i] != NULL; i++)
{
if (string && (strcmp(text[i],string) == 0))
{
return i;
}
}
return cfa_nointerval;
}
/*********************************************************************/
int Day2Number(char *datestring)
{ int i = 0;
for (i = 0; i < 7; i++)
{
if (strncmp(datestring,DAY_TEXT[i],3) == 0)
{
return i;
}
}
return -1;
}
/****************************************************************************/
void UtcShiftInterval(time_t t, char *out, int outSz)
/* 00 - 06,
06 - 12,
12 - 18,
18 - 24*/
{
char buf[CF_MAXVARSIZE];
int hr = 0, fromHr = 0, toHr = 0;
cf_strtimestamp_utc(t,buf);
sscanf(buf+11,"%d", &hr);
buf[11] = '\0';
if(hr < 6)
{
fromHr = 0;
toHr = 6;
}
else if(hr < 12)
{
fromHr = 6;
toHr = 12;
}
else if(hr < 18)
{
fromHr = 12;
toHr = 18;
}
else
{
fromHr = 18;
toHr = 24;
}
snprintf(out, outSz, "%s %02d-%02d", buf, fromHr, toHr);
}
/****************************************************************************/
mode_t Str2Mode(char *s)
{ int a = CF_UNDEFINED;
char output[CF_BUFSIZE];
if (s == NULL)
{
return 0;
}
sscanf(s,"%o",&a);
if (a == CF_UNDEFINED)
{
snprintf(output,CF_BUFSIZE,"Error reading assumed octal value %s\n",s);
ReportError(output);
}
return (mode_t)a;
}
/****************************************************************************/
double Str2Double(char *s)
{ double a = CF_NODOUBLE;
char remainder[CF_BUFSIZE];
char output[CF_BUFSIZE];
char c = 'X';
if (s == NULL)
{
return CF_NODOUBLE;
}
remainder[0] = '\0';
sscanf(s,"%lf%c%s",&a,&c,remainder);
if (a == CF_NODOUBLE || !IsSpace(remainder))
{
snprintf(output,CF_BUFSIZE,"Error reading assumed real value %s (anomalous remainder %s)\n",s,remainder);
ReportError(output);
}
else
{
switch (c)
{
case 'k':
a = 1000 * a;
break;
case 'K':
a = 1024 * a;
break;
case 'm':
a = 1000 * 1000 * a;
break;
case 'M':
a = 1024 * 1024 * a;
break;
case 'g':
a = 1000 * 1000 * 1000 * a;
break;
case 'G':
a = 1024 * 1024 * 1024 * a;
break;
case '%':
if (a < 0 || a > 100)
{
CfOut(cf_error,"","Percentage out of range (%d)",a);
return CF_NOINT;
}
else
{
/* Represent percentages internally as negative numbers */
a = -a;
}
break;
case ' ':
break;
default:
break;
}
}
return a;
}
/****************************************************************************/
void IntRange2Int(char *intrange,long *min,long *max,struct Promise *pp)
{ struct Item *split;
long lmax = CF_LOWINIT, lmin = CF_HIGHINIT;
char output[CF_BUFSIZE];
/* Numeric types are registered by range separated by comma str "min,max" */
if (intrange == NULL)
{
*min = CF_NOINT;
*max = CF_NOINT;
return;
}
split = SplitString(intrange,',');
sscanf(split->name,"%ld",&lmin);
if (strcmp(split->next->name,"inf") == 0)
{
lmax = (long)CF_INFINITY;
}
else
{
sscanf(split->next->name,"%ld",&lmax);
}
DeleteItemList(split);
if (lmin == CF_HIGHINIT || lmax == CF_LOWINIT)
{
PromiseRef(cf_error,pp);
snprintf(output,CF_BUFSIZE,"Could not make sense of integer range [%s]",intrange);
FatalError(output);
}
*min = lmin;
*max = lmax;
}
/*********************************************************************/
enum cf_acl_method Str2AclMethod(char *string)
{ static char *text[3] = { "append", "overwrite", NULL };
int i;
for (i = 0; i < 2; i++)
{
if (string && (strcmp(text[i],string) == 0))
{
return i;
}
}
return cfacl_nomethod;
}
/*********************************************************************/
enum cf_acl_type Str2AclType(char *string)
{ static char *text[4] = { "generic","posix", "ntfs", NULL };
int i;
for (i = 0; i < 3; i++)
{
if (string && (strcmp(text[i],string) == 0))
{
return i;
}
}
return cfacl_notype;
}
/*********************************************************************/
enum cf_acl_inherit Str2AclInherit(char *string)
{ static char *text[5] = { "nochange", "specify", "parent", "clear", NULL };
int i;
for (i = 0; i < 4; i++)
{
if (string && (strcmp(text[i],string) == 0))
{
return i;
}
}
return cfacl_noinherit;
}
/*********************************************************************/
enum cf_acl_inherit Str2ServicePolicy(char *string)
{ static char *text[4] = { "start", "stop", "disable", NULL };
int i;
for (i = 0; i < 3; i++)
{
if (string && (strcmp(text[i],string) == 0))
{
return i;
}
}
return cfsrv_nostatus;
}
/*********************************************************************/
char *Dtype2Str(enum cfdatatype dtype)
{
switch(dtype)
{
case cf_str:
return "s";
case cf_slist:
return "sl";
case cf_int:
return "i";
case cf_ilist:
return "il";
case cf_real:
return "r";
case cf_rlist:
return "rl";
case cf_opts:
return "m";
case cf_olist:
return "ml";
default:
return "D?";
}
}
/*********************************************************************/
/* Level */
/*********************************************************************/
int Month2Int(char *string)
{
return MonthLen2Int(string,10); // no month names longer than 10 chars
}
/*************************************************************/
int MonthLen2Int(char *string, int len)
{ int i;
if (string == NULL)
{
return -1;
}
for (i = 0; i < 12; i++)
{
if (strncmp(MONTH_TEXT[i],string,strlen(string))==0)
{
return i+1;
break;
}
}
return -1;
}
/*********************************************************************/
void TimeToDateStr(time_t t, char *outStr, int outStrSz)
/**
* Formats a time as "30 Sep 2010".
*/
{
char month[CF_SMALLBUF],day[CF_SMALLBUF],year[CF_SMALLBUF];
char tmp[CF_SMALLBUF];
snprintf(tmp,sizeof(tmp),"%s",cf_ctime(&t));
sscanf(tmp,"%*s %5s %3s %*s %5s",month,day,year);
snprintf(outStr,outStrSz,"%s %s %s",day,month,year);
}
/*********************************************************************/
const char *GetArg0(const char *execstr)
{ const char *sp;
static char arg[CF_BUFSIZE];
int i = 0;
for (sp = execstr; *sp != ' ' && *sp != '\0'; sp++)
{
i++;
if (*sp == '\"')
{
DeEscapeQuotedString(sp,arg);
return arg;
}
}
memset(arg,0,CF_MAXVARSIZE);
strncpy(arg,execstr,i);
arg[i] = '\0';
return arg;
}
/*************************************************************/
void CommPrefix(char *execstr,char *comm)
{ char *sp;
for (sp = execstr; *sp != ' ' && *sp != '\0'; sp++)
{
}
if (sp - 10 >= execstr)
{
sp -= 10; /* copy 15 most relevant characters of command */
}
else
{
sp = execstr;
}
memset(comm,0,20);
strncpy(comm,sp,15);
}
/*************************************************************/
int NonEmptyLine(char *line)
{ char *sp;
for (sp = line; *sp != '\0'; sp++)
{
if (!isspace((int)*sp))
{
return true;
}
}
return false;
}
/*************************************************************/
char *Item2String(struct Item *ip)
{
struct Item *currItem;
int stringSz = 0;
char *buf;
// compute required buffer size
for(currItem = ip; currItem != NULL; currItem = currItem->next)
{
stringSz += strlen(currItem->name);
stringSz++; // newline space
}
// we automatically get \0-termination because we are not appending a \n after the last item
buf = calloc(1, stringSz);
if(buf == NULL)
{
FatalError("Memory allocation in ItemToString()");
}
// do the copy
for(currItem = ip; currItem != NULL; currItem = currItem->next)
{
strcat(buf, currItem->name);
if(currItem->next != NULL) // no newline after last item
{
strcat(buf, "\n");
}
}
return buf;
}
/*******************************************************************/
static int IsSpace(char *remainder)
{ char *sp;
for (sp = remainder; *sp != '\0'; sp++)
{
if (!isspace(*sp))
{
return false;
}
}
return true;
}
/*******************************************************************/
int IsNumber(char *s)
{ char *sp;
for (sp = s; *sp != '\0'; sp++)
{
if (!isdigit(*sp))
{
return false;
}
}
return true;
}
/*******************************************************************/
int IsRealNumber(char *s)
{ double a = CF_NODOUBLE;
sscanf(s,"%lf",&a);
if (a == CF_NODOUBLE)
{
return false;
}
return true;
}
/********************************************************************/
enum cfd_menu String2Menu(char *s)
{ static char *menus[] = { "delta", "full", "relay", NULL };
int i;
for (i = 0; menus[i] != NULL; i++)
{
if (strcmp(s,menus[i]) == 0)
{
return i;
}
}
return cfd_menu_error;
}
/*******************************************************************/
/* Unix-only functions */
/*******************************************************************/
#ifndef MINGW
/****************************************************************************/
/* Rlist to Uid/Gid lists */
/****************************************************************************/
struct UidList *Rlist2UidList(struct Rlist *uidnames,struct Promise *pp)
{ struct UidList *uidlist = NULL;
struct Rlist *rp;
char username[CF_MAXVARSIZE];
uid_t uid;
for (rp = uidnames; rp != NULL; rp=rp->next)
{
username[0] = '\0';
uid = Str2Uid(rp->item,username,pp);
AddSimpleUidItem(&uidlist,uid,username);
}
if (uidlist == NULL)
{
AddSimpleUidItem(&uidlist,CF_SAME_OWNER,NULL);
}
return (uidlist);
}
/*********************************************************************/
struct GidList *Rlist2GidList(struct Rlist *gidnames,struct Promise *pp)
{ struct GidList *gidlist = NULL;
struct Rlist *rp;
char groupname[CF_MAXVARSIZE];
gid_t gid;
for (rp = gidnames; rp != NULL; rp=rp->next)
{
groupname[0] = '\0';
gid = Str2Gid(rp->item,groupname,pp);
AddSimpleGidItem(&gidlist,gid,groupname);
}
if (gidlist == NULL)
{
AddSimpleGidItem(&gidlist,CF_SAME_GROUP,NULL);
}
return(gidlist);
}
/*********************************************************************/
uid_t Str2Uid(char *uidbuff,char *usercopy,struct Promise *pp)
{ struct Item *ip, *tmplist;
struct passwd *pw;
int offset,uid = -2,tmp = -2;
char *machine,*user,*domain;
if (uidbuff[0] == '+') /* NIS group - have to do this in a roundabout */
{ /* way because calling getpwnam spoils getnetgrent */
offset = 1;
if (uidbuff[1] == '@')
{
offset++;
}
setnetgrent(uidbuff+offset);
tmplist = NULL;
while (getnetgrent(&machine,&user,&domain))
{
if (user != NULL)
{
AppendItem(&tmplist,user,NULL);
}
}
endnetgrent();
for (ip = tmplist; ip != NULL; ip=ip->next)
{
if ((pw = getpwnam(ip->name)) == NULL)
{
CfOut(cf_inform,""," !! Unknown user in promise \'%s\'\n",ip->name);
if (pp != NULL)
{
PromiseRef(cf_inform,pp);
}
uid = CF_UNKNOWN_OWNER; /* signal user not found */
}
else
{
uid = pw->pw_uid;
if (usercopy != NULL)
{
strcpy(usercopy,ip->name);
}
}
}
DeleteItemList(tmplist);
return uid;
}
if (isdigit((int)uidbuff[0]))
{
sscanf(uidbuff,"%d",&tmp);
uid = (uid_t)tmp;
}
else
{
if (strcmp(uidbuff,"*") == 0)
{
uid = CF_SAME_OWNER; /* signals wildcard */
}
else if ((pw = getpwnam(uidbuff)) == NULL)
{
CfOut(cf_inform,""," !! Unknown user %s in promise\n",uidbuff);
uid = CF_UNKNOWN_OWNER; /* signal user not found */
if (usercopy != NULL)
{
strcpy(usercopy,uidbuff);
}
}
else
{
uid = pw->pw_uid;
}
}
return uid;
}
/*********************************************************************/
gid_t Str2Gid(char *gidbuff,char *groupcopy,struct Promise *pp)
{ struct group *gr;
int gid = -2, tmp = -2;
if (isdigit((int)gidbuff[0]))
{
sscanf(gidbuff,"%d",&tmp);
gid = (gid_t)tmp;
}
else
{
if (strcmp(gidbuff,"*") == 0)
{
gid = CF_SAME_GROUP; /* signals wildcard */
}
else if ((gr = getgrnam(gidbuff)) == NULL)
{
CfOut(cf_inform,""," !! Unknown group \'%s\' in promise\n",gidbuff);
if (pp)
{
PromiseRef(cf_inform,pp);
}
gid = CF_UNKNOWN_GROUP;
}
else
{
gid = gr->gr_gid;
strcpy(groupcopy,gidbuff);
}
}
return gid;
}
#endif /* NOT MINGW */
cfengine-3.2.4/src/mon_network.c 0000644 0001750 0001750 00000014106 11715232734 013523 0000000 0000000 /*
Copyright (C) Cfengine AS
This file is part of Cfengine 3 - written and maintained by Cfengine 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 Commerical Open Source License
(COSL) may apply to this file if you as a licensee so wish it. See
included file COSL.txt.
*/
#include "cf3.defs.h"
#include "cf3.extern.h"
#include "monitoring.h"
/* Globals */
static struct Item *ALL_INCOMING;
static struct Item *ALL_OUTGOING;
/* Implementation */
static void SetNetworkEntropyClasses(const char *service, const char *direction,
const struct Item *list)
{
const struct Item *ip;
struct Item *addresses = NULL;
double entropy;
for (ip = list; ip != NULL; ip=ip->next)
{
if (strlen(ip->name) > 0)
{
char local[CF_BUFSIZE];
char remote[CF_BUFSIZE];
char vbuff[CF_BUFSIZE];
char *sp;
if (strncmp(ip->name,"tcp",3) == 0)
{
sscanf(ip->name,"%*s %*s %*s %s %s",local,remote); /* linux-like */
}
else
{
sscanf(ip->name,"%s %s",local,remote); /* solaris-like */
}
strncpy(vbuff,remote,CF_BUFSIZE-1);
for (sp = vbuff+strlen(vbuff)-1; isdigit((int)*sp); sp--)
{
}
*sp = '\0';
if (!IsItemIn(addresses,vbuff))
{
AppendItem(&addresses,vbuff,"");
}
IncrementItemListCounter(addresses,vbuff);
}
}
entropy = MonEntropyCalculate(addresses);
MonEntropyClassesSet(service, direction, entropy);
DeleteItemList(addresses);
}
/******************************************************************************/
void MonNetworkGatherData(double *cf_this)
{
FILE *pp;
char local[CF_BUFSIZE],remote[CF_BUFSIZE],comm[CF_BUFSIZE];
struct Item *in[ATTR],*out[ATTR];
char *sp;
int i;
char vbuff[CF_BUFSIZE];
Debug("GatherSocketData()\n");
for (i = 0; i < ATTR; i++)
{
in[i] = out[i] = NULL;
}
if (ALL_INCOMING != NULL)
{
DeleteItemList(ALL_INCOMING);
ALL_INCOMING = NULL;
}
if (ALL_OUTGOING != NULL)
{
DeleteItemList(ALL_OUTGOING);
ALL_OUTGOING = NULL;
}
sscanf(VNETSTAT[VSYSTEMHARDCLASS],"%s",comm);
strcat(comm," -n");
if ((pp = cf_popen(comm,"r")) == NULL)
{
return;
}
while (!feof(pp))
{
memset(local,0,CF_BUFSIZE);
memset(remote,0,CF_BUFSIZE);
CfReadLine(vbuff,CF_BUFSIZE,pp);
if (strstr(vbuff,"UNIX"))
{
break;
}
if (!strstr(vbuff,"."))
{
continue;
}
/* Different formats here ... ugh.. */
if (strncmp(vbuff,"tcp",3) == 0)
{
sscanf(vbuff,"%*s %*s %*s %s %s",local,remote); /* linux-like */
}
else
{
sscanf(vbuff,"%s %s",local,remote); /* solaris-like */
}
if (strlen(local) == 0)
{
continue;
}
for (sp = local+strlen(local); (*sp != '.') && (sp > local); sp--)
{
}
sp++;
if ((strlen(sp) < 5) &&!IsItemIn(ALL_INCOMING,sp))
{
PrependItem(&ALL_INCOMING,sp,NULL);
}
for (sp = remote+strlen(remote); (sp >= remote) && !isdigit((int)*sp); sp--)
{
}
sp++;
if ((strlen(sp) < 5) && !IsItemIn(ALL_OUTGOING,sp))
{
PrependItem(&ALL_OUTGOING,sp,NULL);
}
for (i = 0; i < ATTR; i++)
{
char *spend;
for (spend = local+strlen(local)-1; isdigit((int)*spend); spend--)
{
}
spend++;
if (strcmp(spend,ECGSOCKS[i].portnr) == 0)
{
cf_this[ECGSOCKS[i].in]++;
AppendItem(&in[i],vbuff,"");
}
for (spend = remote+strlen(remote)-1; (sp >= remote) && isdigit((int)*spend); spend--)
{
}
spend++;
if (strcmp(spend,ECGSOCKS[i].portnr) == 0)
{
cf_this[ECGSOCKS[i].out]++;
AppendItem(&out[i],vbuff,"");
}
}
}
cf_pclose(pp);
/* Now save the state for ShowState() cf2 version alert function IFF
the state is not smaller than the last or at least 40 minutes
older. This mirrors the persistence of the maxima classes */
for (i = 0; i < ATTR; i++)
{
struct stat statbuf;
time_t now = time(NULL);
Debug("save incoming %s\n",ECGSOCKS[i].name);
snprintf(vbuff,CF_MAXVARSIZE,"%s/state/cf_incoming.%s",CFWORKDIR,ECGSOCKS[i].name);
if (cfstat(vbuff,&statbuf) != -1)
{
if ((ByteSizeList(in[i]) < statbuf.st_size) && (now < statbuf.st_mtime+40*60))
{
CfOut(cf_verbose,"","New state %s is smaller, retaining old for 40 mins longer\n",ECGSOCKS[i].name);
DeleteItemList(in[i]);
continue;
}
}
SetNetworkEntropyClasses(ECGSOCKS[i].name,"in",in[i]);
RawSaveItemList(in[i],vbuff);
DeleteItemList(in[i]);
Debug("Saved in netstat data in %s\n",vbuff);
}
for (i = 0; i < ATTR; i++)
{
struct stat statbuf;
time_t now = time(NULL);
Debug("save outgoing %s\n",ECGSOCKS[i].name);
snprintf(vbuff,CF_MAXVARSIZE,"%s/state/cf_outgoing.%s",CFWORKDIR,ECGSOCKS[i].name);
if (cfstat(vbuff,&statbuf) != -1)
{
if ((ByteSizeList(out[i]) < statbuf.st_size) && (now < statbuf.st_mtime+40*60))
{
CfOut(cf_verbose,"","New state %s is smaller, retaining old for 40 mins longer\n",ECGSOCKS[i].name);
DeleteItemList(out[i]);
continue;
}
}
SetNetworkEntropyClasses(ECGSOCKS[i].name,"out",out[i]);
RawSaveItemList(out[i],vbuff);
Debug("Saved out netstat data in %s\n",vbuff);
DeleteItemList(out[i]);
}
}
cfengine-3.2.4/src/string_expressions.c 0000644 0001750 0001750 00000014617 11715232734 015140 0000000 0000000 /*
Copyright (C) Cfengine AS
This file is part of Cfengine 3 - written and maintained by Cfengine 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 Commerical Open Source License
(COSL) may apply to this file if you as a licensee so wish it. See
included file COSL.txt.
*/
#ifdef HAVE_CONFIG_H
# include
#endif
#include
#include
#include
#include "bool.h"
#include "string_expressions.h"
#include "cf3.defs.h"
#include "prototypes3.h"
/* */
static StringParseResult ParseQname(const char *expr, int start, int end)
{
StringParseResult lhs, rhs;
StringExpression *ret, *subret, *dot;
lhs = ParseStringExpression(expr, start, end);
if (!lhs.result)
{
return lhs;
}
if (lhs.position == end || expr[lhs.position] != '.')
{
return lhs;
}
rhs = ParseStringExpression(expr, lhs.position + 1, end);
if (!rhs.result)
{
FreeStringExpression(lhs.result);
return rhs;
}
dot = calloc(1, sizeof(StringExpression));
dot->op = LITERAL;
dot->val.literal.literal = strdup(".");
subret = calloc(1, sizeof(StringExpression));
subret->op = CONCAT;
subret->val.concat.lhs = dot;
subret->val.concat.rhs = rhs.result;
ret = calloc(1, sizeof(StringExpression));
ret->op = CONCAT;
ret->val.concat.lhs = lhs.result;
ret->val.concat.rhs = subret;
return (StringParseResult) { ret, rhs.position };
}
/* */
static StringParseResult ParseVarRef(const char *expr, int start, int end)
{
if (start + 1 < end && expr[start] == '$')
{
if (expr[start+1] == '(' || expr[start+1] == '{')
{
char closing_bracket = expr[start+1] == '(' ? ')' : '}';
StringParseResult res = ParseQname(expr, start + 2, end);
if (res.result)
{
if (res.position < end && expr[res.position] == closing_bracket)
{
StringExpression *ret = calloc(1, sizeof(StringExpression));
ret->op = VARREF;
ret->val.varref.name = res.result;
return (StringParseResult) { ret, res.position + 1 };
}
else
{
FreeStringExpression(res.result);
return (StringParseResult) { NULL, res.position };
}
}
else
{
return res;
}
}
else
{
return (StringParseResult) { NULL, start + 1 };
}
}
else
{
return (StringParseResult) { NULL, start };
}
}
/* */
static bool ValidTokenCharacter(char c)
{
if (c >= 'a' && c <= 'z')
{
return true;
}
if (c >= 'A' && c <= 'Z')
{
return true;
}
if (c >= '0' && c <= '9')
{
return true;
}
if (c == '_' || c == '[' || c == ']')
{
return true;
}
return false;
}
static StringParseResult ParseToken(const char *expr, int start, int end)
{
int endlit = start;
while (endlit < end && ValidTokenCharacter(expr[endlit]))
{
endlit++;
}
if (endlit > start)
{
StringExpression *ret = calloc(1, sizeof(StringExpression));
ret->op = LITERAL;
ret->val.literal.literal = strndup(expr + start, endlit - start);
return (StringParseResult) { ret, endlit };
}
else
{
return (StringParseResult) { NULL, endlit };
}
}
/* */
static StringParseResult ParseTerm(const char *expr, int start, int end)
{
StringParseResult res = ParseToken(expr, start, end);
if (res.result)
{
return res;
}
else
{
return ParseVarRef(expr, start, end);
}
}
/* */
StringParseResult ParseStringExpression(const char *expr, int start, int end)
{
StringParseResult lhs = ParseTerm(expr, start, end);
if (lhs.result)
{
StringParseResult rhs = ParseStringExpression(expr, lhs.position, end);
if (rhs.result)
{
StringExpression *ret = calloc(1, sizeof(StringExpression));
ret->op = CONCAT;
ret->val.concat.lhs = lhs.result;
ret->val.concat.rhs = rhs.result;
return (StringParseResult) { ret, rhs.position };
}
else
{
return lhs;
}
}
else
{
return lhs;
}
}
/* Evaluation */
static char *EvalConcat(const StringExpression *expr, VarRefEvaluator evalfn,
void *param)
{
char *lhs, *rhs;
lhs = EvalStringExpression(expr->val.concat.lhs, evalfn, param);
if (!lhs)
{
return NULL;
}
rhs = EvalStringExpression(expr->val.concat.rhs, evalfn, param);
if (!rhs)
{
free(lhs);
return NULL;
}
char *res = malloc(strlen(lhs) + strlen(rhs) + 1);
sprintf(res, "%s%s", lhs, rhs);
free(lhs);
free(rhs);
return res;
}
static char *EvalVarRef(const StringExpression *expr, VarRefEvaluator evalfn,
void *param)
{
char *name, *eval;
name = EvalStringExpression(expr->val.varref.name, evalfn, param);
if (!name)
{
return NULL;
}
eval = (*evalfn)(name, param);
free(name);
return eval;
}
char *EvalStringExpression(const StringExpression *expr, VarRefEvaluator evalfn,
void *param)
{
switch (expr->op)
{
case CONCAT:
return EvalConcat(expr, evalfn, param);
case LITERAL:
return strdup(expr->val.literal.literal);
case VARREF:
return EvalVarRef(expr, evalfn, param);
default:
FatalError("Unknown type of string expression"
"encountered during evaluation: %d", expr->op);
}
}
/* Freeing results */
void FreeStringExpression(StringExpression *expr)
{
if (!expr)
{
return;
}
switch (expr->op)
{
case CONCAT:
FreeStringExpression(expr->val.concat.lhs);
FreeStringExpression(expr->val.concat.rhs);
break;
case LITERAL:
free(expr->val.literal.literal);
break;
case VARREF:
FreeStringExpression(expr->val.varref.name);
break;
default:
FatalError("Unknown type of string expression encountered: %d",
expr->op);
}
free(expr);
}
cfengine-3.2.4/src/mod_measurement.c 0000644 0001750 0001750 00000010047 11715232734 014345 0000000 0000000 /*
Copyright (C) Cfengine AS
This file is part of Cfengine 3 - written and maintained by Cfengine 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 Commerical Open Source License
(COSL) may apply to this file if you as a licensee so wish it. See
included file COSL.txt.
*/
/*****************************************************************************/
/* */
/* File: mod_process.c */
/* */
/*****************************************************************************/
/*
This file can act as a template for adding functionality to cfengine 3.
All functionality can be added by extending the main array
CF_MOD_SUBTYPES[CF3_MODULES]
and its array dimension, in mod_common, in the manner shown here.
*/
#define CF3_MOD_MEASUREMENT
#include "cf3.defs.h"
#include "cf3.extern.h"
/***********************************************************/
/* Read this module file backwards, as dependencies have */
/* to be defined first - these arrays declare pairs of */
/* constraints */
/* */
/* lval => rval */
/* */
/* in the form (lval,type,range) */
/* */
/* If the type is cf_body then the range is a pointer */
/* to another array of pairs, like in a body "sub-routine" */
/* */
/***********************************************************/
struct BodySyntax CF_MATCHVALUE_BODY[] =
{
/* Row models */
{"select_line_matching",cf_str,CF_ANYSTRING,"Regular expression for matching line location"},
{"select_line_number",cf_int,CF_VALRANGE,"Read from the n-th line of the output (fixed format)"},
{"extraction_regex",cf_str,"","Regular expression that should contain a single backreference for extracting a value"},
{"track_growing_file",cf_opts,CF_BOOL,"If true, cfengine remembers the position to which is last read when opening the file, and resets to the start if the file has since been truncated"},
{NULL,cf_notype,NULL,NULL}
};
/***************************************************************/
struct BodySyntax CF_MEASURE_BODIES[] =
{
{"stream_type",cf_opts,"pipe,file","The datatype being collected."},
{"data_type",cf_opts,"counter,int,real,string,slist","The datatype being collected."},
{"history_type",cf_opts,"weekly,scalar,static,log","Whether the data can be seen as a time-series or just an isolated value"},
{"units",cf_str,"","The engineering dimensions of this value or a note about its intent used in plots"},
{"match_value",cf_body,CF_MATCHVALUE_BODY,"Criteria for extracting the measurement from a datastream"},
{NULL,cf_notype,NULL,NULL}
};
/***************************************************************/
/* This is the point of entry from mod_common.c */
/***************************************************************/
struct SubTypeSyntax CF_MEASUREMENT_SUBTYPES[] =
{
{"monitor","measurements",CF_MEASURE_BODIES},
{NULL,NULL,NULL},
};
cfengine-3.2.4/src/dbm_berkeley.c 0000644 0001750 0001750 00000022061 11715232734 013604 0000000 0000000 /*
Copyright (C) Cfengine AS
This file is part of Cfengine 3 - written and maintained by Cfengine 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 Commerical Open Source License
(COSL) may apply to this file if you as a licensee so wish it. See
included file COSL.txt.
*/
/*****************************************************************************/
/* */
/* File: dbm_berkeley.c */
/* */
/*****************************************************************************/
/*
* Implementation of the Cfengine DBM API using Berkeley DB.
*/
#include "cf3.defs.h"
#include "cf3.extern.h"
#ifdef BDB
static DBT *BDB_NewDBKey(char *name);
static DBT *BDB_NewDBComplexKey(char *key,int size);
static void BDB_DeleteDBKey(DBT *key);
static DBT *BDB_NewDBValue(const void *ptr,int size);
static void BDB_DeleteDBValue(DBT *value);
/*****************************************************************************/
int BDB_OpenDB(char *filename,DB **dbp)
{
int ret;
if ((ret = db_create(dbp,NULL,0)) != 0)
{
CfOut(cf_error, "",
"BDB_OpenDB: Couldn't get database environment for %s: %s\n",
filename, db_strerror(ret));
return false;
}
#ifdef CF_OLD_DB
if ((ret = ((*dbp)->open)(*dbp,filename,NULL,DB_BTREE,DB_CREATE,0644)) != 0)
#else
if ((ret = ((*dbp)->open)(*dbp,NULL,filename,NULL,DB_BTREE,DB_CREATE,0644)) != 0)
#endif
{
CfOut(cf_error, "",
"BDB_OpenDB: Couldn't open database %s: %s\n",
filename, db_strerror(ret));
return false;
}
return true;
}
/*****************************************************************************/
int BDB_CloseDB(DB *dbp)
{
int ret;
if ((ret = dbp->close(dbp, 0)) == 0)
{
return true;
}
else
{
CfOut(cf_error, "",
"BDB_CloseDB: Unable to close database: %s\n", db_strerror(ret));
return false;
}
}
/*****************************************************************************/
int BDB_ValueSizeDB(DB *dbp, char *key)
{
DBT *db_key, value;
int retv;
int ret;
db_key = BDB_NewDBKey(key);
memset(&value,0,sizeof(DBT));
if ((ret = dbp->get(dbp,NULL,db_key,&value,0)) == 0)
{
retv = value.size;
}
else
{
retv = -1;
if (ret == DB_NOTFOUND || ret == DB_KEYEMPTY)
{
Debug("Key %s does not exist in database.\n", key);
}
else
{
CfOut(cf_error, "",
"BDB_ValueSizeDB: Error trying to read database: %s\n",
db_strerror(ret));
}
}
BDB_DeleteDBKey(db_key);
return retv;
}
/*****************************************************************************/
int BDB_ReadComplexKeyDB(DB *dbp,char *name,int keysize,void *ptr,int size)
{
DBT *key,value;
int ret;
bool retval = false;
key = BDB_NewDBValue(name,keysize);
memset(&value,0,sizeof(DBT));
if ((ret = dbp->get(dbp,NULL,key,&value,0)) == 0)
{
memset(ptr,0,size);
if (value.data)
{
if (size < value.size)
{
memcpy(ptr,value.data,size);
}
else
{
memcpy(ptr,value.data,value.size);
}
Debug("READ %s\n",name);
retval = true;
}
}
else
{
if (ret == DB_NOTFOUND || ret == DB_KEYEMPTY)
{
Debug("Key %.*s does not exist in database", keysize, name);
}
else
{
CfOut(cf_error, "",
"BDB_ReadComplexKeyDB: Error trying to read database: %s\n",
db_strerror(ret));
}
}
BDB_DeleteDBValue(key);
return retval;
}
/*****************************************************************************/
int BDB_RevealDB(DB *dbp,char *name,void **result,int *rsize)
{
DBT *key,value;
int ret;
bool retval = false;
key = BDB_NewDBKey(name);
memset(&value,0,sizeof(DBT));
if ((ret = dbp->get(dbp,NULL,key,&value,0)) == 0)
{
if (value.data)
{
*rsize = value.size;
*result = value.data;
retval = true;
}
}
else
{
if (ret == DB_NOTFOUND || ret == DB_KEYEMPTY)
{
Debug("Key %s does not exist in database", name);
}
else
{
CfOut(cf_error, "", "Error trying to read database: %s\n",
db_strerror(ret));
}
}
BDB_DeleteDBKey(key);
return retval;
}
/*****************************************************************************/
int BDB_WriteComplexKeyDB(DB *dbp,char *name,int keysize,const void *ptr,int size)
{
DBT *key,*value;
int ret;
key = BDB_NewDBValue(name,keysize);
value = BDB_NewDBValue(ptr,size);
if ((ret = dbp->put(dbp,NULL,key,value,0)) == 0)
{
Debug("WriteDB => %s\n",name);
BDB_DeleteDBValue(key);
BDB_DeleteDBValue(value);
return true;
}
else
{
CfOut(cf_error, "",
"BDB_WriteComplexKeyDB: Error trying to write database: %s\n",
db_strerror(ret));
BDB_DeleteDBKey(key);
BDB_DeleteDBValue(value);
return false;
}
}
/*****************************************************************************/
int BDB_DeleteComplexKeyDB(DB *dbp,char *name,int size)
{
DBT *key;
int ret;
key = BDB_NewDBValue(name,size);
if ((ret = dbp->del(dbp,NULL,key,0)) == 0)
{
BDB_DeleteDBKey(key);
return true;
}
else
{
if (ret == DB_NOTFOUND || ret == DB_KEYEMPTY)
{
Debug("Trying to remove from database non-existing key %.*s\n",
size, name);
}
else
{
CfOut(cf_error, "", "BDB_DeleteComplexKeyDB: "
"Unable to remove key %.*s from database: %s\n",
size, name, db_strerror(ret));
}
BDB_DeleteDBKey(key);
return false;
}
}
/*****************************************************************************/
int BDB_NewDBCursor(CF_DB *dbp,CF_DBC **dbcpp)
{
int ret;
if ((ret = dbp->cursor(dbp,NULL,dbcpp,0)) == 0)
{
return true;
}
else
{
CfOut(cf_error, "",
"BDB_NewDBCursor: Error establishing cursor for hash database: %s\n",
db_strerror(ret));
return false;
}
}
/*****************************************************************************/
int BDB_NextDB(CF_DB *dbp,CF_DBC *dbcp,char **key,int *ksize,void **value,int *vsize)
{
DBT dbvalue,dbkey;
int ret;
memset(&dbkey,0,sizeof(DBT));
memset(&dbvalue,0,sizeof(DBT));
ret = dbcp->c_get(dbcp,&dbkey,&dbvalue,DB_NEXT);
*ksize = dbkey.size;
*vsize = dbvalue.size;
*key = dbkey.data;
*value = dbvalue.data;
if (ret == 0)
{
return true;
}
else
{
if (ret != DB_NOTFOUND && ret != DB_KEYEMPTY)
{
CfOut(cf_error, "", "BDB_NextDB: Unable to read database: %s\n",
db_strerror(ret));
}
return false;
}
}
/*****************************************************************************/
int BDB_DeleteDBCursor(CF_DB *dbp,CF_DBC *dbcp)
{
int ret;
if ((ret = dbcp->c_close(dbcp)) == 0)
{
return true;
}
else
{
CfOut(cf_error, "", "BDB_DeleteDBCursor: Unable to close cursor: %s\n",
db_strerror(ret));
return false;
}
}
/*****************************************************************************/
/* Level 2 */
/*****************************************************************************/
static DBT *BDB_NewDBKey(char *name)
{
char *dbkey;
DBT *key;
if ((dbkey = malloc(strlen(name)+1)) == NULL)
{
FatalError("NewChecksumKey malloc error");
}
if ((key = (DBT *)malloc(sizeof(DBT))) == NULL)
{
FatalError("DBT malloc error");
}
memset(key,0,sizeof(DBT));
memset(dbkey,0,strlen(name)+1);
strncpy(dbkey,name,strlen(name));
key->data = (void *)dbkey;
key->size = strlen(name)+1;
return key;
}
/*****************************************************************************/
static void BDB_DeleteDBKey(DBT *key)
{
free((char *)key->data);
free((char *)key);
}
/*****************************************************************************/
static DBT *BDB_NewDBValue(const void *ptr,int size)
{
void *val;
DBT *value;
if ((val = (void *)malloc(size)) == NULL)
{
FatalError("BDB_NewDBKey malloc error");
}
if ((value = (DBT *) malloc(sizeof(DBT))) == NULL)
{
FatalError("DBT Value malloc error");
}
memset(value,0,sizeof(DBT));
memcpy(val,ptr,size);
value->data = val;
value->size = size;
return value;
}
/*****************************************************************************/
static void BDB_DeleteDBValue(DBT *value)
{
free((char *)value->data);
free((char *)value);
}
#endif
cfengine-3.2.4/src/files_copy.c 0000644 0001750 0001750 00000020737 11715232734 013324 0000000 0000000 /*
Copyright (C) Cfengine AS
This file is part of Cfengine 3 - written and maintained by Cfengine 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 Commerical Open Source License
(COSL) may apply to this file if you as a licensee so wish it. See
included file COSL.txt.
*/
/*****************************************************************************/
/* */
/* File: files_copy.c */
/* */
/*****************************************************************************/
#include "cf3.defs.h"
#include "cf3.extern.h"
/*****************************************************************************/
void *CopyFileSources(char *destination,struct Attributes attr,struct Promise *pp)
{ char *source = attr.copy.source;
char *server = pp->this_server;
char vbuff[CF_BUFSIZE];
struct stat ssb,dsb;
struct timespec start;
char eventname[CF_BUFSIZE];
Debug("CopyFileSources(%s,%s)", source, destination);
if (pp->conn != NULL && !pp->conn->authenticated)
{
cfPS(cf_verbose,CF_FAIL,"",pp,attr,"No authenticated source %s in files.copyfrom promise\n",source);
return NULL;
}
if (cf_stat(attr.copy.source,&ssb,attr,pp) == -1)
{
cfPS(cf_inform,CF_FAIL,"",pp,attr,"Can't stat %s in files.copyfrom promise\n",source);
return NULL;
}
start = BeginMeasure();
strncpy(vbuff,destination,CF_BUFSIZE-4);
if (S_ISDIR(ssb.st_mode)) /* could be depth_search */
{
AddSlash(vbuff);
strcat(vbuff,".");
}
if (!MakeParentDirectory(vbuff,attr.move_obstructions))
{
cfPS(cf_inform,CF_FAIL,"",pp,attr,"Can't make directories for %s in files.copyfrom promise\n",vbuff);
return NULL;
}
if (S_ISDIR(ssb.st_mode)) /* could be depth_search */
{
if (attr.copy.purge)
{
CfOut(cf_verbose,""," !! (Destination purging enabled)\n");
}
CfOut(cf_verbose,""," ->> Entering %s\n",source);
SetSearchDevice(&ssb,pp);
SourceSearchAndCopy(source,destination,attr.recursion.depth,attr,pp);
if (cfstat(destination,&dsb) != -1)
{
if (attr.copy.check_root)
{
VerifyCopiedFileAttributes(destination,&dsb,&ssb,attr,pp);
}
}
}
else
{
VerifyCopy(source,destination,attr,pp);
}
snprintf(eventname,CF_BUFSIZE-1,"Copy(%s:%s > %s)",server,source,destination);
EndMeasure(eventname,start);
if (attr.transaction.background)
{
ServerDisconnection(pp->conn);
}
else
{
ServerNotBusy(pp->conn);
}
return NULL;
}
/*****************************************************************************/
/* Local low level */
/*****************************************************************************/
void CheckForFileHoles(struct stat *sstat,struct Promise *pp)
/* Need a transparent way of getting this into CopyReg() */
/* Use a public member in struct Image */
{
if (pp == NULL)
{
return;
}
#if !defined(IRIX) && !defined(MINGW)
if (sstat->st_size > sstat->st_blocks * DEV_BSIZE)
#else
# ifdef HAVE_ST_BLOCKS
if (sstat->st_size > sstat->st_blocks * DEV_BSIZE)
# else
if (sstat->st_size > ST_NBLOCKS((*sstat)) * DEV_BSIZE)
# endif
#endif
{
pp->makeholes = 1; /* must have a hole to get checksum right */
}
pp->makeholes = 0;
}
/*********************************************************************/
int CopyRegularFileDisk(char *source,char *new,struct Attributes attr,struct Promise *pp)
{ int sd, dd, buf_size;
char *buf, *cp;
int n_read, *intp;
long n_read_total = 0;
int last_write_made_hole = 0;
if ((sd = open(source,O_RDONLY|O_BINARY)) == -1)
{
CfOut(cf_inform,"open","Can't copy %s!\n",source);
unlink(new);
return false;
}
unlink(new); /* To avoid link attacks */
if ((dd = open(new,O_WRONLY|O_CREAT|O_TRUNC|O_EXCL|O_BINARY, 0600)) == -1)
{
cfPS(cf_inform,CF_FAIL,"open",pp,attr,"Copy %s possible security violation (race) or permission denied (Not copied)\n",new);
close(sd);
unlink(new);
return false;
}
buf_size = ST_BLKSIZE(dstat);
buf = (char *) malloc(buf_size + sizeof(int));
while (true)
{
if ((n_read = read(sd,buf,buf_size)) == -1)
{
if (errno == EINTR)
{
continue;
}
close(sd);
close(dd);
free(buf);
return false;
}
if (n_read == 0)
{
break;
}
n_read_total += n_read;
intp = 0;
if (pp && pp->makeholes)
{
buf[n_read] = 1; /* Sentinel to stop loop. */
/* Find first non-zero *word*, or the word with the sentinel. */
intp = (int *) buf;
while (*intp++ == 0)
{
}
/* Find the first non-zero *byte*, or the sentinel. */
cp = (char *) (intp - 1);
while (*cp++ == 0)
{
}
/* If we found the sentinel, the whole input block was zero,
and we can make a hole. */
if (cp > buf + n_read)
{
/* Make a hole. */
if (lseek (dd, (off_t) n_read, SEEK_CUR) < 0L)
{
CfOut(cf_error,"lseek","Copy failed (no space?) while doing %s to %s\n",source,new);
free(buf);
unlink(new);
close(dd);
close(sd);
return false;
}
last_write_made_hole = 1;
}
else
{
/* Clear to indicate that a normal write is needed. */
intp = 0;
}
}
if (intp == 0)
{
if (cf_full_write (dd, buf, n_read) < 0)
{
CfOut(cf_error,"","Copy failed (no space?) while doing %s to %s\n",source,new);
close(sd);
close(dd);
free(buf);
unlink(new);
return false;
}
last_write_made_hole = 0;
}
}
/* If the file ends with a `hole', something needs to be written at
the end. Otherwise the kernel would truncate the file at the end
of the last write operation. */
if (last_write_made_hole)
{
/* Write a null character and truncate it again. */
if (cf_full_write (dd, "", 1) < 0 || ftruncate (dd, n_read_total) < 0)
{
CfOut(cf_error,"write","cfengine: full_write or ftruncate error in CopyReg\n");
free(buf);
unlink(new);
close(sd);
close(dd);
return false;
}
}
close(sd);
close(dd);
free(buf);
return true;
}
/*********************************************************************/
int FSWrite(char *new,int dd,char *buf,int towrite,int *last_write_made_hole,int n_read,struct Attributes attr,struct Promise *pp)
{ int *intp;
char *cp;
intp = 0;
if (pp && pp->makeholes)
{
buf[n_read] = 1; /* Sentinel to stop loop. */
/* Find first non-zero *word*, or the word with the sentinel. */
intp = (int *) buf;
while (*intp++ == 0)
{
}
/* Find the first non-zero *byte*, or the sentinel. */
cp = (char *) (intp - 1);
while (*cp++ == 0)
{
}
/* If we found the sentinel, the whole input block was zero,
and we can make a hole. */
if (cp > buf + n_read)
{
/* Make a hole. */
if (lseek (dd,(off_t)n_read,SEEK_CUR) < 0L)
{
CfOut(cf_error,"lseek","lseek in EmbeddedWrite, dest=%s\n", new);
return false;
}
*last_write_made_hole = 1;
}
else
{
/* Clear to indicate that a normal write is needed. */
intp = 0;
}
}
if (intp == 0)
{
if (cf_full_write(dd,buf,towrite) < 0)
{
CfOut(cf_error,"write","Local disk write(%.256s) failed\n",new);
pp->conn->error = true;
return false;
}
*last_write_made_hole = 0;
}
return true;
}
cfengine-3.2.4/src/transaction.c 0000644 0001750 0001750 00000046432 11715232734 013515 0000000 0000000 /*
Copyright (C) Cfengine AS
This file is part of Cfengine 3 - written and maintained by Cfengine 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 Commerical Open Source License
(COSL) may apply to this file if you as a licensee so wish it. See
included file COSL.txt.
*/
/*****************************************************************************/
/* */
/* File: transaction.c */
/* */
/*****************************************************************************/
#include "cf3.defs.h"
#include "cf3.extern.h"
static void WaitForCriticalSection(void);
static void ReleaseCriticalSection(void);
static time_t FindLock(char *last);
static int WriteLock(char *lock);
static int RemoveLock(char *name);
static void LogLockCompletion(char *cflog,int pid,char *str,char *operator,char *operand);
static time_t FindLockTime(char *name);
static pid_t FindLockPid(char *name);
static CF_DB *OpenLock(void);
static void CloseLock(CF_DB *dbp);
#if defined HAVE_PTHREAD_H && (defined HAVE_LIBPTHREAD || defined BUILDTIN_GCC_THREAD)
static pthread_mutex_t *NameToThreadMutex(enum cf_thread_mutex name);
#endif
static void RemoveDates(char *s);
/*****************************************************************************/
void SummarizeTransaction(struct Attributes attr,struct Promise *pp,char *logname)
{ FILE *fout;
if (logname && attr.transaction.log_string)
{
if (strcmp(logname,"udp_syslog") == 0)
{
RemoteSyslog(attr,pp);
}
else if (strcmp(logname,"stdout") == 0)
{
CfOut(cf_reporting,"","L: %s\n",attr.transaction.log_string);
}
else
{
if ((fout = fopen(logname,"a")) == NULL)
{
CfOut(cf_error,"","Unable to open private log %s",logname);
return;
}
CfOut(cf_verbose,""," -> Logging string \"%s\" to %s\n",attr.transaction.log_string,logname);
fprintf(fout,"%s\n",attr.transaction.log_string);
fclose(fout);
}
attr.transaction.log_string = NULL; /* To avoid repetition */
}
else if (attr.transaction.log_failed)
{
if (strcmp(logname,attr.transaction.log_failed) == 0)
{
cfPS(cf_log,CF_NOP,"",pp,attr,"%s",attr.transaction.log_string);
}
}
}
/*****************************************************************************/
struct CfLock AcquireLock(char *operand,char *host,time_t now,struct Attributes attr,struct Promise *pp, int ignoreProcesses)
{ unsigned int pid;
int i, err, sum=0;
time_t lastcompleted = 0, elapsedtime;
char *promise,cc_operator[CF_BUFSIZE],cc_operand[CF_BUFSIZE];
char cflock[CF_BUFSIZE],cflast[CF_BUFSIZE],cflog[CF_BUFSIZE];
char str_digest[CF_BUFSIZE];
struct CfLock this;
unsigned char digest[EVP_MAX_MD_SIZE+1];
this.last = (char *) CF_UNDEFINED;
this.lock = (char *) CF_UNDEFINED;
this.log = (char *) CF_UNDEFINED;
if (now == 0)
{
return this;
}
this.last = NULL;
this.lock = NULL;
this.log = NULL;
/* Indicate as done if we tried ... as we have passed all class
constraints now but we should only do this for level 0
promises. Sub routine bundles cannot be marked as done or it will
disallow iteration over bundles */
if (pp->done)
{
return this;
}
if (CF_STCKFRAME == 1)
{
*(pp->donep) = true;
/* Must not set pp->done = true for editfiles etc */
}
HashPromise(operand,pp,digest,CF_DEFAULT_DIGEST);
strcpy(str_digest,HashPrint(CF_DEFAULT_DIGEST,digest));
/* As a backup to "done" we need something immune to re-use */
if (THIS_AGENT_TYPE == cf_agent)
{
if (IsItemIn(DONELIST,str_digest))
{
CfOut(cf_verbose,""," -> This promise has already been verified");
return this;
}
PrependItem(&DONELIST,str_digest,NULL);
}
/* Finally if we're supposed to ignore locks ... do the remaining stuff */
if (IGNORELOCK)
{
this.lock = strdup("dummy");
return this;
}
promise = BodyName(pp);
snprintf(cc_operator,CF_MAXVARSIZE-1,"%s-%s",promise,host);
strncpy(cc_operand, operand, CF_BUFSIZE-1);
CanonifyNameInPlace(cc_operand);
RemoveDates(cc_operand);
free(promise);
Debug("AcquireLock(%s,%s), ExpireAfter=%d, IfElapsed=%d\n",cc_operator,cc_operand,attr.transaction.expireafter,attr.transaction.ifelapsed);
for (i = 0; cc_operator[i] != '\0'; i++)
{
sum = (CF_MACROALPHABET * sum + cc_operator[i]) % CF_HASHTABLESIZE;
}
for (i = 0; cc_operand[i] != '\0'; i++)
{
sum = (CF_MACROALPHABET * sum + cc_operand[i]) % CF_HASHTABLESIZE;
}
snprintf(cflog,CF_BUFSIZE,"%s/cf3.%.40s.runlog",CFWORKDIR,host);
snprintf(cflock,CF_BUFSIZE,"lock.%.100s.%s.%.100s_%d_%s",pp->bundle,cc_operator,cc_operand,sum,str_digest);
snprintf(cflast,CF_BUFSIZE,"last.%.100s.%s.%.100s_%d_%s",pp->bundle,cc_operator,cc_operand,sum,str_digest);
Debug("LOCK(%s)[%s]\n",pp->bundle,cflock);
// Now see if we can get exclusivity to edit the locks
CFINITSTARTTIME = time(NULL);
WaitForCriticalSection();
/* Look for non-existent (old) processes */
lastcompleted = FindLock(cflast);
elapsedtime = (time_t)(now-lastcompleted) / 60;
if (elapsedtime < 0)
{
CfOut(cf_verbose,""," XX Another cf-agent seems to have done this since I started (elapsed=%d)\n",elapsedtime);
ReleaseCriticalSection();
return this;
}
if (elapsedtime < attr.transaction.ifelapsed)
{
CfOut(cf_verbose,""," XX Nothing promised here [%.40s] (%u/%u minutes elapsed)\n",cflock,elapsedtime,attr.transaction.ifelapsed);
ReleaseCriticalSection();
return this;
}
/* Look for existing (current) processes */
if (!ignoreProcesses)
{
lastcompleted = FindLock(cflock);
elapsedtime = (time_t)(now-lastcompleted) / 60;
if (lastcompleted != 0)
{
if (elapsedtime >= attr.transaction.expireafter)
{
CfOut(cf_inform,"","Lock %s expired (after %u/%u minutes)\n",cflock,elapsedtime,attr.transaction.expireafter);
pid = FindLockPid(cflock);
if (pid == -1)
{
CfOut(cf_error,"","Illegal pid in corrupt lock %s - ignoring lock\n",cflock);
}
#ifdef MINGW // killing processes with e.g. task manager does not allow for termination handling
else if (!NovaWin_IsProcessRunning(pid))
{
CfOut(cf_verbose,"","Process with pid %d is not running - ignoring lock (Windows does not support graceful processes termination)\n",pid);
LogLockCompletion(cflog,pid,"Lock expired, process not running",cc_operator,cc_operand);
unlink(cflock);
}
#endif /* MINGW */
else
{
CfOut(cf_verbose,"","Trying to kill expired process, pid %d\n",pid);
err = GracefulTerminate(pid);
if (err || errno == ESRCH)
{
LogLockCompletion(cflog,pid,"Lock expired, process killed",cc_operator,cc_operand);
unlink(cflock);
}
else
{
ReleaseCriticalSection();
CfOut(cf_error,"kill","Unable to kill expired cfagent process %d from lock %s, exiting this time..\n",pid,cflock);
FatalError("");
}
}
}
else
{
ReleaseCriticalSection();
CfOut(cf_verbose,"","Couldn't obtain lock for %s (already running!)\n",cflock);
return this;
}
}
WriteLock(cflock);
}
ReleaseCriticalSection();
this.lock = strdup(cflock);
this.last = strdup(cflast);
this.log = strdup(cflog);
/* Keep this as a global for signal handling */
strcpy(CFLOCK,cflock);
strcpy(CFLAST,cflast);
strcpy(CFLOG,cflog);
return this;
}
/************************************************************************/
void YieldCurrentLock(struct CfLock this)
{
if (IGNORELOCK)
{
return;
}
if (this.lock == (char *)CF_UNDEFINED)
{
return;
}
Debug("Yielding lock %s\n",this.lock);
if (RemoveLock(this.lock) == -1)
{
CfOut(cf_verbose,"","Unable to remove lock %s\n",this.lock);
free(this.last);
free(this.lock);
free(this.log);
return;
}
if (WriteLock(this.last) == -1)
{
CfOut(cf_error,"creat","Unable to create %s\n",this.last);
free(this.last);
free(this.lock);
free(this.log);
return;
}
LogLockCompletion(this.log,getpid(),"Lock removed normally ",this.lock,"");
free(this.last);
free(this.lock);
free(this.log);
}
/************************************************************************/
void GetLockName(char *lockname,char *locktype,char *base,struct Rlist *params)
{ struct Rlist *rp;
int max_sample, count = 0;
for (rp = params; rp != NULL; rp=rp->next)
{
count++;
}
if (count)
{
max_sample = CF_BUFSIZE / (2*count);
}
else
{
max_sample = 0;
}
strncpy(lockname,locktype,CF_BUFSIZE/10);
strcat(lockname,"_");
strncat(lockname,base,CF_BUFSIZE/10);
strcat(lockname,"_");
for (rp = params; rp != NULL; rp=rp->next)
{
strncat(lockname,(char *)rp->item,max_sample);
}
}
/************************************************************************/
#if defined HAVE_PTHREAD_H && (defined HAVE_LIBPTHREAD || defined BUILDTIN_GCC_THREAD)
static pthread_mutex_t *NameToThreadMutex(enum cf_thread_mutex name)
{
switch(name)
{
case cft_system:
return &MUTEX_SYSCALL;
break;
case cft_count:
return &MUTEX_COUNT;
break;
case cft_getaddr:
return &MUTEX_GETADDR;
break;
case cft_lock:
return &MUTEX_LOCK;
break;
case cft_output:
return &MUTEX_OUTPUT;
break;
case cft_dbhandle:
return &MUTEX_DBHANDLE;
break;
case cft_policy:
return &MUTEX_POLICY;
break;
case cft_db_lastseen:
return &MUTEX_DB_LASTSEEN;
break;
case cft_report:
return &MUTEX_DB_REPORT;
break;
case cft_vscope:
return &MUTEX_VSCOPE;
break;
case cft_server_keyseen:
return &MUTEX_SERVER_KEYSEEN;
break;
case cft_server_children:
return &MUTEX_SERVER_CHILDREN;
break;
default:
CfOut(cf_error, "", "!! NameToThreadMutex supplied with unknown mutex name: %d", name);
FatalError("Internal software error\n");
break;
}
return NULL;
}
#endif
/************************************************************************/
int ThreadLock(enum cf_thread_mutex name)
{
#if defined HAVE_PTHREAD_H && (defined HAVE_LIBPTHREAD || defined BUILDTIN_GCC_THREAD)
pthread_mutex_t *mutex;
mutex = NameToThreadMutex(name);
if (pthread_mutex_lock(mutex) != 0)
{
// Don't use CfOut here as it also requires locking
printf("!! Could not lock: %d", name);
return false;
}
return true;
#else // NOT_HAVE_PTHREAD
return true;
#endif
}
/************************************************************************/
int ThreadUnlock(enum cf_thread_mutex name)
{
#if defined HAVE_PTHREAD_H && (defined HAVE_LIBPTHREAD || defined BUILDTIN_GCC_THREAD)
pthread_mutex_t *mutex;
mutex = NameToThreadMutex(name);
if (pthread_mutex_unlock(mutex) != 0)
{
// Don't use CfOut here as it also requires locking
printf("pthread_mutex_unlock: pthread_mutex_unlock failed");
return false;
}
return true;
#else // NOT_HAVE_PTHREAD
return true;
#endif
}
/*****************************************************************************/
void AssertThreadLocked(enum cf_thread_mutex name, char *fname)
/* Verifies that a given lock is taken (not neccessary by the current thread) */
{
#if defined HAVE_PTHREAD_H && (defined HAVE_LIBPTHREAD || defined BUILDTIN_GCC_THREAD)
pthread_mutex_t *mutex;
int status;
mutex = NameToThreadMutex(name);
status = pthread_mutex_trylock(mutex);
if (status != EBUSY && status != EDEADLK)
{
CfOut(cf_error, "", "!! The mutex %d was not locked in %s() -- status=%d", name, fname, status);
FatalError("Software assertion failure\n");
}
#endif
}
/*****************************************************************************/
/* Level */
/*****************************************************************************/
static time_t FindLock(char *last)
{ time_t mtime;
if ((mtime = FindLockTime(last)) == -1)
{
/* Do this to prevent deadlock loops from surviving if IfElapsed > T_sched */
if (WriteLock(last) == -1)
{
CfOut(cf_error,"","Unable to lock %s\n",last);
return 0;
}
return 0;
}
else
{
return mtime;
}
}
/************************************************************************/
static int WriteLock(char *name)
{ CF_DB *dbp;
struct LockData entry;
Debug("WriteLock(%s)\n",name);
ThreadLock(cft_lock);
if ((dbp = OpenLock()) == NULL)
{
ThreadUnlock(cft_lock);
return -1;
}
entry.pid = getpid();
entry.time = time((time_t *)NULL);
WriteDB(dbp,name,&entry,sizeof(entry));
CloseLock(dbp);
ThreadUnlock(cft_lock);
return 0;
}
/*****************************************************************************/
static void LogLockCompletion(char *cflog,int pid,char *str,char *operator,char *operand)
{ FILE *fp;
char buffer[CF_MAXVARSIZE];
struct stat statbuf;
time_t tim;
Debug("LockLogCompletion(%s)\n",str);
if (cflog == NULL)
{
return;
}
if ((fp = fopen(cflog,"a")) == NULL)
{
CfOut(cf_error,"fopen","Can't open lock-log file %s\n",cflog);
exit(1);
}
if ((tim = time((time_t *)NULL)) == -1)
{
Debug("Cfengine: couldn't read system clock\n");
}
sprintf(buffer,"%s",cf_ctime(&tim));
Chop(buffer);
fprintf(fp,"%s:%s:pid=%d:%s:%s\n",buffer,str,pid,operator,operand);
fclose(fp);
if (cfstat(cflog,&statbuf) != -1)
{
if (statbuf.st_size > CFLOGSIZE)
{
CfOut(cf_verbose,"","Rotating lock-runlog file\n");
RotateFiles(cflog,2);
}
}
}
/*****************************************************************************/
int RemoveLock(char *name)
{ CF_DB *dbp;
if ((dbp = OpenLock()) == NULL)
{
return -1;
}
ThreadLock(cft_lock);
DeleteDB(dbp,name);
ThreadUnlock(cft_lock);
CloseLock(dbp);
return 0;
}
/************************************************************************/
static time_t FindLockTime(char *name)
{ CF_DB *dbp;
struct LockData entry;
Debug("FindLockTime(%s)\n",name);
if ((dbp = OpenLock()) == NULL)
{
return -1;
}
if (ReadDB(dbp,name,&entry,sizeof(entry)))
{
CloseLock(dbp);
return entry.time;
}
else
{
CloseLock(dbp);
return -1;
}
}
/************************************************************************/
static pid_t FindLockPid(char *name)
{ CF_DB *dbp;
struct LockData entry;
if ((dbp = OpenLock()) == NULL)
{
return -1;
}
if (ReadDB(dbp,name,&entry,sizeof(entry)))
{
CloseLock(dbp);
return entry.pid;
}
else
{
CloseLock(dbp);
return -1;
}
}
/************************************************************************/
static CF_DB *OpenLock()
{ char name[CF_BUFSIZE];
CF_DB *dbp;
snprintf(name,CF_BUFSIZE,"%s/state/%s",CFWORKDIR, CF_LOCKDB_FILE);
MapName(name);
if (!OpenDB(name,&dbp))
{
return NULL;
}
Debug("OpenLock(%s)\n",name);
return dbp;
}
/************************************************************************/
static void CloseLock(CF_DB *dbp)
{
if (dbp)
{
CloseDB(dbp);
}
}
/*****************************************************************************/
static void RemoveDates(char *s)
{ int i,a = 0,b = 0,c = 0,d = 0;
char *dayp = NULL, *monthp = NULL, *sp;
char *days[7] = { "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun" };
char *months[12] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
// Canonifies or blanks our times/dates for locks where there would be an explosion of state
if (strlen(s) < strlen("Fri Oct 1 15:15:23 EST 2010"))
{
// Probably not a full date
return;
}
for (i = 0; i < 7; i++)
{
if ((dayp = strstr(s,days[i])))
{
*dayp = 'D';
*(dayp+1) = 'A';
*(dayp+2) = 'Y';
break;
}
}
for (i = 0; i < 12; i++)
{
if ((monthp = strstr(s,months[i])))
{
*monthp = 'M';
*(monthp+1) = 'O';
*(monthp+2) = 'N';
break;
}
}
if (dayp && monthp) // looks like a full date
{
sscanf(monthp+4,"%d %d:%d:%d",&a,&b,&c,&d);
if (a*b*c*d == 0)
{
// Probably not a date
return;
}
for (sp = monthp+4; *sp != '\0'; sp++)
{
if (sp > monthp+15)
{
break;
}
if (isdigit(*sp))
{
*sp = 't';
}
}
}
}
/************************************************************************/
void PurgeLocks()
{ CF_DB *dbp = OpenLock();
CF_DBC *dbcp;
char *key;
int ksize,vsize;
struct LockData entry;
time_t now = time(NULL);
memset(&entry, 0, sizeof(entry));
if (ReadDB(dbp,"lock_horizon",&entry,sizeof(entry)))
{
if (now - entry.time < CF_MONTH)
{
CfOut(cf_verbose,""," -> No lock purging scheduled");
CloseLock(dbp);
return;
}
}
CfOut(cf_verbose,""," -> Looking for stale locks to purge");
if (!NewDBCursor(dbp,&dbcp))
{
CloseLock(dbp);
return;
}
while(NextDB(dbp,dbcp,&key,&ksize,(void *)&entry,&vsize))
{
if (strncmp(key,"last.internal_bundle.track_license.handle",
strlen("last.internal_bundle.track_license.handle")) == 0)
{
continue;
}
if (now - entry.time > (time_t)CF_LOCKHORIZON)
{
CfOut(cf_verbose,""," --> Purging lock (%d) %s",now-entry.time,key);
DeleteDB(dbp,key);
}
}
entry.time = now;
WriteDB(dbp,"lock_horizon",&entry,sizeof(entry));
DeleteDBCursor(dbp,dbcp);
CloseLock(dbp);
}
/************************************************************************/
/* Release critical section */
/************************************************************************/
static void WaitForCriticalSection()
{ time_t now = time(NULL), then = FindLockTime("CF_CRITICAL_SECTION");
/* Another agent has been waiting more than a minute, it means there
is likely crash detritus to clear up... After a minute we take our
chances ... */
while ((then != -1) && (now - then < 60))
{
sleep(1);
then = FindLockTime("CF_CRITICAL_SECTION");
}
WriteLock("CF_CRITICAL_SECTION");
}
/************************************************************************/
static void ReleaseCriticalSection()
{
RemoveLock("CF_CRITICAL_SECTION");
}
/************************************************************************/
int ShiftChange(void)
{
if (IsDefinedClass("(Hr00|Hr06|Hr12|Hr16|Hr18).Min00_05"))
{
return true;
}
else
{
return false;
}
}
cfengine-3.2.4/src/cf.defs.h 0000644 0001750 0001750 00000103550 11715232734 012500 0000000 0000000 /*
Copyright (C) Cfengine AS
This file is part of Cfengine 3 - written and maintained by Cfengine 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 Commerical Open Source License
(COSL) may apply to this file if you as a licensee so wish it. See
included file COSL.txt.
*/
/*******************************************************************/
/* */
/* HEAER for cfengine */
/* */
/*******************************************************************/
#ifndef CFENGINE_CF_DEFS_H
#define CFENGINE_CF_DEFS_H
/* Hard link this file between cf2/cf3 for consistent update */
#include "conf.h"
#ifdef NT
# define MAX_FILENAME 227
# define WINVER 0x501
# define FD_SETSIZE 512 // increase select(2) FD limit from 64
#else
# define MAX_FILENAME 254
#endif
#ifdef MINGW
# include
# include
# include
# include
# include
# include
# include
# include
# include
# include
# include // for disphelper
#endif
#include
#include
#ifndef _GETOPT_H
#include "../pub/getopt.h"
#endif
#ifdef HAVE_STDLIB_H
#include
#endif
#include
#include
#include
#include
#ifdef HAVE_UNAME
#include
#else
#define _SYS_NMLN 257
struct utsname
{
char sysname[_SYS_NMLN];
char nodename[_SYS_NMLN];
char release[_SYS_NMLN];
char version[_SYS_NMLN];
char machine[_SYS_NMLN];
};
#endif
#include
#include
#ifdef HAVE_STDINT_H
# include
#endif
#ifdef HAVE_SYS_SYSTEMINFO_H
# include
#endif
#ifdef HAVE_SYS_PARAM_H
# include
#endif
#ifdef HAVE_SYS_MOUNT_H
#include
#endif
#ifdef HAVE_SYS_WAIT_H
# include
#endif
#ifndef WEXITSTATUS
# define WEXITSTATUS(s) ((unsigned)(s) >> 8)
#endif
#ifndef WIFEXITED
# define WIFEXITED(s) (((s) & 255) == 0)
#endif
#ifndef WIFSIGNALED
# define WIFSIGNALED(s) ((s) & 0) /* Can't use for BSD */
#endif
#ifndef WTERMSIG
#define WTERMSIG(s) ((s) & 0)
#endif
#include "bool.h"
#include "compiler.h"
#include
#include
#include
#include
#include
#include
#include
#ifdef HAVE_DIRENT_H
# include
#else
# define dirent direct
# if HAVE_SYS_NDIR_H
# include
# endif
# if HAVE_SYS_DIR_H
# include
# endif
# if HAVE_NDIR_H
# include
# endif
#endif
#include
#ifdef MINGW
#define LOG_LOCAL0 (16<<3)
#define LOG_LOCAL1 (17<<3)
#define LOG_LOCAL2 (18<<3)
#define LOG_LOCAL3 (19<<3)
#define LOG_LOCAL4 (20<<3)
#define LOG_LOCAL5 (21<<3)
#define LOG_LOCAL6 (22<<3)
#define LOG_LOCAL7 (23<<3)
#define LOG_USER (1<<3)
#define LOG_DAEMON (3<<3)
#else /* NOT MINGW */
#include
extern int errno;
#endif
/* Do this for ease of configuration from the Makefile */
#ifdef HPuUX
#define HPUX
#endif
#ifdef SunOS
#define SUN4
#endif
/* end of patch */
#ifdef AIX
#ifndef ps2
#include
#endif
#include
#endif
#ifdef SOLARIS
#include
#undef nfstype
#endif
#ifndef HAVE_BCOPY
#define bcopy(fr,to,n) memcpy(to,fr,n) /* Eliminate ucblib */
#define bcmp(s1, s2, n) memcmp ((s1), (s2), (n))
#define bzero(s, n) memset ((s), 0, (n))
#endif
#if !HAVE_DECL_STRNDUP
char *strndup(const char *s, size_t n);
#endif
#ifdef HAVE_UNISTD_H
#include
#endif
#if !HAVE_DECL_STRLCPY
size_t strlcpy(char *destination, const char *source, size_t size);
#endif
#if !HAVE_DECL_STRLCAT
size_t strlcat(char *destination, const char *source, size_t size);
#endif
#ifdef DARWIN
#include
#include
#endif
#ifdef HAVE_SYS_MALLOC_H
#ifdef DARWIN
#include
#include
#endif
#else
#ifdef HAVE_MALLOC_H
#ifndef OPENBSD
#ifdef __FreeBSD__
#include
#else
#include
#endif
#endif
#endif
#endif
#include
#ifdef HAVE_VFS_H
# include
#endif
#ifdef HPUX
# include
#endif
#ifdef HAVE_UTIME_H
# include /* use utime not utimes for portability */
#elif TIME_WITH_SYS_TIME
# include
# include
#elif HAVE_SYS_TIME_H
# include
#elif ! defined(AOS)
# include
#endif
#define _GNU_SOURCE
#ifdef HAVE_TIME_H
# include
#endif
#ifdef HAVE_SYS_TIME_H
# include
#endif
#ifndef MINGW
#include
#include
#endif
#ifdef HAVE_SYS_SOCKIO_H
# include
#endif
#ifndef MINGW
# include
# include
# include
# include
# ifndef AOS
# include
# endif
# include
# if !defined LINUX && !defined NT
# include
# undef sgi
# include
# endif
#endif
#ifdef LINUX
#ifdef __GLIBC__
# include
# include
#else
# include
# include