pax_global_header 0000666 0000000 0000000 00000000064 13237071060 0014511 g ustar 00root root 0000000 0000000 52 comment=f25b16afb6ac761fea13132ff406fba4cdfd2b76
openscap-daemon-0.1.10/ 0000775 0000000 0000000 00000000000 13237071060 0014641 5 ustar 00root root 0000000 0000000 openscap-daemon-0.1.10/.gitignore 0000664 0000000 0000000 00000001530 13237071060 0016630 0 ustar 00root root 0000000 0000000 # Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
# C extensions
*.so
# Distribution / packaging
.Python
env/
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
*.egg-info/
.installed.cfg
*.egg
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
MANIFEST
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*,cover
# Translations
*.mo
*.pot
# Django stuff:
*.log
# Sphinx documentation
docs/_build/
# PyBuilder
target/
# vim rope
.ropeproject/
# IntelliJ IDEA
.idea/
/static-analysis-output
/tests/data_dir_template/cve_feeds/
/tests/data_dir_template/results/
openscap-daemon-0.1.10/DESIGN_NOTES.md 0000664 0000000 0000000 00000003527 13237071060 0017113 0 ustar 00root root 0000000 0000000 # Design Notes
## Puzzle Pieces
### Task
* target
* host
* VM $URL
* container / image $ID
* input content
* tailoring
* profile id, datastream id, ...
* HTML guide can be always generated
### Task Result
* ARF always
* HTML report can be always generated
## CLI use-cases
```
$ oscapd-cli task list
Active tasks:
ID | Title | Next run | Repeats |
-------------------------------------------------------------------------
2 | Weekly USGCB evaluation | 2015-04-10 01:00 (in 8 hours) | @weekly |
3 | Daily STIG evaluation | 2015-03-09 23:00 (in 6 hours) | @daily |
4 | One-off evaluation | 2015-03-09 23:30 (in 6 hours) | - |
Inactive tasks:
ID | Title
------------------------------------------------------------------------
1 | Testing evaluation
```
```
$ oscapd-cli task 2
ID: 2
Title: Weekly USGCB evaluation
Target: localhost
Input file: /usr/share/xml/scap/ssg/content/ssg-rhel6-ds.xml
Tailoring: N/A
Profile ID: xccdf_org.ssgproject.content_profile_usgcb-rhel6-server
Next run: 2015-04-10 01:00 (in 8 hours)
Repeats: @weekly = 168 hours
Time slip: no_slip
ARF upload: disabled
One-off: false
Results:
ID | Timestamp
----------------------
23 | 2015-04-03 01:13
14 | 2015-03-27 01:11
11 | 2015-03-20 01:15
````
```
$ oscapd-cli result 23
ID: 23
Task ID: 2
Timestamp: 2015-04-03
ARF path: /var/lib/oscapd-cli/results/23/results-arf.xml
```
```
$ oscapd-cli result 23 report > report.html
```
```
$ oscapd-cli result 23 arf > arf.xml
```
```
# generate report of last result from task 2
$ oscapd-cli result 2/last report
```
```
$ oscapd-cli task 2 disable
$ oscapd-cli task 2 enable
```
```
# manually update oscapd-cli, for debugging purposes
$ oscapd-cli update
Found 4 tasks in total, 3 enabled tasks.
````
openscap-daemon-0.1.10/LICENSE 0000664 0000000 0000000 00000063536 13237071060 0015663 0 ustar 00root root 0000000 0000000 GNU LESSER GENERAL PUBLIC LICENSE
Version 2.1, February 1999
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
(This is the first released version of the Lesser GPL. It also counts
as the successor of the GNU Library Public License, version 2, hence
the version number 2.1.)
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
Licenses are intended to guarantee your freedom to share and change
free software--to make sure the software is free for all its users.
This license, the Lesser General Public License, applies to some
specially designated software packages--typically libraries--of the
Free Software Foundation and other authors who decide to use it. You
can use it too, but we suggest you first think carefully about whether
this license or the ordinary General Public License is the better
strategy to use in any particular case, based on the explanations below.
When we speak of free software, we are referring to freedom of use,
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 this service if you wish); that you receive source code or can get
it if you want it; that you can change the software and use pieces of
it in new free programs; and that you are informed that you can do
these things.
To protect your rights, we need to make restrictions that forbid
distributors to deny you these rights or to ask you to surrender these
rights. These restrictions translate to certain responsibilities for
you if you distribute copies of the library or if you modify it.
For example, if you distribute copies of the library, whether gratis
or for a fee, you must give the recipients all the rights that we gave
you. You must make sure that they, too, receive or can get the source
code. If you link other code with the library, you must provide
complete object files to the recipients, so that they can relink them
with the library after making changes to the library and recompiling
it. And you must show them these terms so they know their rights.
We protect your rights with a two-step method: (1) we copyright the
library, and (2) we offer you this license, which gives you legal
permission to copy, distribute and/or modify the library.
To protect each distributor, we want to make it very clear that
there is no warranty for the free library. Also, if the library is
modified by someone else and passed on, the recipients should know
that what they have is not the original version, so that the original
author's reputation will not be affected by problems that might be
introduced by others.
Finally, software patents pose a constant threat to the existence of
any free program. We wish to make sure that a company cannot
effectively restrict the users of a free program by obtaining a
restrictive license from a patent holder. Therefore, we insist that
any patent license obtained for a version of the library must be
consistent with the full freedom of use specified in this license.
Most GNU software, including some libraries, is covered by the
ordinary GNU General Public License. This license, the GNU Lesser
General Public License, applies to certain designated libraries, and
is quite different from the ordinary General Public License. We use
this license for certain libraries in order to permit linking those
libraries into non-free programs.
When a program is linked with a library, whether statically or using
a shared library, the combination of the two is legally speaking a
combined work, a derivative of the original library. The ordinary
General Public License therefore permits such linking only if the
entire combination fits its criteria of freedom. The Lesser General
Public License permits more lax criteria for linking other code with
the library.
We call this license the "Lesser" General Public License because it
does Less to protect the user's freedom than the ordinary General
Public License. It also provides other free software developers Less
of an advantage over competing non-free programs. These disadvantages
are the reason we use the ordinary General Public License for many
libraries. However, the Lesser license provides advantages in certain
special circumstances.
For example, on rare occasions, there may be a special need to
encourage the widest possible use of a certain library, so that it becomes
a de-facto standard. To achieve this, non-free programs must be
allowed to use the library. A more frequent case is that a free
library does the same job as widely used non-free libraries. In this
case, there is little to gain by limiting the free library to free
software only, so we use the Lesser General Public License.
In other cases, permission to use a particular library in non-free
programs enables a greater number of people to use a large body of
free software. For example, permission to use the GNU C Library in
non-free programs enables many more people to use the whole GNU
operating system, as well as its variant, the GNU/Linux operating
system.
Although the Lesser General Public License is Less protective of the
users' freedom, it does ensure that the user of a program that is
linked with the Library has the freedom and the wherewithal to run
that program using a modified version of the Library.
The precise terms and conditions for copying, distribution and
modification follow. Pay close attention to the difference between a
"work based on the library" and a "work that uses the library". The
former contains code derived from the library, whereas the latter must
be combined with the library in order to run.
GNU LESSER GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License Agreement applies to any software library or other
program which contains a notice placed by the copyright holder or
other authorized party saying it may be distributed under the terms of
this Lesser General Public License (also called "this License").
Each licensee is addressed as "you".
A "library" means a collection of software functions and/or data
prepared so as to be conveniently linked with application programs
(which use some of those functions and data) to form executables.
The "Library", below, refers to any such software library or work
which has been distributed under these terms. A "work based on the
Library" means either the Library or any derivative work under
copyright law: that is to say, a work containing the Library or a
portion of it, either verbatim or with modifications and/or translated
straightforwardly into another language. (Hereinafter, translation is
included without limitation in the term "modification".)
"Source code" for a work means the preferred form of the work for
making modifications to it. For a library, complete source code means
all the source code for all modules it contains, plus any associated
interface definition files, plus the scripts used to control compilation
and installation of the library.
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running a program using the Library is not restricted, and output from
such a program is covered only if its contents constitute a work based
on the Library (independent of the use of the Library in a tool for
writing it). Whether that is true depends on what the Library does
and what the program that uses the Library does.
1. You may copy and distribute verbatim copies of the Library's
complete source code as you receive it, in any medium, provided that
you conspicuously and appropriately publish on each copy an
appropriate copyright notice and disclaimer of warranty; keep intact
all the notices that refer to this License and to the absence of any
warranty; and distribute a copy of this License along with the
Library.
You may charge a fee for the physical act of transferring a copy,
and you may at your option offer warranty protection in exchange for a
fee.
2. You may modify your copy or copies of the Library or any portion
of it, thus forming a work based on the Library, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) The modified work must itself be a software library.
b) You must cause the files modified to carry prominent notices
stating that you changed the files and the date of any change.
c) You must cause the whole of the work to be licensed at no
charge to all third parties under the terms of this License.
d) If a facility in the modified Library refers to a function or a
table of data to be supplied by an application program that uses
the facility, other than as an argument passed when the facility
is invoked, then you must make a good faith effort to ensure that,
in the event an application does not supply such function or
table, the facility still operates, and performs whatever part of
its purpose remains meaningful.
(For example, a function in a library to compute square roots has
a purpose that is entirely well-defined independent of the
application. Therefore, Subsection 2d requires that any
application-supplied function or table used by this function must
be optional: if the application does not supply it, the square
root function must still compute square roots.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Library,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Library, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote
it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Library.
In addition, mere aggregation of another work not based on the Library
with the Library (or with a work based on the Library) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may opt to apply the terms of the ordinary GNU General Public
License instead of this License to a given copy of the Library. To do
this, you must alter all the notices that refer to this License, so
that they refer to the ordinary GNU General Public License, version 2,
instead of to this License. (If a newer version than version 2 of the
ordinary GNU General Public License has appeared, then you can specify
that version instead if you wish.) Do not make any other change in
these notices.
Once this change is made in a given copy, it is irreversible for
that copy, so the ordinary GNU General Public License applies to all
subsequent copies and derivative works made from that copy.
This option is useful when you wish to copy part of the code of
the Library into a program that is not a library.
4. You may copy and distribute the Library (or a portion or
derivative of it, under Section 2) in object code or executable form
under the terms of Sections 1 and 2 above provided that you accompany
it with the complete corresponding machine-readable source code, which
must be distributed under the terms of Sections 1 and 2 above on a
medium customarily used for software interchange.
If distribution of object code is made by offering access to copy
from a designated place, then offering equivalent access to copy the
source code from the same place satisfies the requirement to
distribute the source code, even though third parties are not
compelled to copy the source along with the object code.
5. A program that contains no derivative of any portion of the
Library, but is designed to work with the Library by being compiled or
linked with it, is called a "work that uses the Library". Such a
work, in isolation, is not a derivative work of the Library, and
therefore falls outside the scope of this License.
However, linking a "work that uses the Library" with the Library
creates an executable that is a derivative of the Library (because it
contains portions of the Library), rather than a "work that uses the
library". The executable is therefore covered by this License.
Section 6 states terms for distribution of such executables.
When a "work that uses the Library" uses material from a header file
that is part of the Library, the object code for the work may be a
derivative work of the Library even though the source code is not.
Whether this is true is especially significant if the work can be
linked without the Library, or if the work is itself a library. The
threshold for this to be true is not precisely defined by law.
If such an object file uses only numerical parameters, data
structure layouts and accessors, and small macros and small inline
functions (ten lines or less in length), then the use of the object
file is unrestricted, regardless of whether it is legally a derivative
work. (Executables containing this object code plus portions of the
Library will still fall under Section 6.)
Otherwise, if the work is a derivative of the Library, you may
distribute the object code for the work under the terms of Section 6.
Any executables containing that work also fall under Section 6,
whether or not they are linked directly with the Library itself.
6. As an exception to the Sections above, you may also combine or
link a "work that uses the Library" with the Library to produce a
work containing portions of the Library, and distribute that work
under terms of your choice, provided that the terms permit
modification of the work for the customer's own use and reverse
engineering for debugging such modifications.
You must give prominent notice with each copy of the work that the
Library is used in it and that the Library and its use are covered by
this License. You must supply a copy of this License. If the work
during execution displays copyright notices, you must include the
copyright notice for the Library among them, as well as a reference
directing the user to the copy of this License. Also, you must do one
of these things:
a) Accompany the work with the complete corresponding
machine-readable source code for the Library including whatever
changes were used in the work (which must be distributed under
Sections 1 and 2 above); and, if the work is an executable linked
with the Library, with the complete machine-readable "work that
uses the Library", as object code and/or source code, so that the
user can modify the Library and then relink to produce a modified
executable containing the modified Library. (It is understood
that the user who changes the contents of definitions files in the
Library will not necessarily be able to recompile the application
to use the modified definitions.)
b) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (1) uses at run time a
copy of the library already present on the user's computer system,
rather than copying library functions into the executable, and (2)
will operate properly with a modified version of the library, if
the user installs one, as long as the modified version is
interface-compatible with the version that the work was made with.
c) Accompany the work with a written offer, valid for at
least three years, to give the same user the materials
specified in Subsection 6a, above, for a charge no more
than the cost of performing this distribution.
d) If distribution of the work is made by offering access to copy
from a designated place, offer equivalent access to copy the above
specified materials from the same place.
e) Verify that the user has already received a copy of these
materials or that you have already sent this user a copy.
For an executable, the required form of the "work that uses the
Library" must include any data and utility programs needed for
reproducing the executable from it. However, as a special exception,
the materials to be distributed need not include anything that is
normally distributed (in either source or binary form) with the major
components (compiler, kernel, and so on) of the operating system on
which the executable runs, unless that component itself accompanies
the executable.
It may happen that this requirement contradicts the license
restrictions of other proprietary libraries that do not normally
accompany the operating system. Such a contradiction means you cannot
use both them and the Library together in an executable that you
distribute.
7. You may place library facilities that are a work based on the
Library side-by-side in a single library together with other library
facilities not covered by this License, and distribute such a combined
library, provided that the separate distribution of the work based on
the Library and of the other library facilities is otherwise
permitted, and provided that you do these two things:
a) Accompany the combined library with a copy of the same work
based on the Library, uncombined with any other library
facilities. This must be distributed under the terms of the
Sections above.
b) Give prominent notice with the combined library of the fact
that part of it is a work based on the Library, and explaining
where to find the accompanying uncombined form of the same work.
8. You may not copy, modify, sublicense, link with, or distribute
the Library except as expressly provided under this License. Any
attempt otherwise to copy, modify, sublicense, link with, or
distribute the Library is void, and will automatically terminate your
rights under this License. However, parties who have received copies,
or rights, from you under this License will not have their licenses
terminated so long as such parties remain in full compliance.
9. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Library or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Library (or any work based on the
Library), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Library or works based on it.
10. Each time you redistribute the Library (or any work based on the
Library), the recipient automatically receives a license from the
original licensor to copy, distribute, link with or modify the Library
subject to these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties with
this License.
11. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
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
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Library at all. For example, if a patent
license would not permit royalty-free redistribution of the Library by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Library.
If any portion of this section is held invalid or unenforceable under any
particular circumstance, the balance of the section is intended to apply,
and the section as a whole is intended to apply in other circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
12. If the distribution and/or use of the Library is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Library under this License may add
an explicit geographical distribution limitation excluding those countries,
so that distribution is permitted only in or among countries not thus
excluded. In such case, this License incorporates the limitation as if
written in the body of this License.
13. The Free Software Foundation may publish revised and/or new
versions of the Lesser General Public License from time to time.
Such new versions will be similar in spirit to the present version,
but may differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the Library
specifies a version number of this License which applies to it and
"any later version", you have the option of following the terms and
conditions either of that version or of any later version published by
the Free Software Foundation. If the Library does not specify a
license version number, you may choose any version ever published by
the Free Software Foundation.
14. If you wish to incorporate parts of the Library into other free
programs whose distribution conditions are incompatible with these,
write to the author to ask for permission. For software which is
copyrighted by the Free Software Foundation, write to the Free
Software Foundation; we sometimes make exceptions for this. Our
decision will be guided by the two goals of preserving the free status
of all derivatives of our free software and of promoting the sharing
and reuse of software generally.
NO WARRANTY
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
OTHER PARTIES PROVIDE THE LIBRARY "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
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
AND/OR REDISTRIBUTE THE LIBRARY 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
LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Libraries
If you develop a new library, and you want it to be of the greatest
possible use to the public, we recommend making it free software that
everyone can redistribute and change. You can do so by permitting
redistribution under these terms (or, alternatively, under the terms of the
ordinary General Public License).
To apply these terms, attach the following notices to the library. It is
safest to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least the
"copyright" line and a pointer to where the full notice is found.
{description}
Copyright (C) {year} {fullname}
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
USA
Also add information on how to contact you by electronic and paper mail.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the library, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the
library `Frob' (a library for tweaking knobs) written by James Random
Hacker.
{signature of Ty Coon}, 1 April 1990
Ty Coon, President of Vice
That's all there is to it!
openscap-daemon-0.1.10/README.md 0000664 0000000 0000000 00000026154 13237071060 0016130 0 ustar 00root root 0000000 0000000 # OpenSCAP-daemon
> Continuously evaluate your infrastructure for *SCAP* compliance!
> Avoid copying big SCAP files around, avoid having to type long IDs, avoid
> writing ad-hoc bash scripts to solve your compliance needs!
## Project Description
OpenSCAP-daemon is a service that performs SCAP scans of bare-metal machines,
virtual machines and containers. These scans can be either one-shot or
continuous according to a schedule. You can interact with the service
using the provided oscapd-cli tool or via the DBus interface.
## Motivation
The [OpenSCAP](http://open-scap.org) project has progressed greatly over the
past years and now provides very nice tooling to perform solicited one-off
*SCAP* evaluation of the machine it runs on. Unsolicited, continuous or
planned evaluation has always been out of scope of *OpenSCAP* to avoid feature
creep. The previously mentioned use-case is very desirable and has been
requested many times. We feel that now the time is right to start a project
that **helps you run oscap** and **does evaluation for you**. *OpenSCAP-daemon*
is such a project.
The project currently comprises of two parts, the **daemon** that runs in the
background sleeping until a task needs processing, and the **command-line tool**
that talks to the aforementioned daemon using *dbus*. Do not be alarmed, the
**command-line tool** is much easier to use than pure `oscap` for common
use-cases.
## Features
* *SCAP* evaluation of the following assets using
[OpenSCAP](http://open-scap.org) -- a **NIST-certified** scanner
* **local machine** -- `oscap`
* **remote machine** -- `oscap-ssh`
* **virtual machine** -- `oscap-vm`
* **container** -- `oscap-docker`
* flexible task definition and planning
* use any valid *SCAP* content -- for example
[SCAP Security Guide](http://github.com/OpenSCAP/scap-security-guide),
[NIST USGCB](http://usgcb.nist.gov/), or even
[RHSA OVAL](https://www.redhat.com/security/data/oval/)
* evaluate *daily*, *weekly*, *monthly* or in custom intervals
* evaluate on demand
* parallel task processing
* results storage -- query ARFs of past results, generate HTML reports, get
`oscap` stdout/stderr and exit codes
* command-line interface
* *dbus* *API*
* fully automated CVE evaluation of containers using OpenSCAP and Atomic.mount
* *Cockpit* integration (planned)
## Key Goals & Design Decisions
We have learned many important lessons when developing the lower layers of the
*SCAP* evaluation stack that we want to address in this project.
- **useful defaults** -- just pressing *Enter* and not providing any details
should still yield a valid setup
- **simplicity** -- we avoid *RDBMS* and instead use features of the filesystem
- **datastreams** -- *SDS* (source datastream) and *ARF* (results datastream)
are both used as primary data formats for maximum compatibility between
various tools
- **interactive CLI** -- the CLI should be as interactive as possible, user
shouldn't need to type any IDs or other lengthy options
## Example Use-Cases
### Scan a container or container image on Atomic Host
Atomic host can use the functionality in OpenSCAP-Daemon to perform vulnerability
scans of containers and container images using the `atomic scan` command.
To use this functionality, install atomic. Then install openscap-daemon either
in standalone mode or as a SPC container image. When the daemon is running
the `atomic scan` functionality is available.
### Scan all containers or all contaner images on Atomic Host
The `atomic scan` command has command-line arguments --images, --containers and
--all that scan all images, all container and everything respectively.
### Scan local machine every day at 1:00 AM UTC
OpenSCAP-daemon thinks in terms of tasks. Let us first define the task we want
to perform:
```bash
# interactively create a new task
oscapd-cli task-create -i
Creating new task in interactive mode
Title: Daily USGCB
Target (empty for localhost):
Found the following SCAP Security Guide content:
1: /usr/share/xml/scap/ssg/content/ssg-fedora-ds.xml
2: /usr/share/xml/scap/ssg/content/ssg-firefox-ds.xml
3: /usr/share/xml/scap/ssg/content/ssg-java-ds.xml
4: /usr/share/xml/scap/ssg/content/ssg-rhel6-ds.xml
5: /usr/share/xml/scap/ssg/content/ssg-rhel7-ds.xml
Choose SSG content by number (empty for custom content): 4
Tailoring file (absolute path, empty for no tailoring):
Found the following possible profiles:
1: CSCF RHEL6 MLS Core Baseline (id='xccdf_org.ssgproject.content_profile_CSCF-RHEL6-MLS')
2: United States Government Configuration Baseline (USGCB) (id='xccdf_org.ssgproject.content_profile_usgcb-rhel6-server')
3: Common Profile for General-Purpose Systems (id='xccdf_org.ssgproject.content_profile_common')
4: PCI-DSS v3 Control Baseline for Red Hat Enterprise Linux 6 (id='xccdf_org.ssgproject.content_profile_pci-dss')
5: Example Server Profile (id='xccdf_org.ssgproject.content_profile_CS2')
6: C2S for Red Hat Enterprise Linux 6 (id='xccdf_org.ssgproject.content_profile_C2S')
7: Common Profile for General-Purpose SystemsUpstream STIG for RHEL 6 Server (id='xccdf_org.ssgproject.content_profile_stig-rhel6-server-upstream')
8: Common Profile for General-Purpose SystemsServer Baseline (id='xccdf_org.ssgproject.content_profile_server')
9: Red Hat Corporate Profile for Certified Cloud Providers (RH CCP) (id='xccdf_org.ssgproject.content_profile_rht-ccp')
Choose profile by number (empty for (default) profile): 2
Online remediation (1, y or Y for yes, else no):
Schedule:
- not before (YYYY-MM-DD HH:MM in UTC, empty for NOW): 2014-07-30 01:00
- repeat after (hours or @daily, @weekly, @monthly, empty or 0 for no repeat): @daily
Task created with ID '1'. It is currently set as disabled. You can enable it with `oscapd-cli task 1 enable`.
```
As the command-line interface suggests, we need to enable the task.
```bash
# enable previously created task of given ID
oscapd-cli task 1 enable
```
We may also want to see the HTML guide of our specified task to confirm it will do what we need.
```bash
# get the HTML guide of task of ID 1
oscapd-cli task 1 guide > guide.html
# open the guide in firefox
firefox guide.html
```
At this point `oscapd` will evaluate the local machine at `1:00 AM UTC` every
day and store all the results. To finish this use-case, lets see how we can
query the results after a week of evaluations.
```bash
# list all available results of task 1
$ oscapd-cli result 1
7
6
5
4
3
2
1
# get the verbatim results ARF of the 4th result of task 1
oscapd-cli result 1 4 arf > exported-arf.xml
# get the HTML report of previously mentioned result
oscapd-cli result 1 4 report > report.html
# open the report in firefox
firefox report.html
```
### Solicited evaluation
Sometimes we may want to run the evaluation outside the schedule for testing
or other purposes. The task may even be scheduled to never run automatically!
Such tasks are sometimes necessary.
```bash
# run task of ID 1 immediately
oscapd-cli task 1 run
# query available results
oscapd-cli result 1
8
7
6
# [snip]
# fetch ARF of result 8 of task 1
oscapd-cli result 1 8 arf > exported-arf.xml
```
### Evaluate something else than local machine
Every task has a *target* attribute that can take various forms:
* localhost -- scan the local machine, the same machine the daemon runs on
* ssh://auditor@192.168.0.22 -- scan remote machine of given IP with given username
* make sure you can log onto the same machine non-interactively!
* ssh+sudo://auditor@192.168.0.22 -- scan remote machine of given IP with given username with sudo privileges
* sudo mustn't require tty
* vm://qemu+kvm://localhost/VM1 -- virtual machine -- work in progress, subject to change
* docker://container_id -- local container -- work in progress, subject to change
The rest of the use-case is similar to previously mentioned use-cases. It is
important to remark that the *SCAP* content only needs to be available on the
local machine -- the machine that runs *OpenSCAP-daemon*. It is not necessary
to perform any extra manual action to get the content to the scanned machines,
this is done automatically.
### Scan all images in my registry to make sure no vulnerable images are published
When maintaining a registry it makes sense to unpublish images that have known
vulnerabilities to prevent people from using them.
We need to react to the CVE feeds changing and re-scan the images and of course
we need to scan all new images incoming into the registry.
This is a future use-case that hasn't been fully implemented yet.
## Requirements
* [*python2*](http://python.org) >= 2.6 OR [*python3*](http://python.org) >= 3.2
* full source compatibility with *python2* and *python3*
* [*OpenSCAP*](http://open-scap.org) >= 1.2.6
* [*dbus-python*](http://www.freedesktop.org/wiki/Software/DBusBindings/)
* (optional) [*Atomic*](http://www.projectatomic.io) >= 1.4
* (optional) [*docker*](http://www.docker.com)
## Running the test-suite
The test-suite can be run without installing the software.
```bash
cd openscap-daemon
cd tests
./make_check
```
## Installation on Linux (standalone on host)
```bash
cd openscap-daemon
# as a python2 application
sudo python2 setup.py install
# as a python3 application
sudo python3 setup.py install
```
## Building a container with OpenSCAP Daemon
Containerized version of OpenSCAP Daemon is used as a backend for the
'atomic scan' command. Atomic scan can scan containers and images
for vulnerabilities and configuration compliance.
You can build and install the container image using these commands:
```bash
./generate-dockerfile.py
docker build -t openscap .
atomic install openscap
```
At this point you can run 'atomic scan' on the host.
The image is not meant to be run outside of the atomic command.
The image is based on Fedora and contains OpenSCAP, OpenSCAP Daemon
and SCAP Security Guide as they are available in Fedora packages.
To install your local working tree of OpenSCAP Daemon instead, add
`--daemon-from-local` to the `./generate-dockerfile.py`.
If you need the latest code from upstream git of OpenSCAP and/or
SCAP Security Guide instead, pass `--openscap-from-git` and/or
`--ssg-from-git` to the `./generate-dockerfile.py`.
## API Consumers
> Please do not rely on the API just yet, we reserve the right to make breaking
> changes. The API will stabilize in time for 1.0.0 release.
OpenSCAP-daemon provides a stable dbus API that is designed to be used by
other projects.
### Atomic Integration
OpenSCAP-daemon is used to implement the `atomic scan` functionality.
`atomic scan` allows users to scan containers and container images for
vulnerabilities.
### Cockpit Integration
Features:
* declare new tasks, schedule when they run, set how they repeat
* generate HTML guides of scheduled tasks
* show past results of tasks
* get ARFs, HTML reports for past results
* set tasks to automatically push results to external result stores
* most importantly to [*scaptimony*](http://github.com/OpenSCAP/scaptimony)
### Foreman Integration
Provide a way to reliably do one-off tasks. Unify various `oscap` runners into
one code-base.
openscap-daemon-0.1.10/bin/ 0000775 0000000 0000000 00000000000 13237071060 0015411 5 ustar 00root root 0000000 0000000 openscap-daemon-0.1.10/bin/oscapd 0000775 0000000 0000000 00000005306 13237071060 0016614 0 ustar 00root root 0000000 0000000 #!/usr/bin/python
# Copyright 2015 Red Hat Inc., Durham, North Carolina.
# All Rights Reserved.
#
# openscap-daemon is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 2.1 of the License, or
# (at your option) any later version.
#
# openscap-daemon is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
# You should have received a copy of the GNU Lesser General Public License
# along with openscap-daemon. If not, see .
#
# Authors:
# Martin Preisler
from openscap_daemon import dbus_daemon
from openscap_daemon import dbus_utils
from openscap_daemon import version
import os
import logging
import sys
import argparse
gobject_mainloop = None
if sys.version_info < (3,):
import gobject
gobject_MainLoop = gobject.MainLoop
else:
from gi.repository import GObject as gobject
from gi.repository import GLib
gobject_MainLoop = GLib.MainLoop
def main():
parser = argparse.ArgumentParser(
description="OpenSCAP-Daemon executable."
)
parser.add_argument(
"-v", "--version", action="version",
version="%(prog)s " + version.VERSION_STRING
)
parser.add_argument("--verbose",
help="be verbose, useful for debugging",
action="store_true")
args = parser.parse_args()
logging.basicConfig(format='%(levelname)s:%(message)s',
level=logging.DEBUG if args.verbose else logging.INFO)
logging.info("OpenSCAP Daemon %s", version.VERSION_STRING)
import dbus.mainloop.glib
gobject.threads_init()
dbus.mainloop.glib.threads_init()
dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
try:
bus = dbus_utils.get_dbus()
name = dbus.service.BusName(dbus_utils.BUS_NAME, bus)
except dbus.exceptions.DBusException as e:
if e.get_dbus_name() == "org.freedesktop.DBus.Error.AccessDenied":
sys.stderr.write(
"Error: DBus denied access to own '%s'. "
"Do you have the necessary permissions?\n\n"
% (dbus_utils.BUS_NAME)
)
raise
config_file = os.path.join("/", "etc", "oscapd", "config.ini")
if "OSCAPD_CONFIG_FILE" in os.environ:
config_file = os.environ["OSCAPD_CONFIG_FILE"]
obj = dbus_daemon.OpenSCAPDaemonDbus(bus, config_file)
loop = gobject_MainLoop()
loop.run()
if __name__ == "__main__":
main()
openscap-daemon-0.1.10/bin/oscapd-cli 0000775 0000000 0000000 00000070352 13237071060 0017364 0 ustar 00root root 0000000 0000000 #!/usr/bin/python
# Copyright 2015 Red Hat Inc., Durham, North Carolina.
# All Rights Reserved.
#
# openscap-daemon is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 2.1 of the License, or
# (at your option) any later version.
#
# openscap-daemon is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
# You should have received a copy of the GNU Lesser General Public License
# along with openscap-daemon. If not, see .
#
# Authors:
# Martin Preisler
from openscap_daemon import dbus_utils
from openscap_daemon import oscap_helpers
from openscap_daemon import cli_helpers
from openscap_daemon import version
import dbus
import sys
import argparse
from datetime import datetime
import os.path
import json
import time
import io
if sys.version_info < (3,):
import gobject
else:
from gi.repository import GObject as gobject
try:
import Atomic.util
atomic_support = True
except:
atomic_support = False
class TaskAccessor(object):
def __init__(self):
self._attributes = dict()
@staticmethod
def get_bool(values):
TaskAccessor._expect_param_len(values, 1)
bool_val = get_bool(values[0])
return [bool_val,]
@staticmethod
def get_int(values):
TaskAccessor._expect_param_len(values, 1)
return [int(values[0])]
@staticmethod
def _expect_param_len(values, expected):
length = len(values)
if length != expected:
raise ValueError(
"Expected %d parameters, but %d were provided." %
(expected, length)
)
@staticmethod
def get_string(values):
TaskAccessor._expect_param_len(values, 1)
return [values[0]]
def add_accessor(self, key, dbus_getter, dbus_setter, check=None, result_processor=None):
self.add_getter(key, dbus_getter, result_processor)
self.add_setter(key, dbus_setter, check)
def add_getter(self, key, dbus_getter, result_processor=None):
self._attributes["get-%s" % key] = (dbus_getter, None, result_processor)
def add_setter(self, key, dbus_setter, check=None):
self._attributes["set-%s" % key] = (dbus_setter, check, None)
def eval(self, dbus_iface, key, task_id, args):
record = self._attributes[key]
method_name = record[0]
cast_func = record[1]
result_func = record[2]
if cast_func:
casted_args = cast_func(args)
else:
casted_args = TaskAccessor.get_string(args)
casted_args.insert(0, task_id)
dbus_method = getattr(dbus_iface, method_name)
res = dbus_method(*casted_args)
if result_func:
result_func(res)
def __contains__(self, key):
return key in self._attributes
def get_allowed(self):
return self._attributes.keys()
def get_dbus_interface():
bus = dbus_utils.get_dbus()
if bus is None:
return None
obj = bus.get_object(
dbus_utils.BUS_NAME,
dbus_utils.OBJECT_PATH
)
if obj is None:
return None
return dbus.Interface(obj, dbus_utils.DBUS_INTERFACE)
def cli_status(dbus_iface, args):
async_status = dbus_iface.GetAsyncActionsStatus()
print(async_status)
def cli_eval(dbus_iface, args):
eval_spec = cli_helpers.cli_create_evaluation_spec(dbus_iface)
if eval_spec is not None:
token = dbus_iface.EvaluateSpecXMLAsync(eval_spec.to_xml_source())
try:
print("Evaluating...")
while True:
success, arf, stdout, stderr, exit_code = \
dbus_iface.GetEvaluateSpecXMLAsyncResults(token)
if success:
if args.results_arf:
args.results_arf.write(arf)
args.results_arf.close()
if args.stdout:
args.stdout.write(stdout)
args.stdout.close()
if args.stderr:
args.stderr.write(stderr)
args.stderr.close()
# TODO: show the results
break
time.sleep(1)
except:
dbus_iface.CancelEvaluateSpecXMLAsync(token)
raise
def cli_print_results_table(dbus_iface, task_id, result_ids,
max_items=sys.maxsize):
table = [["ID", "Timestamp", "Status"]]
for result_id in result_ids[:max_items]:
exit_code = dbus_iface.GetExitCodeOfTaskResult(
task_id, result_id
)
status = oscap_helpers.get_status_from_exit_code(exit_code)
timestamp = dbus_iface.GetResultCreatedTimestamp(task_id, result_id)
table.append([str(result_id), datetime.fromtimestamp(timestamp), status])
cli_helpers.print_table(table)
if max_items < len(result_ids):
print("... and %i more" % (len(result_ids) - max_items))
def cli_task(dbus_iface, task_accessor, args):
if args.task_id is None:
# args.task_action is ignored in this scope
table = [["ID", "Title", "Target", "Modified", "Enabled"]]
task_ids = dbus_iface.ListTaskIDs()
enabled_count = 0
for task_id in task_ids:
title = dbus_iface.GetTaskTitle(task_id)
target = dbus_iface.GetTaskTarget(task_id)
modified_timestamp = dbus_iface.GetTaskModifiedTimestamp(task_id)
modified = datetime.fromtimestamp(modified_timestamp)
enabled = dbus_iface.GetTaskEnabled(task_id)
if enabled:
enabled_count += 1
table.append([
str(task_id),
title,
target,
modified,
# TODO: Maybe we can show the disabled state in a better way?
"enabled" if enabled else "disabled"
])
cli_helpers.print_table(table)
print("")
print("Found %i tasks, %i of them enabled." %
(len(task_ids), enabled_count))
else:
if args.task_action == "info":
title = dbus_iface.GetTaskTitle(args.task_id)
target = dbus_iface.GetTaskTarget(args.task_id)
created_timestamp = dbus_iface.GetTaskCreatedTimestamp(args.task_id)
created = datetime.fromtimestamp(created_timestamp)
modified_timestamp = dbus_iface.GetTaskModifiedTimestamp(args.task_id)
modified = datetime.fromtimestamp(modified_timestamp)
table = []
table.append(["Title", title])
table.append(["ID", str(args.task_id)])
table.append(["Target", target])
table.append(["Created", created])
table.append(["Modified", modified])
cli_helpers.print_table(table, first_row_header=False)
print("")
result_ids = dbus_iface.GetTaskResultIDs(args.task_id)
if len(result_ids) > 0:
print("Latest results:")
cli_print_results_table(dbus_iface, args.task_id, result_ids, 5)
print("")
if not dbus_iface.GetTaskEnabled(args.task_id):
print("This task is currently disabled. Enable it by calling:")
print("$ oscapd-cli task %i enable" % (args.task_id))
# TODO
elif args.task_action == "guide":
guide = dbus_iface.GenerateGuideForTask(args.task_id)
print(guide)
elif args.task_action == "bash_fix":
fix = dbus_iface.GenerateFixForTask(args.task_id, "bash")
print(fix)
elif args.task_action == "ansible_fix":
fix = dbus_iface.GenerateFixForTask(args.task_id, "ansible")
print(fix)
elif args.task_action == "puppet_fix":
fix = dbus_iface.GenerateFixForTask(args.task_id, "puppet")
print(fix)
elif args.task_action == "run":
dbus_iface.RunTaskOutsideSchedule(args.task_id)
elif args.task_action == "enable":
dbus_iface.SetTaskEnabled(args.task_id, True)
elif args.task_action == "disable":
dbus_iface.SetTaskEnabled(args.task_id, False)
elif args.task_action == "remove":
if args.force or confirm("Do you really want to delete task with ID %i?" % args.task_id):
dbus_iface.RemoveTask(args.task_id, args.remove_results)
elif args.task_action in task_accessor:
try:
task_accessor.eval(
dbus_iface, args.task_action, args.task_id,
args.parameters[0]
)
except ValueError as e:
sys.stderr.write("%s\n" % (e))
sys.exit(1)
else:
# throwing exception here, this code should never be executed if
# argparse does its job
raise RuntimeError("Unknown action '%s'." % (args.task_action))
def cli_task_create(dbus_iface, args):
if args.interactive:
print("Creating new task in interactive mode")
title = cli_helpers.py2_raw_input("Title: ")
target = cli_helpers.py2_raw_input("Target (empty for localhost): ")
if not target:
target = "localhost"
input_ssg_choice = ""
ssg_choices = dbus_iface.GetSSGChoices()
if ssg_choices:
print("Found the following SCAP Security Guide content: ")
for i, ssg_choice in enumerate(ssg_choices):
print("\t%i: %s" % (i + 1, ssg_choice))
input_file = None
input_ssg_choice = cli_helpers.py2_raw_input(
"Choose SSG content by number (empty for custom content): ")
if not input_ssg_choice:
input_file = cli_helpers.py2_raw_input("Input file (absolute path): ")
else:
input_file = ssg_choices[int(input_ssg_choice) - 1]
if not input_file:
sys.stderr.write(
"You have to provide an SCAP input file for the task!\n"
)
sys.exit(1)
if not os.path.isabs(input_file):
sys.stderr.write(
"'%s' is not an absolute path. Please provide the absolute "
"path that can be used to access the SCAP content on the "
"machine running openscap-daemon.\n" % (input_file)
)
sys.exit(1)
tailoring_file = cli_helpers.py2_raw_input(
"Tailoring file (absolute path, empty for no tailoring): ")
if tailoring_file in [None, ""]:
tailoring_file = ""
else:
if not os.path.isabs(tailoring_file):
sys.stderr.write(
"'%s' is not an absolute path. Please provide the absolute "
"path that can be used to access the tailoring file on the "
"machine running openscap-daemon.\n" % (tailoring_file)
)
sys.exit(1)
print("Found the following possible profiles: ")
profile_choices = dbus_iface.GetProfileChoicesForInput(
input_file, tailoring_file
)
for i, (key, value) in enumerate(profile_choices.items()):
print("\t%i: %s (id='%s')" % (i + 1, value, key))
profile_choice = cli_helpers.py2_raw_input(
"Choose profile by number (empty for (default) profile): ")
if profile_choice:
profile = list(profile_choices.keys())[int(profile_choice) - 1]
else:
profile = ""
online_remediation_raw = \
cli_helpers.py2_raw_input(
"Online remediation (1, y or Y for yes, else no): "
)
try:
online_remediation = get_bool(online_remediation_raw, default=False)
except ValueError:
pass
print("Schedule: ")
schedule_not_before = None
schedule_not_before_str = \
cli_helpers.py2_raw_input(
" - not before (YYYY-MM-DD HH:MM in UTC, empty for NOW): "
)
if schedule_not_before_str == "":
schedule_not_before = datetime.now()
else:
schedule_not_before = datetime.strptime(
schedule_not_before_str, "%Y-%m-%d %H:%M"
)
schedule_repeat_after = None
schedule_repeat_after_str = \
cli_helpers.py2_raw_input(
" - repeat after (hours or @daily, @weekly, @monthly, "
"empty or 0 for no repeat): "
)
schedule_repeat_after = 0
if not schedule_repeat_after_str:
pass # empty means no repeat
elif schedule_repeat_after_str == "@daily":
schedule_repeat_after = 1 * 24
elif schedule_repeat_after_str == "@weekly":
schedule_repeat_after = 7 * 24
elif schedule_repeat_after_str == "@monthly":
schedule_repeat_after = 30 * 24
else:
schedule_repeat_after = int(schedule_repeat_after_str)
# most users need just drop_missed_aligned, we will not offer the
# other options here
# schedule_slip_mode = task.SlipMode.DROP_MISSED_ALIGNED
task_id = dbus_iface.CreateTask()
dbus_iface.SetTaskTitle(task_id, title)
dbus_iface.SetTaskTarget(task_id, target)
dbus_iface.SetTaskInput(task_id, input_file)
dbus_iface.SetTaskTailoring(task_id, tailoring_file)
dbus_iface.SetTaskProfileID(task_id, profile)
dbus_iface.SetTaskOnlineRemediation(task_id, online_remediation)
dbus_iface.SetTaskScheduleNotBefore(
task_id, schedule_not_before.strftime("%Y-%m-%dT%H:%M")
)
dbus_iface.SetTaskScheduleRepeatAfter(task_id, schedule_repeat_after)
print(
"Task created with ID '%i'. It is currently set as disabled. "
"You can enable it with `oscapd-cli task %i enable`." %
(task_id, task_id)
)
# TODO: Setting Schedule SlipMode
else:
raise NotImplementedError("Not yet!")
def cli_result(dbus_iface, args):
if args.result_id is None:
task_title = dbus_iface.GetTaskTitle(args.task_id)
print("Results of Task \"%s\", ID = %i" % (task_title, args.task_id))
print("")
result_ids = dbus_iface.GetTaskResultIDs(args.task_id)
cli_print_results_table(dbus_iface, args.task_id, result_ids)
elif args.result_id == "remove":
if args.force or confirm("Do you really want to remove all results of task %d"
% args.task_id):
dbus_iface.RemoveTaskResults(args.task_id)
else:
if args.result_action == "arf":
arf = dbus_iface.GetARFOfTaskResult(args.task_id, args.result_id)
print(arf)
elif args.result_action == "stdout":
stdout = dbus_iface.GetStdOutOfTaskResult(
args.task_id, args.result_id
)
print(stdout)
elif args.result_action == "stderr":
stderr = dbus_iface.GetStdErrOfTaskResult(
args.task_id, args.result_id
)
print(stderr)
elif args.result_action == "exit_code":
exit_code = dbus_iface.GetExitCodeOfTaskResult(
args.task_id, args.result_id
)
print("%i" % (exit_code))
elif args.result_action == "report":
report = dbus_iface.GenerateReportForTaskResult(
args.task_id, args.result_id
)
print(report)
elif args.result_action == "bash_fix":
fix = dbus_iface.GenerateFixForTaskResult(
args.task_id, args.result_id, "bash"
)
print(fix)
elif args.result_action == "ansible_fix":
fix = dbus_iface.GenerateFixForTaskResult(
args.task_id, args.result_id, "ansible"
)
print(fix)
elif args.result_action == "puppet_fix":
fix = dbus_iface.GenerateFixForTaskResult(
args.task_id, args.result_id, "puppet"
)
print(fix)
elif args.result_action == "remove":
if args.force or confirm("Do you really want to remove result %d from task %d"
% (args.result_id, args.task_id)):
dbus_iface.RemoveTaskResult(args.task_id, args.result_id)
else:
raise RuntimeError(
"Unknown result action '%s'." % (args.result_action)
)
def cli_scan(dbus_iface, args):
if args.fetch_cves is None:
fetch_cve = 2 # use defaults
elif args.fetch_cves:
fetch_cve = 1 # disable
else:
fetch_cve = 0 # enable
threads_count = 4
scan_targets = []
any_target_specified = False
if args.all or args.images:
images = json.loads(dbus_iface.images())
images_ids = [str(image["Id"]) for image in images]
scan_targets.extend(images_ids)
any_target_specified = True
if args.all or args.containers:
containers = json.loads(dbus_iface.containers())
container_ids = [str(container["Id"]) for container in containers]
scan_targets.extend(container_ids)
any_target_specified = True
if args.scan_targets:
scan_targets.extend(args.scan_targets) # todo do check if targets are valid
any_target_specified = True
if not any_target_specified:
raise RuntimeError("No scan target")
token = dbus_iface.CVEScanListAsync(
scan_targets, threads_count, fetch_cve
)
try:
print("Processing...")
while True:
success, scan_results = dbus_iface.GetCVEScanListAsyncResults(token)
if success:
break
time.sleep(1)
except:
dbus_iface.CancelCVEScanListAsync(token)
raise
if args.json:
print(scan_results)
else:
json_parsed = json.loads(scan_results)
if args.detail:
clean = Atomic.util.print_detail_scan_summary(
json_parsed
)
else:
if args.scan_targets:
raise NotImplemented(
"This type of output is not implemented"
"for specified targets.\n"
)
clean = Atomic.util.print_scan_summary(
json_parsed, scan_targets
)
if not clean:
sys.exit(1)
def get_bool(val, default=False):
val = val.lower()
if not val:
return default
if val in ['n', '0', 'false', 'no']:
return False
if val in ['y', '1', 'true', 'yes']:
return True
raise ValueError("'%s' is not valid value, use y/n instead." % (val))
def confirm(prompt, default=False):
options = "Y/n" if default else "y/N"
while True:
try:
res = cli_helpers.py2_raw_input("%s [%s]: " % (prompt, options))
return get_bool(res, default)
except ValueError:
continue
except EOFError:
sys.stderr.write("Operation aborted.\n")
return default
def main():
parser = argparse.ArgumentParser(
description="OpenSCAP-Daemon command line interface."
)
parser.add_argument(
"-v", "--version", action="version",
version="%(prog)s " + version.VERSION_STRING
)
subparsers = parser.add_subparsers(dest="action")
subparsers.required = True
task_accessor = TaskAccessor()
task_accessor.add_setter("enabled",
"SetTaskEnabled",
TaskAccessor.get_bool)
task_accessor.add_setter("title", "SetTaskTitle")
task_accessor.add_setter("target", "SetTaskTarget")
task_accessor.add_setter("input", "SetTaskInput")
task_accessor.add_setter("tailoring", "SetTaskTailoring")
task_accessor.add_setter("profile-id", "SetTaskProfileID")
task_accessor.add_setter("online-remediation",
"SetTaskOnlineRemediation",
TaskAccessor.get_bool)
task_accessor.add_setter("schedule-not-before", "SetTaskScheduleNotBefore")
task_accessor.add_setter("schedule-repeat-after",
"SetTaskScheduleRepeatAfter",
TaskAccessor.get_int)
def add_eval_parser(subparsers):
eval_parser = subparsers.add_parser(
"eval",
help="Interactive one-off evaluation of any target supported by "
"OpenSCAP Daemon"
)
eval_parser.add_argument(
"--results-arf", dest="results_arf",
type=lambda path: io.open(path, "w", encoding="utf-8"),
help="Write ARF (result data stream) into file on this path."
)
eval_parser.add_argument(
"--stdout",
type=lambda path: io.open(path, "w", encoding="utf-8"),
help="Write stdout from oscap into file on this path."
)
eval_parser.add_argument(
"--stderr",
type=lambda path: io.open(path, "w", encoding="utf-8"),
help="Write stderr from oscap into file on this path."
)
# todo non-interactive
add_eval_parser(subparsers)
def add_task_parser(subparsers, task_accessor):
task_parser = subparsers.add_parser(
"task",
help="Show info about tasks that have already been defined. "
"Perform operations on already defined tasks."
)
task_parser.add_argument(
"task_id", metavar="TASK_ID", type=int, nargs="?",
help="ID of the task to display, or perform action on. If none is "
"provided a summary of all tasks is displayed."
)
task_actions = ["info", "guide", "run", "enable", "disable", "remove",
"bash_fix", "ansible_fix", "puppet_fix"]
task_actions += task_accessor.get_allowed()
task_parser.add_argument(
"task_action", metavar="ACTION", type=str,
choices=task_actions,
help="Which action to perform on selected task. Use one of " +
", ".join(task_actions),
default="info", nargs="?"
)
task_parser.add_argument(
"parameters", metavar="parameter", action="append", nargs="*",
help="Parameters for the ACTION. For setter actions this is the "
"string that you want to set. Some actions, such as enable, remove, "
"... don't require any parameters."
)
task_parser.add_argument(
"-f", "--force", help="remove task without confirmation",
action="store_true"
)
task_parser.add_argument(
"-r", "--remove-results", help="remove with results",
action="store_true"
)
add_task_parser(subparsers, task_accessor)
def add_task_create_parser(subparsers):
task_create_parser = subparsers.add_parser(
"task-create",
help="Create new task."
)
task_create_parser.add_argument(
"-i", "--interactive", action="store_true", dest="interactive", required=True
)
add_task_create_parser(subparsers)
def add_status_parser(subparsers):
status_parser = subparsers.add_parser(
"status",
help="Displays status, tasks that are planned and tasks that are "
"being evaluated."
)
add_status_parser(subparsers)
def result_id_or_action(val):
if val == "remove":
return "remove"
try:
return int(val)
except ValueError:
raise argparse.ArgumentTypeError("'%s' is not \"remove\" or integer"
% (val))
def add_result_parser(subparsers):
result_parser = subparsers.add_parser(
"result",
help="Displays info about past results"
)
result_parser.add_argument(
"task_id", metavar="TASK_ID", type=int
)
result_parser.add_argument(
"result_id", metavar="RESULT_ID", type=result_id_or_action, nargs="?",
help="ID of the result we want to interact with, if none is "
"provided a summary of all results of given task is displayed."
)
result_actions = [
"arf", "stdout", "stderr", "exit_code", "report", "remove",
"bash_fix", "ansible_fix", "puppet_fix"
]
result_parser.add_argument(
"result_action", metavar="ACTION", type=str,
choices=result_actions,
help="Which action to perform on selected result. Use one of " +
", ".join(result_actions),
default="arf", nargs="?",
)
result_parser.add_argument(
"-f", "--force", help="remove results without confirmation",
action="store_true"
)
add_result_parser(subparsers)
def add_scan_parser(subparsers):
scan_parser = subparsers.add_parser(
"scan", help="scan an image or container for CVEs",
epilog="atomic scan scans a container or image for CVEs"
)
scan_parser.add_argument(
"scan_targets", nargs='*', help="container image"
)
scan_parser.add_argument(
"--fetch_cves", type=get_bool, default=None
)
scan_out = scan_parser.add_mutually_exclusive_group()
scan_out.add_argument(
"--json", default=False, action='store_true',
help="output json"
)
scan_out.add_argument(
"--detail", default=False, action='store_true',
help="output more detail"
)
scan_group = scan_parser.add_mutually_exclusive_group()
scan_group.add_argument(
"--all", default=False, action='store_true',
help="scan all images (excluding intermediate layers) and containers"
)
scan_group.add_argument(
"--images", default=False, action='store_true',
help="scan all images (excluding intermediate layers"
)
scan_group.add_argument(
"--containers", default=False, action='store_true',
help="scan all containers"
)
if atomic_support:
add_scan_parser(subparsers)
args = parser.parse_args()
gobject.threads_init()
dbus_iface = None
try:
dbus_iface = get_dbus_interface()
except:
sys.stderr.write(
"Error: Failed to connect to the OpenSCAP-daemon DBus interface. "
"Is the daemon running?\n\n"
)
raise
try:
oscapd_version_major, oscapd_version_minor, oscapd_version_patch = \
dbus_iface.GetVersion()
if (oscapd_version_major, oscapd_version_minor, oscapd_version_patch) \
!= (version.VERSION_MAJOR, version.VERSION_MINOR, version.VERSION_PATCH):
sys.stderr.write(
"Warning: Version mismatch between oscapd-cli and oscapd.\n")
except dbus.exceptions.DBusException as e:
if e.get_dbus_name() == "org.freedesktop.DBus.Error.UnknownMethod":
sys.stderr.write(
"Warning: Can't perform version check, the openscap-daemon dbus"
" interface doesn't provide the GetVersion method.\n\n"
)
elif e.get_dbus_name() == "org.freedesktop.DBus.Error.AccessDenied":
sys.stderr.write(
"Error: Access denied on the DBus interface. "
"Do you have the necessary permissions?\n\n"
)
sys.exit(1)
else:
raise
if args.action == "status":
cli_status(dbus_iface, args)
elif args.action == "eval":
cli_eval(dbus_iface, args)
elif args.action == "task":
cli_task(dbus_iface, task_accessor, args)
elif args.action == "task-create":
cli_task_create(dbus_iface, args)
elif args.action == "status":
cli_status(dbus_iface, args)
elif args.action == "result":
cli_result(dbus_iface, args)
elif atomic_support and args.action == "scan":
cli_scan(dbus_iface, args)
else:
raise RuntimeError("Unknown action '%s'." % (args.action))
if __name__ == "__main__":
main()
openscap-daemon-0.1.10/bin/oscapd-evaluate 0000775 0000000 0000000 00000056753 13237071060 0020434 0 ustar 00root root 0000000 0000000 #!/usr/bin/python
# Copyright 2016 Red Hat Inc., Durham, North Carolina.
# All Rights Reserved.
#
# openscap-daemon is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 2.1 of the License, or
# (at your option) any later version.
#
# openscap-daemon is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
# You should have received a copy of the GNU Lesser General Public License
# along with openscap-daemon. If not, see .
#
# Authors:
# Martin Preisler
from __future__ import print_function
from openscap_daemon import config as config_
from openscap_daemon import evaluation_spec
from openscap_daemon import oscap_helpers
from openscap_daemon import cli_helpers
from openscap_daemon import version
from openscap_daemon.evaluation_spec import ProfileSuffixMatchError
import os
import os.path
import logging
import argparse
import sys
import threading
import io
import json
import datetime
if sys.version_info < (3,):
import Queue
else:
import queue as Queue
def cli_xml(args, config):
spec = evaluation_spec.EvaluationSpec()
spec.load_from_xml_file(args.path)
results, stdout, stderr, exit_code = spec.evaluate(config)
if args.results is not None:
args.results.write(results["arf"])
args.results.close()
if args.stdout is not None:
args.stdout.write(stdout)
args.stdout.close()
if args.stderr is not None:
args.stderr.write(stderr)
args.stderr.close()
sys.exit(exit_code)
def cli_spec(args, config):
spec = evaluation_spec.EvaluationSpec()
spec.mode = oscap_helpers.EvaluationMode.from_string(args.mode)
spec.target = args.target
if spec.mode not in [oscap_helpers.EvaluationMode.CVE_SCAN,
oscap_helpers.EvaluationMode.STANDARD_SCAN]:
spec.input_.set_contents(args.input_.read())
if args.tailoring is not None:
spec.tailoring.set_contents(args.tailoring.read())
spec.profile_id = args.profile
spec.online_remediation = args.remediate
if args.print_xml:
print(spec.to_xml_source())
sys.exit(0)
else:
results, stdout, stderr, exit_code = spec.evaluate(config)
if args.results is not None:
args.results.write(results["arf"])
args.results.close()
if args.stdout is not None:
args.stdout.write(stdout)
args.stdout.close()
if args.stderr is not None:
args.stderr.write(stderr)
args.stderr.close()
sys.exit(exit_code)
def cli_scan(args, config):
assert(os.path.isdir(args.output))
output_dir_map = {}
targets = cli_helpers.preprocess_targets(args.targets, output_dir_map)
queue = Queue.Queue(len(targets))
for target in targets:
queue.put_nowait(target)
scanned_targets = []
failed_targets = []
def scan_worker():
while True:
try:
target = queue.get(False)
if len(failed_targets) > 0:
failed_targets.append(target)
queue.task_done()
continue
all_cve_results = None
cve_last_updated = None
all_standard_scan_results = None
logging.debug("Started scanning target '%s'", target)
started_time = None
finished_time = None
try:
started_time = datetime.datetime.now()
cpes = []
try:
cpes = evaluation_spec.EvaluationSpec.\
detect_CPEs_of_target(target, config)
except:
logging.exception(
"Failed to detect CPEs of target '%s'. "
"Assuming no CPEs..." % (target)
)
if not args.no_cve_scan:
es = evaluation_spec.EvaluationSpec()
es.mode = oscap_helpers.EvaluationMode.CVE_SCAN
es.target = target
es.cpe_hints = cpes
try:
all_cve_results, stdout, stderr, exit_code = \
es.evaluate(config)
if exit_code == 1:
logging.warning(
"CVE scan of target '%s' failed with "
"exit_code %i.\n\nstdout:%s\n\nstderr:%s" %
(target, exit_code, stdout, stderr)
)
except:
logging.exception(
"Failed to scan target '%s' for "
"vulnerabilities." % (target)
)
try:
cve_last_updated = config.cve_feed_manager.\
get_cve_feed_last_updated(cpes)
except:
# this is not a crucial part of evaluation, the
# last modified date can be unknown.
pass
if not args.no_standard_compliance:
es = evaluation_spec.EvaluationSpec()
es.mode = oscap_helpers.EvaluationMode.STANDARD_SCAN
es.target = target
es.cpe_hints = cpes
es.result_format = "standard"
if args.stig_viewer:
es.result_format = "stig"
ssg_sds = config.get_ssg_sds(cpes)
es.input_.set_file_path(ssg_sds)
es.input_.xccdf_id = args.xccdf_id
try:
args.profile = es.select_profile_by_suffix(
args.xccdf_id, args.profile
)
except ProfileSuffixMatchError as e:
msg = (
"Failed to pick a profile for scanning '{}': {}"
.format(target, str(e))
)
raise RuntimeError(msg)
try:
all_standard_scan_results, stdout, stderr, exit_code = \
es.evaluate(config)
if exit_code == 1:
logging.warning(
"Configuration compliance scan of target '%s' "
"using profile '%s' "
"failed with exit_code %i.\n\nstdout:%s\n\n"
"stderr:%s" %
(target, es.profile_id, exit_code, stdout, stderr)
)
except:
logging.exception(
"Failed to scan target '%s' for "
"configuration compliance." % (target)
)
finished_time = datetime.datetime.now()
except Exception as e:
logging.error(e)
failed_targets.append(target)
queue.task_done()
scanned_targets.append(
(target, all_cve_results, cve_last_updated,
all_standard_scan_results, started_time, finished_time)
)
percent = "{0:6.2f}%".format(
float(len(scanned_targets) * 100) / len(targets)
)
logging.info("[%s] Scanned target '%s'", percent, target)
except Queue.Empty:
break
assert(args.jobs > 0)
workers = []
for worker_id in range(args.jobs):
worker = threading.Thread(
name="Atomic scan worker #%i" % (worker_id),
target=scan_worker
)
workers.append(worker)
worker.start()
try:
queue.join()
except KeyboardInterrupt:
failed_targets.append(None)
for worker in workers:
worker.join()
sys.stderr.write("Evaluation interrupted by user!\n")
if len(failed_targets) > 0:
# It is difficuly to determine the real count of failed targets right,
# hence the decrementation and usage of "at least".
logging.info(
"Fatal error encountered while evaluating! Failed to evaluate "
"at least %i targets!\n" % (len(failed_targets) - 1)
)
for target, all_cve_results, cve_last_updated, all_standard_scan_results, \
started_time, finished_time in scanned_targets:
cve_results = None
if all_cve_results is not None:
cve_results = all_cve_results["arf"]
output_dir = ""
if target in output_dir_map:
output_dir = output_dir_map[target]
else:
output_dir = target
output_dir = output_dir.replace(":", "_")
output_dir = output_dir.replace("/", "_")
json_target = target
if json_target.startswith("chroot://"):
json_target = json_target[len("chroot://"):]
json_data = {}
json_data["UUID"] = json_target
json_data["Scanner"] = "openscap"
json_data["Time"] = started_time.strftime("%Y-%m-%dT%H:%M:%S") \
if started_time is not None else "unknown"
json_data["Finished Time"] = \
finished_time.strftime("%Y-%m-%dT%H:%M:%S") \
if finished_time is not None else "unknown"
if cve_results is not None:
json_data["CVE Feed Last Updated"] = \
cve_last_updated.strftime("%Y-%m-%dT%H:%M:%S") \
if cve_last_updated is not None else "unknown"
json_data["Vulnerabilities"] = []
if (args.no_cve_scan or cve_results) and \
(args.no_standard_compliance or all_standard_scan_results):
json_data["Successful"] = "true"
else:
json_data["Successful"] = "false"
scan_type = []
full_output_dir = os.path.join(args.output, output_dir)
try:
os.makedirs(full_output_dir)
except OSError as e:
if e.errno != 17: # it's fine if it already exists
raise
if cve_results is not None:
scan_type.append("CVE")
cli_helpers.summarize_cve_results(
cve_results, json_data["Vulnerabilities"]
)
with io.open(os.path.join(
full_output_dir, "cve.xml"), "w",
encoding="utf-8") as f:
f.write(cve_results)
if all_standard_scan_results is None:
all_standard_scan_results = dict()
arf_scan_results = all_standard_scan_results.get("arf", None)
if arf_scan_results is not None:
scan_type.append("Configuration Compliance")
cli_helpers.summarize_standard_compliance_results(
arf_scan_results, json_data["Vulnerabilities"], args.profile
)
json_data["Profile"] = args.profile
arf_filepath = os.path.join(full_output_dir, "arf.xml")
with io.open(arf_filepath, "w", encoding="utf-8") as f:
f.write(arf_scan_results)
if args.fix_type is not None:
fix_script = oscap_helpers.generate_fix_for_result(
config, arf_filepath, args.fix_type, args.xccdf_id
)
suffixes = {"bash": "sh", "ansible": "yml", "puppet": "pp"}
fix_name = "fix." + suffixes[args.fix_type]
fix_filepath = os.path.join(full_output_dir, fix_name)
with io.open(fix_filepath, "w", encoding="utf-8") as f:
f.write(fix_script)
if args.report:
report = oscap_helpers.generate_html_report_for_result(config, arf_filepath)
report_filepath = os.path.join(full_output_dir, "report.html")
with io.open(report_filepath, "w", encoding="utf-8") as f:
f.write(report)
if "stig" in all_standard_scan_results:
stig_filepath = os.path.join(full_output_dir, "stig.xml")
with io.open(stig_filepath, "w", encoding="utf-8") as f:
f.write(all_standard_scan_results["stig"])
json_data["Scan Type"] = ", ".join(scan_type)
with open(os.path.join(
full_output_dir, "json"), "w") as f:
json.dump(json_data, f, indent=2)
def main():
parser = argparse.ArgumentParser(
description="OpenSCAP-Daemon one-off evaluator."
)
parser.add_argument(
"-v", "--version", action="version",
version="%(prog)s " + version.VERSION_STRING
)
parser.add_argument("--verbose",
help="be verbose, useful for debugging",
action="store_true")
subparsers = parser.add_subparsers(dest="action")
subparsers.required = True
config_parser = subparsers.add_parser(
"config",
help="Start with default configuration, auto-detect tool and content "
"locations and output the resulting INI results into stdout or "
"given file path"
)
config_parser.add_argument(
"--path", metavar="PATH", type=argparse.FileType("w"),
default=sys.stdout,
help="Destination where the config file will be written, defaults to "
"stdout."
)
xml_parser = subparsers.add_parser(
"xml",
help="Evaluate an EvaluationSpec passed as an XML, either to stdin or "
"as a file."
)
xml_parser.add_argument(
"--path", metavar="PATH", type=argparse.FileType("r"),
default=sys.stdin,
help="The input Evaluation Spec XML file. Defaults to stdin."
)
xml_parser.add_argument(
"--results", metavar="PATH", type=argparse.FileType("w"),
help="Write ARF (result datastream) or OVAL results XML to this file."
)
xml_parser.add_argument(
"--stdout", metavar="PATH", type=argparse.FileType("w"),
help="Write stdout from oscap tool to this file."
)
xml_parser.add_argument(
"--stderr", metavar="PATH", type=argparse.FileType("w"),
help="Write stderr from oscap tool to this file."
)
spec_parser = subparsers.add_parser(
"spec",
help="Evaluate an EvaluationSpec created using arguments passed on "
"the command line."
)
spec_parser.add_argument(
"--mode", type=str,
choices=["sds", "oval", "cve_scan", "standard_scan"],
default="sds",
help="Evaluation mode for the EvaluationSpec. 'sds' evaluates input as "
"a source datastream. 'oval' evaluates it as an OVAL file. 'cve_scan' "
"is a special mode that automatically uses the right CVE feed as OVAL "
"file. 'standard_scan' uses the right SSG content and standard profile "
"based on OS of the scanned system."
)
spec_parser.add_argument(
"--target", type=str,
default="localhost",
help="Which target should we be evaluating. Possible choices include: "
"'localhost', 'ssh://user@machine', 'docker-image://IMAGE_ID', "
"'docker-container://CONTAINER_ID', 'vm-domain://VM_NAME', "
"'vm-image:///path/to/image.qcow2', 'chroot:///path/to/chroot'."
)
spec_parser.add_argument(
"--input", metavar="PATH", dest="input_",
type=lambda path: io.open(path, "r", encoding="utf-8"),
default=sys.stdin,
help="Depending on --mode this should be a source datastream or OVAL "
"file. In cve_scan and standard_scan mode the --input is not used."
)
spec_parser.add_argument(
"--tailoring", metavar="PATH",
type=lambda path: io.open(path, "r", encoding="utf-8"),
help="XCCDF tailoring file. Only used in 'sds' mode."
)
spec_parser.add_argument(
"--profile", type=str,
default="",
help="ID of the XCCDF profile to use. Only used in 'sds' mode. Empty "
"string is the default and that means the (default) profile."
)
spec_parser.add_argument(
"--remediate", default=False, action="store_true",
help="Perform remediation for failed rules after the scan. Only used "
"in 'sds' and 'standard_scan' modes."
)
spec_parser.add_argument(
"--print-xml",
dest="print_xml",
action="store_true",
help="Don't evaluate the EvaluationSpec, just print its XML to stdout"
)
spec_parser.add_argument(
"--results", metavar="PATH",
type=lambda path: io.open(path, "w", encoding="utf-8"),
help="Write OVAL results or ARF result datastream (depending on mode) "
"to this location."
)
spec_parser.add_argument(
"--stdout", metavar="PATH",
type=lambda path: io.open(path, "w", encoding="utf-8"),
help="Write stdout from oscap tool to this file."
)
spec_parser.add_argument(
"--stderr", metavar="PATH",
type=lambda path: io.open(path, "w", encoding="utf-8"),
help="Write stderr from oscap tool to this file."
)
target_cpes_parser = subparsers.add_parser(
"target-cpes",
help="Detect CPEs applicable on given target"
)
target_cpes_parser.add_argument(
"--target", type=str,
default="localhost",
help="Which target should we be checking. Possible choices include: "
"'localhost', 'ssh://user@machine', 'docker-image://IMAGE_ID', "
"'docker-container://CONTAINER_ID', 'vm-domain://VM_NAME', "
"'vm-image:///path/to/image.qcow2', 'chroot:///path/to/chroot'."
)
target_profiles_parser = subparsers.add_parser(
"target-profiles",
help="Detect SCAP Security Guide profiles applicable on given target"
)
target_profiles_parser.add_argument(
"--target", type=str,
default="localhost",
help="Which target should we be checking. Possible choices include: "
"'localhost', 'ssh://user@machine', 'docker-image://IMAGE_ID', "
"'docker-container://CONTAINER_ID', 'vm-domain://VM_NAME', "
"'vm-image:///path/to/image.qcow2', 'chroot:///path/to/chroot'."
)
scan_parser = subparsers.add_parser(
"scan",
help="Scan a list of targets for CVEs and configuration compliance, "
"return aggregated results. This is an integration shim "
"intended for Atomic but can also be useful elsewhere."
)
scan_parser.add_argument(
"--targets", type=str, nargs="+",
default=["localhost"],
help="Which target(s) should we be scanning. Possible choices include: "
"'localhost', 'ssh://user@machine', 'docker-image://IMAGE_ID', "
"'docker-container://CONTAINER_ID', 'vm-domain://VM_NAME', "
"'vm-image:///path/to/image.qcow2', 'chroot:///path/to/chroot', "
"'chroots-in-dir:///path/to/chroots'. "
"Delimited by spaces."
)
scan_parser.add_argument(
"-j", "--jobs", type=int,
default=4,
help="How many worker jobs should scan in parallel."
)
scan_parser.add_argument(
"--no-cve-scan", default=False, action="store_true",
dest="no_cve_scan",
help="Skip the CVE scan."
)
scan_parser.add_argument(
# keeping the alias for compatibility with Atomic
"--no-configuration-compliance", "--no-standard-compliance", default=False, action="store_true",
dest="no_standard_compliance",
help="Skip the configuration compliance scan."
)
scan_parser.add_argument(
"--xccdf-id", type=str,
default=None,
help="ID of the XCCDF component in a datastream. Empty string is the "
"default and means that the first XCCDF component found in a "
"datastream will be used when looking for an XCCDF profile ID."
)
scan_parser.add_argument(
"--profile", type=str,
default="xccdf_org.ssgproject.content_profile_standard",
help="Specify the profile ID for configuration compliance scan. "
"If not specified, the 'standard' profile will be used."
)
scan_parser.add_argument(
"--stig-viewer", action="store_true",
help="Whether to produce output that is consumable "
"by the STIG viewer app."
)
scan_parser.add_argument(
"--output", type=str, required=True,
help="A directory where results will be stored in. There will be a "
"directory for each target created there with up to 4 files. 'json' "
"with json summary of the scan, cve.xml with CVE scan raw results, "
"arf.xml with configuration compliance scan raw results, and "
"fix.[sh|yml|pp] with a compliance remediation script."
)
scan_parser.add_argument(
"--fix_type", type=str,
choices=["bash", "ansible", "puppet"], default=None,
help="Specify the language of remediation script to be used."
)
scan_parser.add_argument(
"--report", action="store_true", default=False,
help="Create HTML report in the output directory."
)
args = parser.parse_args()
logging.basicConfig(format='%(levelname)s:%(message)s',
level=logging.DEBUG if args.verbose else logging.INFO)
logging.info("OpenSCAP Daemon one-off evaluator %s", version.VERSION_STRING)
if args.action == "config":
config = config_.Configuration()
config.autodetect_tool_paths()
config.autodetect_content_paths()
config.save_as(args.path)
sys.exit(0)
config_file = os.path.join("/", "etc", "oscapd", "config.ini")
if "OSCAPD_CONFIG_FILE" in os.environ:
config_file = os.environ["OSCAPD_CONFIG_FILE"]
config = config_.Configuration()
config.load(config_file)
config.autodetect_tool_paths()
config.autodetect_content_paths()
config.prepare_dirs(cleanup_allowed=False)
try:
config.sanity_check()
except Exception as exc:
logging.error(
"Configuration file '{}' failed sanity checking: {}"
.format(config.config_file, str(exc)))
sys.exit(1)
if args.action == "xml":
cli_xml(args, config)
elif args.action == "spec":
cli_spec(args, config)
elif args.action == "target-cpes":
cpes = evaluation_spec.EvaluationSpec.detect_CPEs_of_target(
args.target, config
)
print("\n".join(cpes))
sys.exit(0)
elif args.action == "target-profiles":
cpes = evaluation_spec.EvaluationSpec.detect_CPEs_of_target(
args.target, config
)
ssg_sds = config.get_ssg_sds(cpes)
print("Security profiles applicable on target " + args.target + ":")
profiles = oscap_helpers.get_profile_choices_for_input(
ssg_sds, None, args.xccdf_id
)
for profile_id, title in profiles.items():
if profile_id:
print(title + " (id='" + profile_id + "')")
else:
print("Default Profile")
sys.exit(0)
elif args.action == "scan":
cli_scan(args, config)
if __name__ == "__main__":
main()
openscap-daemon-0.1.10/container/ 0000775 0000000 0000000 00000000000 13237071060 0016623 5 ustar 00root root 0000000 0000000 openscap-daemon-0.1.10/container/config.ini 0000664 0000000 0000000 00000001126 13237071060 0020571 0 ustar 00root root 0000000 0000000 [General]
tasks-dir = /var/lib/oscapd/tasks
results-dir = /var/lib/oscapd/results
work-in-progress-dir = /var/lib/oscapd/work_in_progress
cve-feeds-dir = /var/lib/oscapd/cve_feeds
jobs = 4
[Tools]
oscap = /usr/bin/oscap
oscap-ssh = /usr/bin/oscap-ssh
oscap-vm = /usr/bin/oscap-vm
oscap-docker = /usr/bin/oscap-docker
oscap-chroot = /usr/bin/oscap-chroot
container-support = yes
[Content]
cpe-oval = /usr/share/openscap/cpe/openscap-cpe-oval.xml
ssg = /usr/share/xml/scap/ssg/content
[CVEScanner]
fetch-cve = no
fetch-cve-url = https://www.redhat.com/security/data/oval/
fetch-cve-timeout = 600
openscap-daemon-0.1.10/container/help.sh 0000775 0000000 0000000 00000001075 13237071060 0020115 0 ustar 00root root 0000000 0000000 #!/bin/bash
DOCKERFILE="/root/Dockerfile"
VERSION=$(grep ' version=' $DOCKERFILE | sed 's|.*version="\(.*\)".*|\1|')
RELEASE=$(grep ' release=' $DOCKERFILE | sed 's|.*release="\(.*\)".*|\1|')
if [ -z ${RELEASE} ]; then
echo -e "Image version: ${VERSION}\n"
else
echo -e "Image version: ${VERSION}-${RELEASE}\n"
fi
DESCRIPTION=$(grep ' description=' $DOCKERFILE \
| sed 's|.*description="\(.*\)".*|\1|')
echo -e "Description:\n${DESCRIPTION}\n"
echo "OpenSCAP packages bundled in the image:"
rpm -qa | grep openscap || true
rpm -qa | grep scap-security-guide || true
openscap-daemon-0.1.10/container/install.sh 0000775 0000000 0000000 00000002644 13237071060 0020636 0 ustar 00root root 0000000 0000000 #!/bin/bash
ETC='/etc/oscapd'
ETC_FILE='config.ini'
HOST='/host'
SELF=$1
echo ""
echo "Installing the configuration file 'openscap' into /etc/atomic.d/. You can now use this scanner with atomic scan with the --scanner openscap command-line option. You can also set 'openscap' as the default scanner in /etc/atomic.conf. To list the scanners you have configured for your system, use 'atomic scan --list'."
echo ""
cp /root/openscap /host/etc/atomic.d/
sed -i "s|\$IMAGE_NAME|${SELF}|" /host/etc/atomic.d/openscap
SCRIPTS="/etc/atomic.d/scripts/"
echo ""
echo "Copying the remediation script 'remediate.py' into $SCRIPTS. You can now remediate images with atomic scan using --remediate command-line option."
echo ""
if [[ ! -d $HOST/$SCRIPTS ]]; then
mkdir -p $HOST/$SCRIPTS
fi
cp /root/remediate.py $HOST/$SCRIPTS
# Check if /etc/oscapd exists on the host
if [[ ! -d ${HOST}/${ETC} ]]; then
mkdir ${HOST}/${ETC}
fi
DATE=$(date +'%Y-%m-%d-%T')
# Check if /etc/oscapd/config.ini exists
if [[ -f ${HOST}/${ETC}/${ETC_FILE} ]]; then
SAVE_NAME=${ETC_FILE}.${DATE}.atomic_save
echo "Saving current ${ETC_FILE} as ${SAVE_NAME}"
mv ${HOST}/${ETC}/${ETC_FILE} ${HOST}/${ETC}/${SAVE_NAME}
fi
# Add config.ini to the host filesystem
echo "Updating ${ETC_FILE} with latest configuration"
cp /root/config.ini ${HOST}/${ETC}/
# Exit Message
echo "Installation complete. You can customize ${ETC}/${ETC_FILE} as needed."
echo ""
openscap-daemon-0.1.10/container/openscap 0000664 0000000 0000000 00000002364 13237071060 0020363 0 ustar 00root root 0000000 0000000 type: scanner
scanner_name: openscap
image_name: $IMAGE_NAME
default_scan: cve
custom_args: ['-v', '/etc/oscapd:/etc/oscapd:ro']
remediation_script: '/etc/atomic.d/scripts/remediate.py'
scans: [
{ name: cve,
args: ['oscapd-evaluate', 'scan', '--no-standard-compliance', '--targets', 'chroots-in-dir:///scanin', '--output', '/scanout', '-j1'],
description: "Performs a CVE scan based on Red Hat relesead CVE OVAL. !WARNING! This CVE is built into container image and it might be out-of-date. Change config.ini to configure the scanner to fetch latest CVE data"},
{ name: standards_compliance,
args: ['oscapd-evaluate', 'scan', '--targets', 'chroots-in-dir:///scanin', '--output', '/scanout', '--no-cve-scan', '-j1'],
description: "!DEPRECATED! Performs scan with Standard Profile, as present in SCAP Security Guide shipped in Red Hat Enterprise Linux"
},
{ name: configuration_compliance,
args: ['oscapd-evaluate', 'scan', '--targets', 'chroots-in-dir:///scanin', '--output', '/scanout', '--no-cve-scan', '--fix_type', 'bash', '-j1'],
description: "Performs a configuration compliance scan according to selected profile from SCAP Security Guide shipped in Red Hat Enterprise Linux."
}
]
openscap-daemon-0.1.10/container/remediate.py 0000775 0000000 0000000 00000012321 13237071060 0021136 0 ustar 00root root 0000000 0000000 #!/usr/bin/python
# Copyright 2017 Red Hat Inc., Durham, North Carolina.
# All Rights Reserved.
#
# openscap-daemon is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 2.1 of the License, or
# (at your option) any later version.
#
# openscap-daemon is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with openscap-daemon. If not, see .
#
# Authors:
# Jan Cerny
# Matus Marhefka
import argparse
import docker
import os
import shutil
import sys
import tempfile
import json
import requests
import re
import xml.etree.ElementTree as ET
def remediate(target_id, results_dir):
# Class docker.Client was renamed to docker.APIClient in
# python-docker-py 2.0.0.
try:
client = docker.APIClient()
except AttributeError:
client = docker.Client()
try:
client.ping()
except requests.exceptions.ConnectionError as e:
raise RuntimeError(
"The Docker daemon does not appear to be running: {}.\n"
.format(e)
)
print("Remediating target {}.".format(target_id))
temp_dir = tempfile.mkdtemp()
fix_script = os.path.join(results_dir, target_id, "fix.sh")
try:
shutil.copy(fix_script, temp_dir)
except IOError as e:
raise RuntimeError(
"Can't find a remediation for given image: {}.\n"
.format(e)
)
# Finds a platform CPE in the ARF results file and based on it selects
# proper package manager and its cleanup command. Applying cleanup command
# after fix script will produce smaller images after remediation. In case
# a platform CPE is not found in the ARF results file cleanup command is
# left empty.
pkg_clean_cmd = ""
arf_results = os.path.join(results_dir, target_id, "arf.xml")
try:
tree = ET.parse(arf_results)
root = tree.getroot()
except FileNotFoundError as e:
raise RuntimeError(e)
try:
ns = "http://checklists.nist.gov/xccdf/1.2"
platform_cpe = root.find(
".//{%s}TestResult/{%s}platform" %(ns, ns)
).attrib['idref']
except AttributeError:
pass
if "fedora" in platform_cpe:
pkg_clean_cmd = "; dnf clean all"
elif "redhat" in platform_cpe:
try:
distro_version = int(re.search("\d+", platform_cpe).group(0))
except AttributeError:
# In case it is not possible to extract rhel version, use yum.
distro_version = 7
if distro_version >= 8:
pkg_clean_cmd = "; dnf clean all"
else:
pkg_clean_cmd = "; yum clean all"
elif "debian" in platform_cpe:
pkg_clean_cmd = "; apt-get clean; rm -rf /var/lib/apt/lists/*"
elif "ubuntu" in platform_cpe:
pkg_clean_cmd = "; apt-get clean; rm -rf /var/lib/apt/lists/*"
try:
dockerfile_path = os.path.join(temp_dir, "Dockerfile")
with open(dockerfile_path, "w") as f:
f.write("FROM " + target_id + "\n")
f.write("COPY fix.sh /\n")
f.write(
"RUN chmod +x /fix.sh; /fix.sh {}\n"
.format(pkg_clean_cmd)
)
try:
build_output_generator = client.build(
path=temp_dir,
# don't use image cache to ensure that original image
# is always remediated
nocache=True,
# remove intermediate containers spawned during build
rm=True
)
except docker.errors.APIError as e:
raise RuntimeError("Docker exception: {}\n".format(e))
build_output = []
for item in build_output_generator:
item_dict = json.loads(item.decode("utf-8"))
if "error" in item_dict:
raise RuntimeError(
"Error during Docker build {}\n".format(item_dict["error"])
)
sys.stdout.write(item_dict["stream"])
build_output.append(item_dict["stream"])
image_id = build_output[-1].split()[-1]
print(
"Successfully built remediated image {} from {}.\n"
.format(image_id, target_id)
)
except RuntimeError as e:
raise RuntimeError(
"Cannot build remediated image from {}: {}\n"
.format(target_id, e)
)
finally:
shutil.rmtree(temp_dir)
if __name__ == "__main__":
parser = argparse.ArgumentParser(description='Remediates container images.')
parser.add_argument("--id", required=True,
help="Image ID")
parser.add_argument("--results_dir", required=True,
help="Directory containing the fix.")
args = parser.parse_args()
try:
remediate(args.id, args.results_dir)
except RuntimeError as e:
sys.stderr.write(str(e))
sys.exit(1)
openscap-daemon-0.1.10/container/run.sh 0000775 0000000 0000000 00000000647 13237071060 0017775 0 ustar 00root root 0000000 0000000 #!/bin/bash
echo ""
if [ ! -e /host/etc/atomic.d/openscap ]; then
echo "No 'openscap' file found in /etc/atomic.d. This image requires you install it with 'atomic install rhel7/openscap'"
else
echo "This container/image is not meant to be run outside of the atomic command. You can use this image by issuing 'atomic scan to scan'. See 'atomic scan --help' for more information."
fi
echo ""
openscap-daemon-0.1.10/generate-dockerfile.py 0000775 0000000 0000000 00000034100 13237071060 0021113 0 ustar 00root root 0000000 0000000 #!/usr/bin/python
import argparse
import collections
import contextlib
INDENTATION = " "
COMMAND_DELIMITER = " \\\n{}&& ".format(INDENTATION)
labels = [
("com.redhat.component", "openscap-docker"),
("name", "openscap"),
("version", "testing"),
("architecture", "x86_64"),
("summary", "OpenSCAP container image that provides security/compliance scanning capabilities for 'atomic scan'"),
("description", "OpenSCAP is an auditing tool that utilizes the Extensible Configuration Checklist Description Format (XCCDF). XCCDF is a standard way of expressing checklist content and defines security checklists."),
("io.k8s.display-name", "OpenSCAP"),
("io.k8s.description", "OpenSCAP is an auditing tool that utilizes the Extensible Configuration Checklist Description Format (XCCDF). XCCDF is a standard way of expressing checklist content and defines security checklists."),
("io.openshift.tags", "security openscap scan"),
("install", "docker run --rm --privileged -v /:/host/ IMAGE sh /root/install.sh IMAGE"),
("run", "docker run -it --rm -v /:/host/ IMAGE sh /root/run.sh"),
("help", "docker run -it --rm IMAGE sh /root/help.sh"),
]
packages = {
"openssh-clients",
"wget",
"bzip2",
}
files = [
("container/install.sh", "/root/"),
("container/run.sh", "/root/"),
("container/openscap", "/root/"),
("container/config.ini", "/root/"),
("container/remediate.py", "/root/"),
("container/help.sh", "/root/"),
("Dockerfile", "/root/"),
]
env_variables = [
("container", "docker")
]
download_cve_feeds_command = [
"wget --no-verbose -P /var/lib/oscapd/cve_feeds/ "
"https://www.redhat.com/security/data/oval/com.redhat.rhsa-RHEL{5,6,7}.xml.bz2",
"bzip2 -dk /var/lib/oscapd/cve_feeds/com.redhat.rhsa-RHEL{5,6,7}.xml.bz2",
"ln -s /var/lib/oscapd/cve_feeds/ /var/tmp/image-scanner",
]
openscap_build_command = [
"git clone -b maint-1.2 https://github.com/OpenSCAP/openscap.git",
"pushd /openscap",
"./autogen.sh",
"./configure --enable-sce --prefix=/usr",
"make -j 4 install",
"popd",
]
ssg_build_command = [
"git clone https://github.com/OpenSCAP/scap-security-guide.git",
"pushd /scap-security-guide/build",
"cmake -DCMAKE_INSTALL_DATADIR=/usr/share ..",
"make -j 4 install",
"popd",
]
daemon_local_build_command = [
"pushd /openscap-daemon",
"python setup.py install",
"popd",
]
def make_parser():
parser = argparse.ArgumentParser(description="Builds an image with OpenSCAP Daemon")
openscap_group = parser.add_mutually_exclusive_group(required=False)
parser.add_argument(
"--base", type=str, default="fedora",
help="Base image name (default is fedora)")
openscap_group.add_argument(
"--openscap-from-git", action="store_true",
default=False, help="Use OpenSCAP from upstream instead of package")
openscap_group.add_argument(
"--openscap-from-koji", type=str,
help="Use OpenSCAP from Koji based on build ID (Fedora only)")
ssg_group = parser.add_mutually_exclusive_group(required=False)
ssg_group.add_argument(
"--ssg-from-koji", type=str,
help="Use SCAP Security Guide from Koji based on build ID (Fedora only)")
ssg_group.add_argument(
"--ssg-from-git", action="store_true", default=False,
help="Use SCAP Security Guide from upstream instead of package")
daemon_group = parser.add_mutually_exclusive_group(required=False)
daemon_group.add_argument(
"--daemon-from-local", action="store_true", default=False,
help="Use OpenSCAP Daemon from local working tree instead of package")
daemon_group.add_argument(
"--daemon-from-koji", type=str,
help="Use OpenSCAP Daemon from Koji based on build ID (Fedora only)")
return parser
def output_baseimage_line(baseimage_name):
return "FROM {0}\n\n".format(baseimage_name)
def output_labels_lines(label_value_pairs):
label_value_lines = [
'{}="{}"'.format(label, value)
for label, value in label_value_pairs]
label_value_lines = ['LABEL'] + label_value_lines
label_statement = " \\\n{}".format(INDENTATION).join(label_value_lines)
return label_statement
def output_env_lines(env_value_pairs):
envvar_value_lines = [
'{}="{}"'.format(envvar, value)
for envvar, value in env_value_pairs]
envvar_value_lines = ['ENV'] + envvar_value_lines
env_statement = " \\\n{}".format(INDENTATION).join(envvar_value_lines)
return env_statement
def _aggregate_by_destination(src_dest_pairs):
destinations = collections.defaultdict(set)
for src, dest in src_dest_pairs:
destinations[dest].add(src)
return destinations
def _output_copy_lines_for_destination(sources, destination):
elements = ['COPY'] + list(sources) + [destination]
if len(sources) == 1:
copy_statement = " ".join(elements)
else:
copy_statement = " \\\n{}".format(INDENTATION).join(elements)
return copy_statement
def output_copy_lines(src_dest_pairs):
destinations = _aggregate_by_destination(src_dest_pairs)
copy_statements = []
for dest, sources in destinations.items():
statement = _output_copy_lines_for_destination(sources, dest)
copy_statements.append(statement)
return "\n".join(copy_statements)
class PackageEnv(object):
def __init__(self):
self.install_command_beginning = None
self.remove_command_beginning = None
self.clear_cache = None
self.builddep_package = None
self.builddep_command_beginning = None
self.additional_repositories_were_enabled = False
def _assert_class_is_complete(self):
assert (
self.install_command_beginning is not None
and self.remove_command_beginning is not None
and self.clear_cache is not None
and self.builddep_package is not None
and self.builddep_command_beginning is not None
), "The class {} is not complete, use a fully defined child."
def install_command_element(self, packages_string):
return "{} {}".format(self.install_command_beginning, packages_string)
def remove_command_element(self, packages_string):
return "{} {}".format(self.remove_command_beginning, packages_string)
def _enable_additional_repositories_command_element(self):
return []
def get_enable_additional_repositories_command_element(self):
if not self.additional_repositories_were_enabled:
return self._enable_additional_repositories_command_element()
else:
return []
self.additional_repositories_were_enabled = True
def _get_install_commands(self, packages_string):
self._assert_class_is_complete()
commands = self.get_enable_additional_repositories_command_element()
commands.append(self.install_command_element(packages_string))
return commands
@contextlib.contextmanager
def install_then_clean_all(self, packages_string):
commands = self._get_install_commands(packages_string)
yield commands
commands.append(self.clear_cache)
@contextlib.contextmanager
def install_then_remove(self, packages_string, clear_cache_afterwards=False):
commands = self._get_install_commands(packages_string)
yield commands
commands.append(self.remove_command_element(packages_string))
if clear_cache_afterwards:
commands.append(self.clear_cache)
class RhelEnv(PackageEnv):
def __init__(self):
super(RhelEnv, self).__init__()
self.install_command_beginning = "yum install -y"
self.remove_command_beginning = "yum remove -y"
self.clear_cache = "yum clean all"
self.builddep_command_beginning = "yum-builddep -y"
self.builddep_package = "yum-utils"
def _enable_additional_repositories_command_element(self):
commands = super(RhelEnv, self)._enable_additional_repositories_command_element()
commands.append(
"rpm -Uvh https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm")
return commands
class FedoraEnv(PackageEnv):
def __init__(self):
super(FedoraEnv, self).__init__()
self.install_command_beginning = "dnf install -y"
self.remove_command_beginning = "dnf remove -y"
self.clear_cache = "dnf clean all"
self.builddep_command_beginning = "dnf -y builddep"
self.builddep_package = "'dnf-command(builddep)'"
def choose_pkg_env_class(baseimage):
if baseimage.startswith("fedora"):
return FedoraEnv
else:
return RhelEnv
class TasksRecorder(object):
def __init__(self, builddep_package):
self.builddep_package = builddep_package
self._build_from_source = []
self._build_commands = []
self._install_from_koji = []
self._koji_commands = []
def merge(self, rhs):
self._build_from_source.extend(rhs._build_from_source)
self._build_commands.extend(rhs._build_commands)
self._koji_commands.extend(rhs._koji_commands)
self._install_from_koji.extend(rhs._install_from_koji)
def build_from_source(self, what, how=None):
packages.add(self.builddep_package)
self._build_from_source.append(what)
if how is not None:
self._build_commands.extend(how)
def install_from_koji(self, what, how=None):
self._install_from_koji.append(what)
if how is not None:
self._koji_commands.extend(how)
def install_build_deps(self, builddep_command):
if len(self._build_from_source) == 0:
return []
build_deps_string = " ".join(self._build_from_source)
command = "{0} {1}".format(builddep_command, build_deps_string)
return [command]
def add_commands_for_building_from_custom_sources(self):
return self._build_commands
def add_koji_commands(self):
return self._koji_commands
def decide_about_getting_openscap(args, pkg_env):
tasks = TasksRecorder(pkg_env.builddep_package)
if args.openscap_from_git:
packages.update({"git", "libtool", "automake"})
tasks.build_from_source("openscap", openscap_build_command)
elif args.openscap_from_koji is not None:
packages.add("koji")
openscap_koji_command = [
"koji download-build -a x86_64 {0}".format(args.openscap_from_koji),
"koji download-build -a noarch {0}".format(args.openscap_from_koji),
pkg_env.install_command_element(
"openscap-[0-9]*.rpm openscap-scanner*.rpm "
"openscap-utils*.rpm openscap-containers*.rpm"),
"rm -f openscap-*.rpm",
]
tasks.install_from_koji("openscap", openscap_koji_command)
else:
packages.add("openscap-utils")
return tasks
def decide_about_getting_ssg(args, pkg_env):
tasks = TasksRecorder(pkg_env.builddep_package)
if args.ssg_from_git:
packages.add("git")
tasks.build_from_source("scap-security-guide", ssg_build_command)
elif args.ssg_from_koji is not None:
packages.add("koji")
ssg_koji_command = [
"koji download-build -a noarch {0}".format(args.ssg_from_koji),
pkg_env.install_command_element("scap-security-guide-[0-9]*.rpm"),
"rm -f scap-security-guide*.rpm",
]
tasks.install_from_koji("scap-security-guide", ssg_koji_command)
else:
packages.add("scap-security-guide")
return tasks
def decide_about_getting_openscap_daemon(args, pkg_env):
tasks = TasksRecorder(pkg_env.builddep_package)
if args.daemon_from_local:
tasks.build_from_source("openscap-daemon", daemon_local_build_command)
files.append((".", "/openscap-daemon/"))
elif args.daemon_from_koji is not None:
packages.add("koji")
daemon_koji_command = [
"koji download-build -a noarch {0}".format(args.daemon_from_koji),
pkg_env.install_command_element("openscap-daemon*.rpm"),
"rm -f openscap-daemon*.rpm",
]
tasks.install_from_koji("openscap-daemon", daemon_koji_command)
else:
packages.add("openscap-daemon")
return tasks
def output_run_directive(commands):
commands_string = COMMAND_DELIMITER.join(["true"] + commands + ["true"])
return "RUN {}\n\n".format(commands_string)
def main():
parser = make_parser()
args = parser.parse_args()
pkg_env = choose_pkg_env_class(args.base)()
if (not isinstance(pkg_env, FedoraEnv)) and (
args.openscap_from_koji is not None
or args.ssg_from_koji is not None
or args.daemon_from_koji is not None):
parser.error("Koji builds can be used only with fedora base image")
with open("Dockerfile", "w") as f:
# write out the Dockerfile
f.write(output_baseimage_line(args.base))
f.write(output_labels_lines(labels))
f.write("\n\n")
f.write(output_env_lines(env_variables))
f.write("\n\n")
install_steps = decide_about_getting_openscap(args, pkg_env)
install_steps.merge(decide_about_getting_ssg(args, pkg_env))
install_steps.merge(decide_about_getting_openscap_daemon(args, pkg_env))
# inject files
f.write(output_copy_lines(files))
f.write("\n\n")
run_commands = []
packages_string = " ".join(packages)
with pkg_env.install_then_clean_all(packages_string) as commands:
commands.extend(
install_steps.install_build_deps(pkg_env.builddep_command_beginning))
commands.extend(
install_steps.add_commands_for_building_from_custom_sources())
commands.extend(
install_steps.add_koji_commands())
run_commands.extend(commands)
f.write(output_run_directive(run_commands))
f.write(output_run_directive(download_cve_feeds_command))
# add CMD instruction to the Dockerfile, including a comment
f.write("# It doesn't matter what is in the line below, atomic will change the CMD\n")
f.write("# before running it\n")
f.write('CMD ["/root/run.sh"]\n')
if __name__ == "__main__":
main()
openscap-daemon-0.1.10/man/ 0000775 0000000 0000000 00000000000 13237071060 0015414 5 ustar 00root root 0000000 0000000 openscap-daemon-0.1.10/man/oscapd-cli.8 0000664 0000000 0000000 00000001657 13237071060 0017534 0 ustar 00root root 0000000 0000000 .TH OSCAPD-CLI "8" "January 2016" "Red Hat" "System Administration Utilities"
.SH NAME
oscapd-cli \- OpenSCAP-daemon command line interface
.SH SYNOPSIS
\fBoscapd-cli\fR [\fI-h\fR] {eval,scan,task,task-create,status,result}
.SS "positional arguments:"
.IP
{eval,task,task\-create,status,result}
.TP
eval
Interactive one\-off evaluation of any target supported
by OpenSCAP Daemon
.TP
task
Show info about tasks that have already been defined.
Perform operations on already defined tasks.
.TP
task\-create
Create new task.
.TP
status
Displays status, tasks that are planned and tasks that
are being evaluated.
.TP
result
Displays info about past results
.SS "optional arguments:"
.TP
\fB\-h\fR, \fB\-\-help\fR
show this help message and exit
.TP
\fB\-v\fR, \fB\-\-version\fR
show program's version number and exit
.SH AUTHORS
.nf
Martin Preisler
Brent Baude
Zbynek Moravec
.fi
openscap-daemon-0.1.10/man/oscapd-evaluate.8 0000664 0000000 0000000 00000002224 13237071060 0020562 0 ustar 00root root 0000000 0000000 .TH OSCAPD-EVALUATE "8" "March 2016" "Red Hat" "System Administration Utilities"
.SH NAME
oscapd-evaluate \- OpenSCAP-daemon one-off non-daemonized evaluator
.SH SYNOPSIS
\fBoscapd-evaluate\fR [\fI-h\fR] [\fI-v\fR] [\fI--verbose\fR] {config,xml,spec,target-cpes,target-profiles,scan}
.SS "positional arguments:"
.IP
{config,xml,spec,target\-cpes,target\-profiles,scan}
.TP
config
Generate default config file for oscapd and oscapd-evaluate.
.TP
xml
Evaluates Evaluation Spec from given XML input.
.TP
spec
Constructs Evaluation Spec from given parameters and evaluates it or outputs its XML.
.TP
target\-cpes
Detects CPEs of given target.
.TP
target\-profiles
Detects configuration compliance profiles from SCAP Security Guide applicable on given target.
.TP
scan
Performs CVE scan and/or configuration compliance evaluation of given targets. Outputs raw XML results and a summary JSON output.
.SS "optional arguments:"
.TP
\fB\-h\fR, \fB\-\-help\fR
show this help message and exit
.TP
\fB\-v\fR, \fB\-\-version\fR
show program's version number and exit
.TP
\fB\-\-verbose\fR
Show debugging logging messages.
.SH AUTHORS
.nf
Martin Preisler
.fi
openscap-daemon-0.1.10/man/oscapd.8 0000664 0000000 0000000 00000001371 13237071060 0016760 0 ustar 00root root 0000000 0000000 .TH OSCAPD "8" "Jan 2016" "Red Hat" "System Administration Utilities"
.SH NAME
oscapd \- OpenSCAP-daemon service
.SH SYNOPSIS
\fBoscapd\fR [\fI-h\fR] [\fI-v\fR] [\fI--verbose\fR]
.SH DESCRIPTION
\fBoscapd\fP is the central executable of OpenSCAP-daemon. When started it provides a dbus interface that other tools (such as oscapd-cli and atomic) can interact with.
In production environments it is not recommended to start the service directly, use \fBsystemctl start oscapd\fP instead.
.SH GENERAL OPTIONS
.TP
\fB\-v, \-\-version\fR
Show version.
.TP
\fB\-h, \-\-help\fR
Help screen.
.TP
\fB\-\-verbose\fR
Start in verbose mode.
.SH AUTHORS
.nf
Martin Preisler
Brent Baude
Zbynek Moravec
.fi
openscap-daemon-0.1.10/openscap_daemon/ 0000775 0000000 0000000 00000000000 13237071060 0017774 5 ustar 00root root 0000000 0000000 openscap-daemon-0.1.10/openscap_daemon/__init__.py 0000664 0000000 0000000 00000001736 13237071060 0022114 0 ustar 00root root 0000000 0000000 # Copyright 2015 Red Hat Inc., Durham, North Carolina.
# All Rights Reserved.
#
# openscap-daemon is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 2.1 of the License, or
# (at your option) any later version.
#
# openscap-daemon is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
# You should have received a copy of the GNU Lesser General Public License
# along with openscap-daemon. If not, see .
#
# Authors:
# Martin Preisler
from openscap_daemon.evaluation_spec import EvaluationSpec
from openscap_daemon.system import System
from openscap_daemon.task import Task
__all__ = ["EvaluationSpec", "System", "Task"]
openscap-daemon-0.1.10/openscap_daemon/async.py 0000664 0000000 0000000 00000012233 13237071060 0021464 0 ustar 00root root 0000000 0000000 # Copyright 2015 Red Hat Inc., Durham, North Carolina.
# All Rights Reserved.
#
# openscap-daemon is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 2.1 of the License, or
# (at your option) any later version.
#
# openscap-daemon is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
# You should have received a copy of the GNU Lesser General Public License
# along with openscap-daemon. If not, see .
#
# Authors:
# Martin Preisler
import threading
import logging
import time
import sys
import traceback
if sys.version_info < (3,):
import Queue as queue
else:
import queue
class Status(object):
"""This enum describes status of async actions. Calls can be pending,
processing or done. When actions are done they are waiting for the caller
to collect the results and then they are deleted entirely.
"""
PENDING = 0
PROCESSING = 1
#DONE = 2
UNKNOWN = 3
@staticmethod
def from_string(status):
if status == "pending":
return Status.PENDING
elif status == "processing":
return Status.PROCESSING
#elif status == "done":
# return Status.DONE
return Status.UNKNOWN
@staticmethod
def to_string(status):
if status == Status.PENDING:
return "pending"
elif status == Status.PROCESSING:
return "processing"
#elif status == Status.DONE:
# return "done"
return "unknown"
class AsyncAction(object):
def __init__(self):
self.token = -1
self.status = Status.UNKNOWN
def run(self):
pass
def __str__(self):
return "Unknown action"
class AsyncManager(object):
"""Allows the user to enqueue asynchronous actions, gives the user a token
they can poll as often as they like and check status of the actions.
This is necessary to run many tasks in parallel and is necessary to make
the dbus API work smoothly. User calling dbus methods doesn't expect them
to take hours to finish. The calls themselves need to finish in seconds.
To make it work with OpenSCAP evaluations that regularly take tens of
minutes we create a task by the dbus call and then poll it.
"""
def _worker_main(self, worker_id):
while True:
priority, action = self.queue.get(True)
logging.debug(
"Worker %i starting action from the priority queue. "
"priority=%i, token=%i, action='%s'",
worker_id, priority, action.token, action
)
action.status = Status.PROCESSING
try:
action.run()
except BaseException as e:
logging.error("Action '%s' threw an exception that hasn't been "
"caught. This is most likely a bug, please"
"report it. %s" % (action, e))
exc_type, exc_value, tb = sys.exc_info()
traceback.print_tb(tb, file=sys.stderr)
self.queue.task_done()
with self.actions_lock:
del self.actions[action.token]
time.sleep(self.sleep_time)
def __init__(self, workers=0):
self.queue = queue.PriorityQueue()
self.sleep_time = 1
if workers == 0:
try:
import multiprocessing
workers = multiprocessing.cpu_count()
except NotImplementedError:
workers = 4
self.workers = []
for i in range(workers):
worker = threading.Thread(
name="AsyncManager worker (%i out of %i)" % (i, workers),
target=AsyncManager._worker_main,
args=(self, i)
)
worker.daemon = True
self.workers.append(worker)
worker.start()
self.last_token = 0
self.actions = {}
self.actions_lock = threading.Lock()
logging.debug("Initialized AsyncManager, %i workers",
len(self.workers))
def _allocate_token(self):
with self.actions_lock:
ret = self.last_token + 1
self.last_token = ret
assert(ret not in self.actions)
return ret
def enqueue(self, action, priority=0):
action.token = self._allocate_token()
action.status = Status.PENDING
with self.actions_lock:
self.actions[action.token] = action
self.queue.put((priority, action))
logging.debug("AsyncManager enqueued action '%s' with token %i",
action, action.token)
return action.token
def get_status(self):
ret = []
for token, action in self.actions.items():
ret.append((token, str(action), action.status))
return ret
def cancel(self, token):
raise NotImplementedError()
openscap-daemon-0.1.10/openscap_daemon/cli_helpers.py 0000664 0000000 0000000 00000024603 13237071060 0022644 0 ustar 00root root 0000000 0000000 # Copyright 2015 Red Hat Inc., Durham, North Carolina.
# All Rights Reserved.
#
# openscap-daemon is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 2.1 of the License, or
# (at your option) any later version.
#
# openscap-daemon is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
# You should have received a copy of the GNU Lesser General Public License
# along with openscap-daemon. If not, see .
#
# Authors:
# Martin Preisler
import sys
import os.path
import logging
from openscap_daemon import evaluation_spec
from xml.etree import cElementTree as ElementTree
if sys.version_info < (3,):
py2_raw_input = raw_input
else:
py2_raw_input = input
def print_table(table, first_row_header=True):
"""Takes given table - list of lists - and prints it as a table, using
ASCII characters for formatting.
The first row is formatted as a header.
I did consider using some python package or module to do this but that
would introduce additional dependencies. The functionality we need is simple
enough to write it ourselves.
"""
column_max_sizes = {}
for row in table:
for i, column_cell in enumerate(row):
if i not in column_max_sizes:
column_max_sizes[i] = 0
column_max_sizes[i] = \
max(column_max_sizes[i], len(str(column_cell)))
total_width = len(" | ".join(
[" " * max_size for max_size in column_max_sizes.values()]
))
start_row = 0
if first_row_header:
assert(len(table) > 0)
print("-+-".join(
"-" * max_size for max_size in column_max_sizes.values())
)
print(" | ".join(
[str(cell).ljust(column_max_sizes[table[start_row].index(cell)])
for cell in table[start_row]]
))
print("-+-".join(
"-" * max_size for max_size in column_max_sizes.values())
)
start_row += 1
for row in table[start_row:]:
print(" | ".join(
[str(cell).ljust(column_max_sizes[row.index(cell)])
for cell in row]
))
def cli_create_evaluation_spec(dbus_iface):
"""Interactively create EvaluationSpec and return it. Returns None if user
cancels the action.
"""
print("Creating EvaluationSpec interactively...")
print("")
try:
target = py2_raw_input("Target (empty for localhost): ")
if not target:
target = "localhost"
print("Found the following SCAP Security Guide content: ")
ssg_choices = dbus_iface.GetSSGChoices()
for i, ssg_choice in enumerate(ssg_choices):
print("\t%i: %s" % (i + 1, ssg_choice))
input_file = None
input_ssg_choice = py2_raw_input(
"Choose SSG content by number (empty for custom content): ")
if not input_ssg_choice:
input_file = py2_raw_input("Input file (absolute path): ")
else:
input_file = ssg_choices[int(input_ssg_choice) - 1]
input_file = os.path.abspath(input_file)
tailoring_file = py2_raw_input(
"Tailoring file (absolute path, empty for no tailoring): ")
if tailoring_file in [None, ""]:
tailoring_file = ""
else:
tailoring_file = os.path.abspath(tailoring_file)
print("Found the following possible profiles: ")
profile_choices = dbus_iface.GetProfileChoicesForInput(
input_file, tailoring_file
)
for i, (key, value) in enumerate(profile_choices.items()):
print("\t%i: %s (id='%s')" % (i + 1, value, key))
profile_choice = py2_raw_input(
"Choose profile by number (empty for (default) profile): ")
if profile_choice is not None:
profile = list(profile_choices.keys())[int(profile_choice) - 1]
else:
profile = None
online_remediation = False
if py2_raw_input("Online remediation (1, y or Y for yes, else no): ") \
in ["1", "y", "Y"]:
online_remediation = True
ret = evaluation_spec.EvaluationSpec()
ret.target = target
ret.input_.set_file_path(input_file)
if tailoring_file not in [None, ""]:
ret.tailoring.set_file_path(tailoring_file)
ret.profile_id = profile
ret.online_remediation = online_remediation
return ret
except KeyboardInterrupt:
return None
def preprocess_targets(targets, output_dir_map):
"""The main goal of this function is to expand chroots-in-dir:// to a list
of chroot:// targets. chroots-in-dir is a convenience function that the rest
of the OpenSCAP-daemon API doesn't know about.
The output_dir_map maps the processed targets to directories from
chroots-in-dir expansion.
"""
ret = []
for target in targets:
if target.startswith("chroots-in-dir://"):
logging.debug("Expanding target '%s'...", target)
dir_ = os.path.abspath(target[len("chroots-in-dir://"):])
for chroot in os.listdir(dir_):
full_path = os.path.abspath(os.path.join(dir_, chroot))
if not os.path.isdir(full_path):
continue
expanded_target = "chroot://" + full_path
logging.debug(" ... '%s'", expanded_target)
ret.append(expanded_target)
output_dir_map[expanded_target] = chroot
logging.debug("Finished expanding target '%s'.", target)
else:
ret.append(target)
return ret
def summarize_cve_results(oval_source, result_list):
"""Takes given OVAL source, assuming it is CVE feed OVAL results source,
and parses it. Each definition that has result 'true' is added to
result_list.
This is used to produce JSON output for atomic scan in
`oscapd-evaluate scan`.
"""
namespaces = {
"ovalres": "http://oval.mitre.org/XMLSchema/oval-results-5",
"ovaldef": "http://oval.mitre.org/XMLSchema/oval-definitions-5"
}
oval_root = ElementTree.fromstring(oval_source.encode("utf-8"))
for result in oval_root.findall(
"ovalres:results/ovalres:system/"
"ovalres:definitions/*[@result='true']",
namespaces):
definition_id = result.get("definition_id")
assert(definition_id is not None)
definition_meta = oval_root.find(
"./ovaldef:oval_definitions/ovaldef:definitions/*[@id='%s']/"
"ovaldef:metadata" % (definition_id),
namespaces
)
assert(definition_meta is not None)
title = definition_meta.find("ovaldef:title", namespaces)
# there can only be one RHSA per definition
rhsa = definition_meta.find("ovaldef:reference[@source='RHSA']",
namespaces)
# there can be one or more CVEs per definition
cves = definition_meta.findall("ovaldef:reference[@source='CVE']",
namespaces)
description = definition_meta.find("ovaldef:description", namespaces)
severity = definition_meta.find("ovaldef:advisory/ovaldef:severity",
namespaces)
result_json = {}
result_json["Title"] = title.text if title is not None else "unknown"
result_json["Description"] = \
description.text if description is not None else "unknown"
result_json["Severity"] = \
severity.text if severity is not None else "unknown"
custom = {}
if rhsa is not None:
custom["RHSA ID"] = rhsa.get("ref_id", "unknown")
custom["RHSA URL"] = rhsa.get("ref_url", "unknown")
if len(cves) > 0:
custom["Associated CVEs"] = []
for cve in cves:
custom["Associated CVEs"].append(
{"CVE ID": cve.get("ref_id", "unknown"),
"CVE URL": cve.get("ref_url", "unknown")}
)
result_json["Custom"] = custom
result_list.append(result_json)
def summarize_standard_compliance_results(arf_source, result_list, profile):
"""Takes given ARF XML source and parses it. Each Rule that doesn't have
result 'pass', 'fixed', 'informational', 'notselected' or 'notapplicable'
is added to result_list.
This is used to produce JSON output for atomic scan in
`oscapd-evaluate scan`.
"""
namespaces = {
"cdf": "http://checklists.nist.gov/xccdf/1.2",
}
arf_root = ElementTree.fromstring(arf_source.encode("utf-8"))
test_result = arf_root.find(
".//cdf:TestResult[@id='%s']" %
# this ID prefix is hardcoded in oscap
("xccdf_org.open-scap_testresult_" + profile), namespaces
)
benchmark = arf_root.find(".//cdf:Benchmark", namespaces)
for rule_result in test_result.findall("./cdf:rule-result", namespaces):
result = rule_result.find("cdf:result", namespaces).text
if result in ["pass", "fixed", "informational", "notselected",
"notapplicable"]:
continue
rule_id = rule_result.get("idref")
assert(rule_id is not None)
rule = benchmark.find(".//cdf:Rule[@id='%s']" % (rule_id), namespaces)
assert(rule is not None)
title = rule.find("cdf:title", namespaces)
description = rule.find("cdf:description", namespaces)
severity = rule.get("severity", "Unknown")
if severity in "low":
severity = "Low"
elif severity == "medium":
severity = "Moderate"
elif severity == "high":
severity = "Important"
else: # "info", a valid XCCDF severity falls here
severity = "Unknown"
result_json = {}
result_json["Title"] = title.text if title is not None else "unknown"
if description is None:
result_json["Description"] = "unknown"
else:
result_json["Description"] = ElementTree.tostring(description, method="text").decode("utf-8")
result_json["Severity"] = severity
result_json["Custom"] = {"XCCDF result": result}
result_list.append(result_json)
openscap-daemon-0.1.10/openscap_daemon/compat.py 0000664 0000000 0000000 00000003277 13237071060 0021642 0 ustar 00root root 0000000 0000000 # Copyright 2015 Red Hat Inc., Durham, North Carolina.
# All Rights Reserved.
#
# openscap-daemon is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 2.1 of the License, or
# (at your option) any later version.
#
# openscap-daemon is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
# You should have received a copy of the GNU Lesser General Public License
# along with openscap-daemon. If not, see .
#
# Authors:
# Martin Preisler
import subprocess
def subprocess_check_output(*popenargs, **kwargs):
# Backport of subprocess.check_output taken from
# https://gist.github.com/edufelipe/1027906
#
# Originally from Python 2.7 stdlib under PSF, compatible with LGPL2+
# Copyright (c) 2003-2005 by Peter Astrand
# Changes by Eduardo Felipe
process = subprocess.Popen(stdout=subprocess.PIPE, *popenargs, **kwargs)
output, unused_err = process.communicate()
retcode = process.poll()
if retcode:
cmd = kwargs.get("args")
if cmd is None:
cmd = popenargs[0]
error = subprocess.CalledProcessError(retcode, cmd)
error.output = output
raise error
return output
if hasattr(subprocess, "check_output"):
# if available we just use the real function
subprocess_check_output = subprocess.check_output
__all__ = ["subprocess_check_output"]
openscap-daemon-0.1.10/openscap_daemon/config.py 0000664 0000000 0000000 00000046040 13237071060 0021617 0 ustar 00root root 0000000 0000000 # Copyright 2015 Red Hat Inc., Durham, North Carolina.
# All Rights Reserved.
#
# openscap-daemon is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 2.1 of the License, or
# (at your option) any later version.
#
# openscap-daemon is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
# You should have received a copy of the GNU Lesser General Public License
# along with openscap-daemon. If not, see .
#
# Authors:
# Martin Preisler
try:
import ConfigParser as configparser
except ImportError:
# ConfigParser has been renamed to configparser in python3
import configparser
import os
import os.path
import logging
import shutil
import inspect
from openscap_daemon import cve_feed_manager
class Configuration(object):
def __init__(self):
self.config_file = None
# General section
self.tasks_dir = os.path.join("/", "var", "lib", "oscapd", "tasks")
self.results_dir = os.path.join("/", "var", "lib", "oscapd", "results")
self.work_in_progress_dir = \
os.path.join("/", "var", "lib", "oscapd", "work_in_progress")
self.cve_feeds_dir = \
os.path.join("/", "var", "lib", "oscapd", "cve_feeds")
self.jobs = 4
# -2 means never prune old results
self.max_results_to_keep = -2
# Tools section
self.oscap_path = ""
self.oscap_ssh_path = ""
self.oscap_vm_path = ""
self.oscap_docker_path = ""
self.oscap_chroot_path = ""
self.container_support = True
# Content section
self.cpe_oval_path = ""
self.ssg_path = ""
# CVEScanner section
self.fetch_cve = True
# empty URL means default URL and is a valid value
self.fetch_cve_url = ""
self.fetch_cve_timeout = 10*60
self.cve_feed_manager = cve_feed_manager.CVEFeedManager()
def autodetect_tool_paths(self):
"""This will try a few well-known public paths and change the paths
accordingly. This method will only try to autodetect paths that are
empty!
Auto-detection is implemented for oscap and various related tools and
SCAP Security Guide content.
"""
def autodetect_tool_path(possible_names, possible_prefixes=None):
if possible_prefixes is None:
possible_prefixes = (
os.path.join("/", "usr", "bin"),
os.path.join("/", "usr", "local", "bin"),
os.path.join("/", "opt", "openscap", "bin")
)
for prefix in possible_prefixes:
for name in possible_names:
full_path = os.path.join(prefix, name)
if os.path.isfile(full_path) and \
os.access(full_path, os.X_OK):
logging.info("Autodetected \"%s\" in path \"%s\".",
name, full_path)
return full_path
logging.info(
"Failed to autodetect tool with name %s in prefixes %s.",
" or ".join(possible_names), ", ".join(possible_prefixes)
)
return ""
if self.oscap_path == "":
self.oscap_path = autodetect_tool_path(["oscap", "oscap.exe"])
if self.oscap_ssh_path == "":
self.oscap_ssh_path = autodetect_tool_path(["oscap-ssh"])
if self.oscap_vm_path == "":
self.oscap_vm_path = autodetect_tool_path(["oscap-vm"])
if self.oscap_docker_path == "":
self.oscap_docker_path = autodetect_tool_path(["oscap-docker"])
if self.oscap_chroot_path == "":
self.oscap_chroot_path = autodetect_tool_path(["oscap-chroot"])
if self.container_support:
# let's verify that we really can enable container support
self.container_support = False
try:
__import__("docker")
try:
from Atomic.mount import DockerMount
if "mnt_mkdir" not in \
inspect.getargspec(DockerMount.__init__).args:
logging.error(
"\"Atomic.mount.DockerMount\" has been successfully"
" imported but it doesn't support the mnt_mkdir "
"argument. Please upgrade your Atomic installation "
"to 1.4 or higher. Direct container scanning via "
"oscap-docker will be disabled."
)
logging.info("Successfully imported 'docker' and "
"'Atomic.mount', container scanning enabled.")
self.container_support = True
except ImportError:
logging.warning("Can't import the 'Atomic.mount' package. "
"Direct container scanning via "
"oscap-docker will be disabled.")
except ImportError:
logging.warning("Can't import the 'docker' package. Direct "
"container scanning via oscap-docker will be "
"disabled.")
def autodetect_content_paths(self):
def autodetect_content_path(possible_paths, possible_filenames):
for path in possible_paths:
if not os.path.isdir(path):
continue
for filename in possible_filenames:
full_path = os.path.join(path, filename)
if os.path.exists(full_path):
logging.info("Autodetected SCAP content at \"%s\".",
full_path)
return full_path
logging.info(
"Failed to autodetect SCAP content in paths %s with filenames "
"%s.", ", ".join(possible_paths), ", ".join(possible_filenames)
)
return ""
if self.cpe_oval_path == "":
self.cpe_oval_path = autodetect_content_path([
os.path.join("/", "usr", "share", "openscap", "cpe"),
os.path.join("/", "usr", "local", "share", "openscap", "cpe"),
os.path.join("/", "opt", "openscap", "cpe")],
["openscap-cpe-oval.xml"]
)
def autodetect_content_dir(possible_paths):
for path in possible_paths:
if os.path.isdir(path):
logging.info("Autodetected SCAP content in path \"%s\".",
path)
return path
logging.info(
"Failed to autodetect SCAP content in paths %s.",
", ".join(possible_paths)
)
return ""
if self.ssg_path == "":
self.ssg_path = autodetect_content_dir([
os.path.join("/", "usr", "share", "xml", "scap", "ssg", "content"),
os.path.join("/", "usr", "local", "share", "xml", "scap", "ssg", "content"),
os.path.join("/", "opt", "ssg", "content")
])
def load(self, config_file):
config = configparser.SafeConfigParser()
config.read(config_file)
base_dir = os.path.dirname(config_file)
def absolutize(path):
path = str(path)
if path == "" or os.path.isabs(path):
return path
return os.path.normpath(os.path.join(base_dir, path))
# General section
try:
self.tasks_dir = absolutize(config.get("General", "tasks-dir"))
except (configparser.NoOptionError, configparser.NoSectionError):
pass
try:
self.results_dir = absolutize(config.get("General", "results-dir"))
except (configparser.NoOptionError, configparser.NoSectionError):
pass
try:
self.work_in_progress_dir = absolutize(config.get("General", "work-in-progress-dir"))
except (configparser.NoOptionError, configparser.NoSectionError):
pass
try:
self.cve_feeds_dir = absolutize(config.get("General", "cve-feeds-dir"))
except (configparser.NoOptionError, configparser.NoSectionError):
pass
try:
self.jobs = config.getint("General", "jobs")
except (configparser.NoOptionError, configparser.NoSectionError):
pass
try:
self.max_results_to_keep = config.getint("General", "max-results-to-keep")
except (configparser.NoOptionError, configparser.NoSectionError):
pass
# Tools section
try:
self.oscap_path = absolutize(config.get("Tools", "oscap"))
except (configparser.NoOptionError, configparser.NoSectionError):
pass
try:
self.oscap_ssh_path = absolutize(config.get("Tools", "oscap-ssh"))
except (configparser.NoOptionError, configparser.NoSectionError):
pass
try:
self.oscap_vm_path = absolutize(config.get("Tools", "oscap-vm"))
except (configparser.NoOptionError, configparser.NoSectionError):
pass
try:
self.oscap_docker_path = absolutize(config.get("Tools", "oscap-docker"))
except (configparser.NoOptionError, configparser.NoSectionError):
pass
try:
self.oscap_chroot_path = absolutize(config.get("Tools", "oscap-chroot"))
except (configparser.NoOptionError, configparser.NoSectionError):
pass
try:
self.container_support = config.get("Tools", "container-support") \
not in ["no", "0", "false", "False"]
except (configparser.NoOptionError, configparser.NoSectionError):
pass
# Content section
try:
self.cpe_oval_path = absolutize(config.get("Content", "cpe-oval"))
except (configparser.NoOptionError, configparser.NoSectionError):
pass
try:
self.ssg_path = absolutize(config.get("Content", "ssg"))
except (configparser.NoOptionError, configparser.NoSectionError):
pass
# CVEScanner section
try:
self.fetch_cve = config.get("CVEScanner", "fetch-cve") not in \
["no", "0", "false", "False"]
except (configparser.NoOptionError, configparser.NoSectionError):
pass
try:
self.fetch_cve_url = config.get("CVEScanner", "fetch-cve-url")
except (configparser.NoOptionError, configparser.NoSectionError):
pass
try:
self.fetch_cve_timeout = config.getint("CVEScanner", "fetch-cve-timeout")
except (configparser.NoOptionError, configparser.NoSectionError):
pass
self.config_file = config_file
def save_as(self, config_file):
config = configparser.SafeConfigParser()
config.add_section("General")
config.set("General", "tasks-dir", str(self.tasks_dir))
config.set("General", "results-dir", str(self.results_dir))
config.set("General", "work-in-progress-dir", str(self.work_in_progress_dir))
config.set("General", "cve-feeds-dir", str(self.cve_feeds_dir))
config.set("General", "jobs", str(self.jobs))
config.set("General", "max-results-to-keep", str(self.max_results_to_keep))
config.add_section("Tools")
config.set("Tools", "oscap", str(self.oscap_path))
config.set("Tools", "oscap-ssh", str(self.oscap_ssh_path))
config.set("Tools", "oscap-vm", str(self.oscap_vm_path))
config.set("Tools", "oscap-docker", str(self.oscap_docker_path))
config.set("Tools", "oscap-chroot", str(self.oscap_chroot_path))
config.set("Tools", "container-support",
"yes" if self.container_support else "no")
config.add_section("Content")
config.set("Content", "cpe-oval", str(self.cpe_oval_path))
config.set("Content", "ssg", str(self.ssg_path))
config.add_section("CVEScanner")
config.set("CVEScanner", "fetch-cve", "yes" if self.fetch_cve else "no")
config.set("CVEScanner", "fetch-cve-url", str(self.fetch_cve_url))
config.set("CVEScanner", "fetch-cve-timeout",
str(self.fetch_cve_timeout))
if hasattr(config_file, "write"):
# config_file is an already opened file, let's use it like one
config.write(config_file)
else:
# treat config_file as a path
with open(config_file, "w") as f:
config.write(f)
self.config_file = config_file
def save(self):
self.save_as(self.config_file)
def prepare_dirs(self, cleanup_allowed=True):
if not os.path.exists(self.tasks_dir):
logging.info(
"Creating tasks directory at '%s' because it didn't exist.",
self.tasks_dir
)
os.makedirs(self.tasks_dir, 0o750)
if not os.path.exists(self.results_dir):
logging.info(
"Creating results directory at '%s' because it didn't exist.",
self.results_dir
)
os.makedirs(self.results_dir)
if not os.path.exists(self.work_in_progress_dir):
logging.info(
"Creating results work in progress directory at '%s' because "
"it didn't exist.", self.work_in_progress_dir
)
os.makedirs(self.work_in_progress_dir)
if not os.path.exists(self.cve_feeds_dir):
logging.info(
"Creating CVE feeds directory at '%s' because it didn't exist.",
self.cve_feeds_dir
)
os.makedirs(self.cve_feeds_dir)
if cleanup_allowed:
for dir_ in os.listdir(self.work_in_progress_dir):
full_path = os.path.join(self.work_in_progress_dir, dir_)
logging.info(
"Found '%s' in work_in_progress results directory, full "
"path is '%s'. This is most likely a left-over from an "
"earlier crash. Deleting...", dir_, full_path
)
try:
shutil.rmtree(full_path)
except OSError as e:
if e.errno == 13: # permission denied
logging.warning(
"Tried to delete '%s' to clean-up but permission "
"was denied. Skipping...", full_path)
else:
raise
def sanity_check(self):
def sanity_check_dir(path, config_file_entry, desc, allow_empty=False):
if allow_empty and path == "":
return
if not os.path.exists(path):
raise RuntimeError(
"Path '%s' given for the %s folder (config file entry: %s) "
"doesn't exist." % (path, desc, config_file_entry)
)
if not os.path.isdir(path):
raise RuntimeError(
"Path '%s' given for the %s folder (config file entry: %s) "
"is not a directory." % (path, desc, config_file_entry)
)
def sanity_check_file(path, config_file_entry, desc, allow_empty=False):
if allow_empty and path == "":
return
if not os.path.exists(path):
raise RuntimeError(
"Path '%s' given for the %s file (config file entry: %s) "
"doesn't exist." % (path, desc, config_file_entry)
)
if not os.path.isfile(path):
raise RuntimeError(
"Path '%s' given for the %s file (config file entry: %s) "
"is not a file." % (path, desc, config_file_entry)
)
sanity_check_dir(self.tasks_dir,
"Tasks configuration storage", "tasks-dir")
sanity_check_dir(self.results_dir, "Results storage", "results-dir")
sanity_check_dir(self.work_in_progress_dir,
"Temporary storage / work in progress",
"work-in-progress-dir")
sanity_check_dir(self.cve_feeds_dir,
"CVE feeds storage", "cve-feeds-dir")
# self.jobs
# self.max_results_to_keep
# self.oscap_path = ""
# self.oscap_ssh_path = ""
# self.oscap_vm_path = ""
# self.oscap_docker_path = ""
# self.oscap_chroot_path = ""
# self.container_support = True
sanity_check_file(self.cpe_oval_path, "CPE OVAL", "cpe-oval")
sanity_check_dir(self.ssg_path, "SCAP Security Guide", "ssg", True)
# self.fetch_cve = True
# self.fetch_cve_url = ""
# self.fetch_cve_timeout = 10*60
def get_cve_feed(self, cpe_ids):
self.cve_feed_manager.dest = self.cve_feeds_dir
if self.fetch_cve_url != "":
self.cve_feed_manager.url = self.fetch_cve_url
else:
self.cve_feed_manager.url = \
cve_feed_manager.CVEFeedManager.default_url
self.cve_feed_manager.fetch_enabled = self.fetch_cve
self.cve_feed_manager.fetch_timeout = self.fetch_cve_timeout
return self.cve_feed_manager.get_cve_feed(cpe_ids)
def get_ssg_sds(self, cpe_ids):
def get_ssg_sds_path(cpe_ids):
if "cpe:/o:redhat:enterprise_linux:7" in cpe_ids:
return os.path.join(self.ssg_path, "ssg-rhel7-ds.xml")
if "cpe:/o:redhat:enterprise_linux:6" in cpe_ids:
return os.path.join(self.ssg_path, "ssg-rhel6-ds.xml")
if "cpe:/o:redhat:enterprise_linux:5" in cpe_ids:
return os.path.join(self.ssg_path, "ssg-rhel5-ds.xml")
for cpe_id in cpe_ids:
if cpe_id.startswith("cpe:/o:fedoraproject:fedora:"):
return os.path.join(self.ssg_path, "ssg-fedora-ds.xml")
if "cpe:/o:centos:centos:7" in cpe_ids:
return os.path.join(self.ssg_path, "ssg-centos7-ds.xml")
if "cpe:/o:centos:centos:6" in cpe_ids:
return os.path.join(self.ssg_path, "ssg-centos6-ds.xml")
if "cpe:/o:centos:centos:5" in cpe_ids:
return os.path.join(self.ssg_path, "ssg-centos5-ds.xml")
raise RuntimeError(
"Can't find suitable SSG source datastream for CPE IDs %s" %
(", ".join(cpe_ids))
)
path = get_ssg_sds_path(cpe_ids)
if not os.path.exists(path):
raise RuntimeError(
"Suitable SSG source datastream doesn't exist on disk. "
"Expected at path '%s'. Please install 'scap-security-guide' "
"of version 0.1.28 or higher." % (path)
)
return path
openscap-daemon-0.1.10/openscap_daemon/cve_feed_manager.py 0000664 0000000 0000000 00000017652 13237071060 0023613 0 ustar 00root root 0000000 0000000 # Copyright (C) 2016 Red Hat Inc., Durham, North Carolina.
# Copyright (C) 2015 Brent Baude
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the
# Free Software Foundation, Inc., 59 Temple Place - Suite 330,
# Boston, MA 02111-1307, USA.
try:
# Python2 imports
import urlparse
import urllib2 as urllib
except ImportError:
# Python3 imports
import urllib.parse as urlparse
import urllib.request as urllib
import os
import os.path
import time
import datetime
import logging
import bz2
import threading
class CVEFeedManager(object):
"""Class to obtain the CVE data provided by RH and possibly other vendors.
The CVE data is used to scan for CVEs using OpenSCAP
"""
default_url = "https://www.redhat.com/security/data/oval/"
class HeadRequest(urllib.Request):
def get_method(self):
return "HEAD"
def __init__(self, dest="/tmp"):
self.dest = dest
self.hdr = {"User-agent": "Mozilla/5.0"}
self.hdr2 = [("User-agent", "Mozilla/5.0")]
self.url = CVEFeedManager.default_url
self.remote_dist_cve_name = "com.redhat.rhsa-RHEL{0}.xml.bz2"
self.local_dist_cve_name = "com.redhat.rhsa-RHEL{0}.xml"
self.dists = [5, 6, 7]
self.remote_pattern = '%a, %d %b %Y %H:%M:%S %Z'
self.fetch_enabled = True
# check for fresh CVE feeds at most every 10 minutes
self.fetch_timeout = 10 * 60
# A map of remote URIs to the time we last checked them for fresh
# content.
self.fetch_last_checked = {}
# Let us only check for fresh CVEs once at a time
self.fetch_lock = threading.Lock()
def _parse_http_headers(self, http_headers):
"""Returns dictionary containing HTTP headers with lowercase keys
"""
headers_dict = dict(http_headers)
return dict((key.lower(), value) for key, value in headers_dict.items())
def _print_no_last_modified_warning(self, url):
logging.warning(
"Warning: Response header of HTTP doesn't contain "
"\"last-modified\" field. Cannot determine version"
" of remote file \"{0}\"".format(url)
)
def _is_cache_same(self, local_file, remote_url):
"""Checks if the local cache version and the upstream
version is the same or not. If they are the same,
returns True; else False.
"""
with self.fetch_lock:
if not os.path.exists(local_file):
logging.debug(
"No local file cached, will fetch {0}".format(remote_url)
)
return False
last_checked = self.fetch_last_checked.get(remote_url, 0)
now = time.time()
if now - last_checked <= self.fetch_timeout:
logging.debug(
"Checked for fresh version of '%s' just %f seconds ago. "
"Will wait %f seconds before checking again.",
remote_url, now - last_checked,
self.fetch_timeout - now + last_checked
)
return True
opener = urllib.build_opener()
# Add the header
opener.addheaders = self.hdr2
# Grab the header
try:
res = opener.open(CVEFeedManager.HeadRequest(remote_url))
headers = self._parse_http_headers(res.info())
res.close()
remote_ts = headers['last-modified']
except urllib.HTTPError as http_error:
logging.debug(
"Cannot send HTTP HEAD request to get \"last-modified\" "
"attribute of remote content file.\n{0} - {1}"
.format(http_error.code, http_error.reason)
)
return False
except KeyError:
self._print_no_last_modified_warning(remote_url)
return False
self.fetch_last_checked[remote_url] = time.time()
# The remote's datetime
remote_dt = datetime.datetime.strptime(
remote_ts, self.remote_pattern
)
# Get the locals datetime from the file's mtime, converted to UTC
local_dt = datetime.datetime.utcfromtimestamp(
os.stat(local_file).st_mtime
)
# Giving a two second comfort zone
# Else we declare they are different
if (remote_dt - local_dt).seconds > 2:
logging.info("Had a local version of {0} "
"but it wasn't new enough".format(local_file))
return False
logging.debug("File {0} is same as upstream".format(local_file))
return True
def get_rhel_cve_feed(self, dist):
"""Given a distribution number (i.e. 7), it will fetch the
distribution specific data file if upstream has a newer
input file. Returns the path of file.
If we already have a cached version that is fresh it will just
return the path.
"""
local_file = os.path.join(
self.dest, self.local_dist_cve_name.format(dist)
)
if not self.fetch_enabled:
return local_file
remote_url = urlparse.urljoin(
self.url, self.remote_dist_cve_name.format(dist)
)
if self._is_cache_same(local_file, remote_url):
return local_file
_url = urllib.Request(remote_url, headers=self.hdr)
try:
resp = urllib.urlopen(_url)
except Exception as url_error:
raise Exception("Unable to fetch CVE inputs due to {0}"
.format(url_error))
fh = open(local_file, "wb")
fh.write(bz2.decompress(resp.read()))
fh.close()
# Correct Last-Modified timestamp
headers = self._parse_http_headers(resp.info())
resp.close()
try:
remote_ts = headers['last-modified']
epoch = datetime.datetime.utcfromtimestamp(0)
remote_dt = datetime.datetime.strptime(remote_ts, self.remote_pattern)
seconds_epoch = (remote_dt - epoch).total_seconds()
os.utime(local_file, (seconds_epoch, seconds_epoch))
except KeyError:
self._print_no_last_modified_warning(remote_url)
return local_file
def fetch_all_rhel_cve_feeds(self):
"""Fetches all the the distribution specific data used for
input with openscap cve scanning and returns a list
of those files.
"""
cve_files = []
for dist in self.dists:
cve_files.append(self.get_cve_feed(dist))
return cve_files
def get_cve_feed(self, cpe_ids):
if "cpe:/o:redhat:enterprise_linux:7" in cpe_ids:
return self.get_rhel_cve_feed(7)
elif "cpe:/o:redhat:enterprise_linux:6" in cpe_ids:
return self.get_rhel_cve_feed(6)
elif "cpe:/o:redhat:enterprise_linux:5" in cpe_ids:
return self.get_rhel_cve_feed(5)
raise RuntimeError(
"Can't find a supported CPE ID in %s" % (", ".join(cpe_ids))
)
def get_cve_feed_last_updated(self, cpe_ids):
local_file = self.get_cve_feed(cpe_ids)
assert(os.path.exists(local_file))
# local timestamp, local timezone datetime
return datetime.datetime.fromtimestamp(os.path.getmtime(local_file))
openscap-daemon-0.1.10/openscap_daemon/cve_scanner/ 0000775 0000000 0000000 00000000000 13237071060 0022262 5 ustar 00root root 0000000 0000000 openscap-daemon-0.1.10/openscap_daemon/cve_scanner/__init__.py 0000664 0000000 0000000 00000001377 13237071060 0024403 0 ustar 00root root 0000000 0000000 # Copyright (C) 2015 Red Hat Inc., Durham, North Carolina.
#
# All Rights Reserved.
#
# openscap-daemon is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 2.1 of the License, or
# (at your option) any later version.
#
# openscap-daemon is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
# You should have received a copy of the GNU Lesser General Public License
# along with openscap-daemon. If not, see .
#__all__ = []
openscap-daemon-0.1.10/openscap_daemon/cve_scanner/applicationconfiguration.py 0000664 0000000 0000000 00000004426 13237071060 0027735 0 ustar 00root root 0000000 0000000 # Copyright (C) 2015 Brent Baude
# Copyright (C) 2015 Red Hat Inc., Durham, North Carolina.
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with openscap-daemon. If not, see .
# TODO: Integrate this to openscap_daemon.config package
from openscap_daemon.cve_scanner.scanner_error import ImageScannerClientError
class ApplicationConfiguration(object):
'''Application Configuration'''
def __init__(self, parserargs=None):
''' Init for Application Configuration '''
self.workdir = parserargs.workdir
self.logfile = parserargs.logfile
self.number = parserargs.number
self.reportdir = parserargs.reportdir
self.fetch_cve = parserargs.fetch_cve
self.fcons = None
self.cons = None
self.images = None
self.allimages = None
self.return_json = None
self.conn = self.ValidateHost(parserargs.host)
self.parserargs = parserargs
self.json_url = None
# "" means we will use oscap-docker defaults, else a string with URL
# is expected. example: "https://www.redhat.com/security/data/oval/"
self.fetch_cve_url = parserargs.fetch_cve_url
def ValidateHost(self, host):
''' Validates if the defined docker host is running'''
try:
import docker
except ImportError:
error = "Can't import 'docker' package. Has docker been installed?"
raise ImageScannerClientError(error)
client = docker.Client(base_url=host, timeout=11)
if not client.ping():
error = "Cannot connect to the Docker daemon. Is it running " \
"on this host?"
raise ImageScannerClientError(error)
return client
openscap-daemon-0.1.10/openscap_daemon/cve_scanner/cve_scanner.py 0000664 0000000 0000000 00000047205 13237071060 0025132 0 ustar 00root root 0000000 0000000 # Copyright (C) 2015 Brent Baude
# Copyright (C) 2015 Red Hat Inc., Durham, North Carolina.
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with openscap-daemon. If not, see .
from openscap_daemon.cve_scanner.applicationconfiguration \
import ApplicationConfiguration
from openscap_daemon.cve_scanner.reporter import Reporter
from openscap_daemon.cve_scanner.scan import Scan
from openscap_daemon.cve_scanner.generate_summary import Create_Summary
from openscap_daemon.cve_scanner.scanner_error import ImageScannerClientError
import dbus
import os
import tempfile
import timeit
import threading
import logging
import sys
import time
import signal
import subprocess
from datetime import datetime
import json
import platform
import collections
import re
class ContainerSearch(object):
''' Does a series of docker queries to setup variables '''
def __init__(self, appc):
self.dead_cids = []
self.ac = appc
self.cons = self.ac.conn.containers(all=True)
self.active_containers = self.ac.conn.containers(all=False)
self.allimages = self.ac.conn.images(name=None, quiet=False,
all=True, viz=False)
self.images = self.ac.conn.images(name=None, quiet=False,
all=False, viz=False)
self.allimagelist = self._returnImageList(self.allimages)
self.imagelist = self._returnImageList(self.images)
self.fcons = self._formatCons(self.cons)
self.fcons_active = self._formatCons(self.active_containers)
self.ac.fcons = self.fcons
self.ac.cons = self.cons
self.ac.allimages = self.allimages
self.ac.return_json = {}
def _returnImageList(self, images):
'''
Walks through the image list and if the image
size is not 0, it will add it to the returned
list.
'''
il = []
for i in images:
if i['VirtualSize'] > 0:
il.append(i['Id'])
return il
def _formatCons(self, cons):
'''
Returns a formatted dictionary of containers by
image id like:
fcons = {'iid': [{'cid': {'running': bool}}, ... ]}
'''
fcons = {}
for c in cons:
cid = c['Id']
inspect = self.ac.conn.inspect_container(cid)
iid = inspect['Image']
run = inspect['State']['Running']
if 'Dead' in inspect['State']:
dead = inspect['State']['Dead']
else:
dead = False
if dead:
self.dead_cids.append(cid)
if iid not in fcons:
fcons[iid] = [{'uuid': cid, 'running': run, 'Dead': dead}]
else:
fcons[iid].append({'uuid': cid, 'running': run, 'Dead': dead})
return fcons
class Worker(object):
min_procs = 2
max_procs = 4
image_tmp = "/var/tmp/image-scanner"
scan_args = ['allcontainers', 'allimages', 'images', 'logfile',
'fetch_cve', 'number', 'onlyactive', 'reportdir',
'workdir', 'url_root', 'host', 'rest_host',
'rest_port', 'scan', 'fetch_cve_url']
scan_tuple = collections.namedtuple('Namespace', scan_args)
def __init__(self, number=2,
logfile=os.path.join(image_tmp, "openscap.log"),
fetch_cve=False, reportdir=image_tmp, workdir=image_tmp,
host='unix://var/run/docker.sock',
allcontainers=False, onlyactive=False, allimages=False,
images=False, scan=[], fetch_cve_url=""):
self.args =\
self.scan_tuple(number=number, logfile=logfile,
fetch_cve=fetch_cve, reportdir=reportdir,
workdir=workdir, host=host,
allcontainers=allcontainers, allimages=allimages,
onlyactive=onlyactive, images=images, url_root='',
rest_host='', rest_port='', scan=scan,
fetch_cve_url=fetch_cve_url)
self.ac = ApplicationConfiguration(parserargs=self.args)
self.procs = self.set_procs(self.args.number)
if not os.path.exists(self.ac.workdir):
os.makedirs(self.ac.workdir)
self.cs = ContainerSearch(self.ac)
self.output = Reporter(self.ac)
self.scan_list = None
self.failed_scan = None
self.rpms = {}
# full image name can look like sha256:abcdxy:efgfz
self.name_regex = re.compile(r"((?:sha256:)?[^:]+)(?::([^:]+))?")
def set_procs(self, number):
if number is None:
try:
import multiprocessing
numThreads = multiprocessing.cpu_count()
except NotImplementedError:
numThreads = 4
else:
numThreads = number
if numThreads < self.min_procs:
if self.ac.number is not None:
print("The image-scanner requires --number to be a minimum " \
"of {0}. Setting --number to {1}".format(self.min_procs,
self.min_procs))
return self.min_procs
elif numThreads <= self.max_procs:
return numThreads
else:
if self.ac.number is not None:
print("Due to docker issues, we limit the max number "\
"of threads to {0}. Setting --number to "\
"{1}".format(self.max_procs, self.max_procs))
return self.max_procs
def _get_cids_for_image(self, cs, image):
cids = []
if image in cs.fcons:
for container in cs.fcons[image]:
cids.append(container['uuid'])
else:
for iid in cs.fcons:
cids = [con['uuid'] for con in cs.fcons[iid]]
if image in cids:
return cids
return cids
def return_active_threadnames(self, threads):
thread_names = []
for thread in threads:
thread_name = thread._Thread__name
if thread_name is not "MainThread":
thread_names.append(thread_name)
return thread_names
def onlyactive(self):
''' This function sorts of out only the active containers'''
con_list = []
# Rid ourselves of 0 size containers
for container in self.cs.active_containers:
con_list.append(container['Id'])
if len(con_list) == 0:
error = "There are no active containers on this system"
raise ImageScannerClientError(error)
else:
try:
self._do_work(con_list)
except Exception as error:
raise ImageScannerClientError(str(error))
def allimages(self):
if len(self.cs.imagelist) == 0:
error = "There are no images on this system"
raise ImageScannerClientError(error)
if self.args.allimages:
try:
self._do_work(self.cs.allimagelist)
except Exception as error:
raise ImageScannerClientError(str(error))
else:
try:
self._do_work(self.cs.imagelist)
except Exception as error:
raise ImageScannerClientError(str(error))
def list_of_images(self, image_list):
try:
self._do_work(image_list)
except Exception as error:
raise ImageScannerClientError(str(error))
def allcontainers(self):
if len(self.cs.cons) == 0:
error = "There are no containers on this system"
raise ImageScannerClientError(error)
else:
con_list = []
for con in self.cs.cons:
con_list.append(con['Id'])
try:
self._do_work(con_list)
except Exception as error:
raise ImageScannerClientError(str(error))
def _do_work(self, image_list):
from oscap_docker_python.get_cve_input import getInputCVE
self.scan_list = image_list
cve_get = getInputCVE(self.image_tmp)
if self.ac.fetch_cve_url != "":
cve_get.url = self.ac.fetch_cve_url
if self.ac.fetch_cve:
cve_get.fetch_dist_data()
threads = []
mnt_dir = tempfile.mkdtemp()
for image in image_list:
if image in self.cs.dead_cids:
raise ImageScannerClientError("Scan not completed. Cannot "
"scan the dead "
"container {0}".format(image))
cids = self._get_cids_for_image(self.cs, image)
t = threading.Thread(target=self.search_containers, name=image,
args=(image, cids, self.output, mnt_dir,))
threads.append(t)
logging.info("Number of containers to scan: {0}".format(len(threads)))
if isinstance(threading.current_thread(), threading._MainThread):
signal.signal(signal.SIGINT, self.signal_handler)
self.threads_complete = 0
self.cur_scan_threads = 0
while len(threads) > 0:
if self.cur_scan_threads < self.procs:
new_thread = threads.pop()
new_thread.start()
self.cur_scan_threads += 1
while self.cur_scan_threads > 0:
time.sleep(1)
pass
os.rmdir(mnt_dir)
if self.failed_scan is not None:
raise ImageScannerClientError(self.failed_scan)
self.output.report_summary()
def signal_handler(self, signal, frame):
print("\n\nExiting...")
sys.exit(0)
def search_containers(self, image, cids, output, mnt_dir):
try:
f = Scan(image, cids, output, self.ac, mnt_dir)
except Exception as e:
# We don't know all types of docker/atomic exception, so we catch
# all these exceptions to avoid daemon freezing
self.failed_scan = str(e)
self.threads_complete += 1
self.cur_scan_threads -= 1
return
try:
if f.get_release():
t = timeit.Timer(f.scan).timeit(number=1)
logging.debug("Scanned chroot for image {0}"
" completed in {1} seconds"
.format(image, t))
try:
timeit.Timer(f.report_results).timeit(number=1)
image_rpms = f._get_rpms()
self.rpms[image] = image_rpms
except Exception as error:
self.failed_scan = str(error)
else:
# This is not a RHEL image or container
f._report_not_rhel(image)
except subprocess.CalledProcessError:
pass
# umount and clean up temporary container
try:
f.unmount()
except ValueError as e:
logging.error("Unmount error: {}".format(e.msg))
except Exception as e:
# We don't know all types of docker/atomic exception, so we catch
# all these exceptions to avoid daemon freezing
logging.error("Docker: {}".format(e.msg()))
self.threads_complete += 1
self.cur_scan_threads -= 1
def _check_input(self, image_list):
'''
Takes a list of image ids, image-names, container ids, or
container-names and returns a list of images ids and
container ids
'''
work_list = []
# verify
try:
for image in image_list:
iid = self.get_iid(image)
work_list.append(iid)
except ImageScannerClientError:
error = "Unable to associate {0} with any image " \
"or container".format(image)
raise ImageScannerClientError(error)
return work_list
def get_cid(self, input_name):
"""
Given a container name or container id, it will return the
container id
"""
for container in self.ac.cons:
if 'Names' in container and container['Names'] is not None:
if (container['Id'].startswith(input_name)) or \
(('Names' in container) and
(any(input_name in item for item in
container['Names']))):
return container['Id']
break
return None
def parse_image_name(self, input_name):
"""
Parse image name and return its parts as tuple
:param input_name:
:return: (name, tag)
"""
m = self.name_regex.match(input_name)
if m:
return (m.group(1), m.group(2))
else:
return (input_name, None)
def _namesearch(self, input_name):
"""
Looks to see if the input name is the name of a image
"""
image_name, tag = self.parse_image_name(input_name)
name_search = self.ac.conn.images(name=image_name, all=True)
# We found only one result, return it
if len(name_search) == 1:
return name_search[0]['Id']
else:
# We found multiple images with the input name
# If a tag is passed, then we can return the right one
# If not, we assume if all the image_ids are same, we
# can use that.
ilist = []
for image in name_search:
if input_name in image['RepoTags']:
return image['Id']
else:
ilist.append(image['Id'])
if tag is not None:
raise ImageScannerClientError("Unable to find"
"to an image named {0}"
.format(input_name))
# We didn't find it by name only. We check if the image_ids
# are all the same
if len(ilist) > 1:
if all(ilist[0] == image for image in ilist) and (tag is None):
return ilist[0]
else:
raise \
ImageScannerClientError("Found multiple images named"
"{0} with different image Ids."
"Try again with the image"
"name and tag"
.format(input_name))
return None
def get_iid(self, input_name):
'''
Find the image id based on a input_name which can be
an image id, image name, or an image name:tag name.
'''
# Check if the input name is a container
cid = self.get_cid(input_name)
if cid is not None:
return cid
# Check if the input_name was an image name or name:tag
image_id = self._namesearch(input_name)
if image_id is not None:
return image_id
# Maybe input name is an image id (or portion)
for image in self.ac.allimages:
if image['Id'].startswith(input_name):
return image['Id']
raise ImageScannerClientError("Unable to associate {0} with any image"
.format(input_name))
def start_application(self):
if not self.args.onlyactive and not self.args.allcontainers and \
not self.allimages and not self.args.images and \
not self.args.scan:
return {'Error': 'No scan type was selected'}
start_time = time.time()
logging.basicConfig(filename=self.ac.logfile,
format='%(asctime)s %(levelname)-8s %(message)s',
datefmt='%m-%d %H:%M', level=logging.DEBUG)
if self.args.onlyactive:
self.onlyactive()
elif self.args.allcontainers:
self.allcontainers()
elif self.args.allimages or self.args.images:
self.allimages()
else:
# Check to make sure we have valid input
image_list = self._check_input(self.args.scan)
try:
self.list_of_images(image_list)
except ImageScannerClientError as error:
raise dbus.exceptions.DBusException(str(error))
end_time = time.time()
duration = (end_time - start_time)
if duration < 60:
unit = "seconds"
else:
unit = "minutes"
duration = duration / 60
logging.info("Completed entire scan in {0} {1}".format(duration, unit))
docker_state = self.dump_json_log()
return docker_state
def _get_rpms_by_obj(self, docker_obj):
return self.rpms[docker_obj]
def dump_json_log(self):
'''
Creates a log of information about the scan and what was
scanned for post-scan analysis
'''
xmlp = Create_Summary()
# Common Information
json_log = {}
json_log['hostname'] = platform.node()
json_log['scan_time'] = datetime.today().isoformat(' ')
json_log['scanned_content'] = self.scan_list
json_log['host_results'] = {}
json_log['docker_state'] = self.ac.fcons
json_log['host_images'] = [image['Id'] for image in self.ac.allimages]
json_log['host_containers'] = [con['Id'] for con in self.ac.cons]
json_log['docker_state_url'] = self.ac.json_url
tuple_keys = ['rest_host', 'rest_port', 'allcontainers',
'allimages', 'images', 'logfile', 'number',
'reportdir', 'workdir', 'url_root',
'host', 'fetch_cve_url']
for tuple_key in tuple_keys:
tuple_val = None if not hasattr(self.ac.parserargs, tuple_key) \
else getattr(self.ac.parserargs, tuple_key)
json_log[tuple_key] = tuple_val
# Per scanned obj information
for docker_obj in self.scan_list:
json_log['host_results'][docker_obj] = {}
tmp_obj = json_log['host_results'][docker_obj]
if 'msg' in self.ac.return_json[docker_obj].keys():
tmp_obj['isRHEL'] = False
else:
tmp_obj['rpms'] = self._get_rpms_by_obj(docker_obj)
tmp_obj['isRHEL'] = True
xml_path = self.ac.return_json[docker_obj]['xml_path']
tmp_obj['cve_summary'] = \
xmlp._summarize_docker_object(xml_path,
json_log, docker_obj)
# Pulling out good stuff from summary by docker object
for docker_obj in self.ac.return_json.keys():
if 'msg' not in self.ac.return_json[docker_obj].keys():
for key, value in self.ac.return_json[docker_obj].items():
json_log['host_results'][docker_obj][key] = value
json_log['results_summary'] = self.ac.return_json
# DEBUG
# print(json.dumps(json_log, indent=4, separators=(',', ': ')))
with open(self.ac.docker_state, 'w') as state_file:
json.dump(json_log, state_file)
return json_log
openscap-daemon-0.1.10/openscap_daemon/cve_scanner/generate_summary.py 0000664 0000000 0000000 00000023275 13237071060 0026214 0 ustar 00root root 0000000 0000000 # Copyright (C) 2015 Brent Baude
# Copyright (C) 2015 Red Hat Inc., Durham, North Carolina.
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with openscap-daemon. If not, see .
'''
Functions used by the docker_scanner to
generate the results dict from the oscap results.xml files
'''
import xml.etree.ElementTree as ET
from collections import namedtuple
from openscap_daemon.cve_scanner.scanner_error import ImageScannerClientError
import json
import sys
if sys.version_info < (3,):
import urlparse
else:
import urllib.parse as urlparse
class Create_Summary(object):
''' Class that provides the functions '''
_cve_tuple = namedtuple('oval_cve', ['title', 'severity', 'cve_ref_id',
'cve_ref_url', 'rhsa_ref_id', 'rhsa_ref_url',
'cve', 'description'])
def __init__(self):
self.containers = None
self.images = None
self.cve_info = None
def _get_root(self, result_file):
'''
Returns an ET object for the input XML which can be a file
or a URL pointing to an xml file
'''
from openscap_daemon.cve_scanner.image_scanner_client import Client
if result_file.startswith("http://"):
split_url = urlparse.urlsplit(result_file)
image_scanner = Client(split_url.hostname, port=split_url.port)
result_tree = image_scanner.getxml(result_file)
else:
result_tree = ET.parse(result_file)
return result_tree.getroot()
def _get_list_cve_def_ids(self, _root):
'''Returns a list of cve definition ids in the result file'''
_def_id_list = []
definitions = _root.findall("{http://oval.mitre.org/XMLSchema/"
"oval-results-5}results/{http://oval.mitre"
".org/XMLSchema/oval-results-5}system/{"
"http://oval.mitre.org/XMLSchema/oval-"
"results-5}definitions/*[@result='true']")
for def_id in definitions:
_def_id_list.append(def_id.attrib['definition_id'])
return _def_id_list
def _get_cve_def_info(self, _def_id_list, _root):
'''
Returns a list of tuples that contain information about the
cve themselves. Currently return are: title, severity, ref_id
and ref_url for the cve and rhsa, the cve id, and description
'''
cve_info_list = []
for def_id in _def_id_list:
oval_defs = _root.find("{http://oval.mitre.org/XMLSchema/oval-"
"definitions-5}oval_definitions/{http://"
"oval.mitre.org/XMLSchema/oval-definitions-"
"5}definitions/*[@id='%s']/{http://oval."
"mitre.org/XMLSchema/oval-definitions-5}"
"metadata" % def_id)
# title
title = oval_defs.find("{http://oval.mitre.org/XMLSchema/oval-"
"definitions-5}title").text
rhsa_meta = oval_defs.find("{http://oval.mitre.org/XMLSchema/oval"
"-definitions-5}reference[@source="
"'RHSA']")
cve_meta = oval_defs.find("{http://oval.mitre.org/XMLSchema/oval-"
"definitions-5}reference[@source='CVE']")
# description
description = oval_defs.find("{http://oval.mitre.org/XMLSchema/"
"oval-definitions-5}description").text
# severity
severity = oval_defs.find("{http://oval.mitre.org/XMLSchema/oval-"
"definitions-5}advisory/{http://oval."
"mitre.org/XMLSchema/oval-definitions"
"-5}severity").text
cve_info_list.append(
self._cve_tuple(title=title, severity=severity,
cve_ref_id=None if cve_meta is None
else cve_meta.attrib['ref_id'],
cve_ref_url=None if cve_meta is None
else cve_meta.attrib['ref_url'],
rhsa_ref_id=rhsa_meta.attrib['ref_id'],
rhsa_ref_url=rhsa_meta.attrib['ref_url'],
cve=def_id.replace(
"oval:com.redhat.rhsa:def:", ""),
description=description))
return cve_info_list
def get_cve_info(self, result_file):
'''
Wrapper function to return a list of tuples with
cve information from the xml input file
'''
_root = self._get_root(result_file)
_id_list = self._get_list_cve_def_ids(_root)
return self._get_cve_def_info(_id_list, _root)
def _return_cve_dict_info(self, title):
'''
Returns a dict containing the specific details of a cve which
includes title, rhsa/cve ref_ids and urls, cve number, and
description.
'''
cve_tuple = [cved for cved in self.cve_info if cved.title == title][0]
cve_dict_info = {'cve_title': cve_tuple.title,
'cve_ref_id': cve_tuple.cve_ref_id,
'cve_ref_url': cve_tuple.cve_ref_url,
'rhsa_ref_id': cve_tuple.rhsa_ref_id,
'rhsa_ref_url': cve_tuple.rhsa_ref_url,
'cve': cve_tuple.cve
}
return cve_dict_info
def _summarize_docker_object(self, result_file, docker_json, item_id):
'''
takes a result.xml file and a docker state json file and
compares output to give an analysis of a given scan
'''
self.cve_info = self.get_cve_info(result_file)
affected_image = 0
affected_children = []
is_image = self.is_id_an_image(item_id, docker_json)
summary = {}
if is_image:
summary['scanned_image'] = item_id
affected_image = item_id
affected_children = self._process_image(affected_image,
docker_json)
else:
summary['scanned_container'] = item_id
affected_children, affected_image = \
self._process_container(docker_json, item_id)
summary['image'] = affected_image
summary['containers'] = affected_children
scan_results = {}
for cve in self.cve_info:
_cve_specifics = self._return_cve_dict_info(cve.title)
if cve.severity not in scan_results:
scan_results[cve.severity] = \
{'num': 1,
'cves': [_cve_specifics]}
else:
scan_results[cve.severity]['num'] += 1
scan_results[cve.severity]['cves'].append(_cve_specifics)
summary['scan_results'] = scan_results
# self.debug_json(summary)
return summary
def _process_container(self, docker_json, item_id):
'''
Returns containers with the same base image
as a list
'''
affected_children = []
for image_id in docker_json['docker_state']:
for containers in docker_json['docker_state'][image_id]:
if item_id == containers['uuid']:
base_image = image_id
for containers in docker_json['docker_state'][base_image]:
affected_children.append(containers['uuid'])
return affected_children, base_image
# Deprecate or rewrite
def _process_image(self, affected_image, docker_json):
'''
Returns containers with a given base
as a list
'''
affected_children = []
# Catch an image that has no containers
if affected_image not in docker_json['docker_state']:
return []
# It has children containers
for containers in docker_json['docker_state'][affected_image]:
affected_children.append(containers['uuid'])
return affected_children
def is_id_an_image(self, docker_id, docker_obj):
'''
helper function that uses the docker_state_file to validate if the
given item_id is a container or image id
'''
if self.containers is None or self.images is None:
self.containers = docker_obj['host_containers']
self.images = docker_obj['host_images']
if docker_id in self.images:
return True
elif docker_id in self.containers:
return False
else:
# Item was not found in the docker state file
error_msg = 'The provided openscap xml result file was ' \
'not generated from the same run as the ' \
'docker state file '
raise ImageScannerClientError(error_msg)
def debug_json(self, json_data):
''' Pretty prints a json object for debug purposes '''
print(json.dumps(json_data, indent=4, separators=(',', ': ')))
openscap-daemon-0.1.10/openscap_daemon/cve_scanner/image_scanner_client.py 0000664 0000000 0000000 00000040205 13237071060 0026766 0 ustar 00root root 0000000 0000000 # Copyright (C) 2015 Brent Baude
# Copyright (C) 2015 Red Hat Inc., Durham, North Carolina.
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with openscap-daemon. If not, see .
''' Image scanner API '''
from openscap_daemon.cve_scanner.scanner_error import ImageScannerClientError
import json
import xml.etree.ElementTree as ET
import collections
import os
import sys
from multiprocessing.dummy import Pool as ThreadPool
# TODO: External dep, verify that we really need it!
import requests
if sys.version_info < (3,):
import urlparse
import ConfigParser
else:
import urllib.parse as urlparse
import configparser as ConfigParser
class Client(requests.Session):
''' The image-scanner client API '''
request_headers = {'content-type': 'application/json'}
def __init__(self, host, port=5001, number=2):
'''
When instantiating, pass in the host and optionally
the port and threading counts
'''
super(Client, self).__init__()
self.host = "http://{0}:{1}" .format(host, port)
self.api_path = "image-scanner/api"
self.num_threads = number
self.client_common = ClientCommon()
def scan_all_containers(self, onlyactive=False):
''' Scans all containers and returns results in json'''
url = urlparse.urljoin(self.host, self.api_path + "/scan")
con_scan = 'allcontainers' if onlyactive is False else 'onlyactive'
params = {con_scan: True, 'number': self.num_threads}
results = self._get_results(url, data=json.dumps(params))
self._check_result(results)
return json.loads(results.text)
def scan_list(self, scan_list):
'''
Scans a list of containers/images by name or id and returns
results in json
'''
if not isinstance(scan_list, list):
raise ImageScannerClientError("You must pass input in list form")
url = urlparse.urljoin(self.host, self.api_path + "/scan")
params = {'scan': scan_list, 'number': self.num_threads}
results = self._get_results(url, data=json.dumps(params))
self._check_result(results)
return json.loads(results.text)
def scan_images(self, all=False):
'''Scans all images and returns results in json'''
url = urlparse.urljoin(self.host, self.api_path + "/scan")
if all:
params = {'allimages': True, 'number': self.num_threads}
else:
params = {'images': True, 'number': self.num_threads}
results = self._get_results(url, data=json.dumps(params))
self._check_result(results)
return json.loads(results.text)
def inspect_container(self, cid):
'''Inspects a container and returns all results in json'''
url = urlparse.urljoin(self.host, self.api_path + "/inspect_container")
results = self._get_results(url, data=json.dumps({'cid': cid}))
return json.loads(results.text)
def inspect_image(self, iid):
'''Inspects a container and returns the results in json'''
url = urlparse.urljoin(self.host, self.api_path + "/inspect_image")
results = self._get_results(url, json.dumps({'iid': iid}))
return json.loads(results.text)
def getxml(self, url):
'''
Given a URL string, returns the results of an openscap XML file as
an Element Tree
'''
try:
results = self.get(url)
except requests.exceptions.ConnectionError:
raise ImageScannerClientError("Unable to connect to REST server "
"at {0}".format(url))
return ET.ElementTree(ET.fromstring(results.content))
def get_docker_json(self, url):
'''
Given a URL, return the state of the docker containers and images
when the images-scanning occurred. Returns as JSON object.
'''
try:
results = self.get(url)
except requests.exceptions.ConnectionError:
raise ImageScannerClientError("Unable to connect to REST server "
"at {0}".format(url))
return json.loads(results.text)
def _get_results(self, url, data=None, headers=None):
'''Wrapper functoin for calling the request.session.get'''
headers = self.request_headers if headers is None else headers
try:
if data is not None:
results = self.get(url, data=data,
headers=headers)
else:
results = self.get(url, headers=headers, timeout=9)
except requests.exceptions.ConnectionError:
raise ImageScannerClientError("Unable to connect to REST server "
"at {0}".format(url))
except requests.exceptions.Timeout:
raise ImageScannerClientError("Timeout reached with REST server "
"at {0}".format(url))
return results
@staticmethod
def _check_result(result):
'''
Examines a json object looking for a key of 'Error'
which indicates the previous call did not work. Raises
an exception upon finding the key
'''
result_json = json.loads(result.text)
if 'Error' in result_json:
raise ImageScannerClientError(result_json['Error'])
if 'results' in result_json.keys() and 'Error' \
in result_json['results']:
raise ImageScannerClientError(result_json['results']['Error'])
def ping(self):
'''
Throws an exception if it cannot access the REST server or
the docker host
'''
url = urlparse.urljoin(self.host, self.api_path + "/ping")
results = self._get_results(url)
if 'results' not in json.loads(results.text):
tmp_obj = json.loads(results.text)
if hasattr(tmp_obj, 'error'):
error = getattr(tmp_obj, 'error')
else:
error = tmp_obj['Error']
error = error.replace('on the host ', 'on the host {0} '
.format(self.host))
raise ImageScannerClientError(error)
class ClientCommon(object):
''' Clients functions that are shared with other classes '''
config_file = "/etc/image-scanner/image-scanner-client.conf"
profile_tuple = collections.namedtuple('profiles', ['profile',
'host',
'port',
'cert',
'number'])
args_tuple = collections.namedtuple('scan_args',
['allimages', 'images',
'allcontainers', 'onlyactive'])
client_dir = "/var/tmp/image-scanner/client"
if not os.path.exists(client_dir):
os.makedirs(client_dir)
uber_file_path = os.path.join(client_dir, 'uber_docker.json')
def __init__(self):
self.uber_docker = {}
self.num_complete = 0
self.num_total = 0
self.last_completed = ""
self.threads = 0
@staticmethod
def debug_json(json_data):
''' Debug function that pretty prints json objects'''
print(json.dumps(json_data, indent=4, separators=(',', ': ')))
def get_profile_info(self, profile):
''' Looks for host and port based on the profile provided '''
config = ConfigParser.RawConfigParser()
config.read(self.config_file)
try:
port = config.get(profile, 'port')
host = config.get(profile, 'host')
cert = None if not config.has_option(profile, 'cert') else \
config.get(profile, 'cert')
number = 2 if not config.has_option(profile, 'threads') else \
config.get(profile, 'threads')
except ConfigParser.NoSectionError:
raise ImageScannerClientError("The profile {0} cannot be found "
"in {1}".format(profile,
self.config_file))
except ConfigParser.NoOptionError as no_option:
print("No option {0} found in profile "\
"{1} in {2}".format(no_option.option,
profile,
self.config_file))
return host, port, number, cert
def _make_profile_tuple(self, host, port, number, cert, section):
''' Creates the profile_tuple and returns it '''
return self.profile_tuple(profile=section, host=host, port=port,
cert=None, number=number)
def return_profiles(self, input_profile_list):
'''
Returns a list of tuples with information about the
input profiles
'''
profile_list = []
config = ConfigParser.ConfigParser()
config.read(self.config_file)
for profile in input_profile_list:
host, port, number, cert = self.get_profile_info(profile)
if self.threads > 0:
number = self.threads
profile_list.append(self._make_profile_tuple(host, port,
number, cert, profile))
return profile_list
def return_all_profiles(self):
''' Returns a list of tuples with host and port information '''
profile_list = []
config = ConfigParser.ConfigParser()
config.read(self.config_file)
for section in config.sections():
host, port, number, cert = self.get_profile_info(section)
profile_list.append(self._make_profile_tuple(host, port, number,
cert, section))
return profile_list
def get_all_profile_names(self):
''' Returns a list of all profile names '''
profile_names = []
all_profiles = self.return_all_profiles()
for profile in all_profiles:
profile_names.append(profile.profile)
return profile_names
def thread_profile_wrapper(self, args):
''' Simple wrapper for thread_profiles '''
return self.thread_profiles(*args)
def thread_profiles(self, profile, onlyactive, allcontainers,
allimages, images):
''' Kicks off a scan of for a remote host'''
scanner = Client(profile.host, profile.port, number=profile.number)
try:
if onlyactive:
results = scanner.scan_all_containers(onlyactive=True)
elif allcontainers:
results = scanner.scan_all_containers()
elif allimages:
results = scanner.scan_images(all=True)
else:
results = scanner.scan_images()
except ImageScannerClientError as scan_error:
results = json.dumps({'error': str(scan_error)})
host_state = results if 'error' in results else \
scanner.get_docker_json(results['json_url'])
self.uber_docker[profile.profile] = host_state
self.num_complete += 1
self.last_completed = " Completed {0}".format(profile.profile)
def scan_multiple_hosts(self, profile_list, allimages=False, images=False,
allcontainers=False, onlyactive=False,
remote_threads=4, threads=0):
'''
Scan multiple hosts and returns an uber-docker object
which is basically an object with one or more docker
state objects in it.
'''
if (threads > 0):
self.threads = threads
if (threads < 2 or threads > 4):
raise ImageScannerClientError("Thread count must be between 2 "
"and 4")
scan_args = self.args_tuple(allimages=allimages, images=images,
allcontainers=allcontainers,
onlyactive=onlyactive)
# Check to make sure a scan type was selected
if not scan_args.allimages and not scan_args.images and not \
scan_args.allcontainers and not scan_args.onlyactive:
raise ImageScannerClientError("You must select \
a scan type")
# Check to make sure only one scan type was selected
if len([x for x in [scan_args.allimages, scan_args.images,
scan_args.allcontainers, scan_args.onlyactive]
if x is True]) > 1:
raise ImageScannerClientError("You may only select one \
type of scan")
# Check profile names are valid
all_profile_names = self.get_all_profile_names()
self._check_profile_is_valid(all_profile_names, profile_list)
# Obtain list of profiles
profiles = self.return_profiles(profile_list)
self.num_total = len(profiles)
# FIXME
# Make this a variable based on desired number
pool = ThreadPool(remote_threads)
pool.map(self.thread_profile_wrapper,
[(x, scan_args.onlyactive, scan_args.allcontainers,
scan_args.allimages, scan_args.images) for x in profiles])
with open(self.uber_file_path, 'w') as state_file:
json.dump(self.uber_docker, state_file)
return self.uber_docker
@staticmethod
def _check_profile_is_valid(all_profile_names, profile_list):
''' Checks a list of profiles to make sure they are valid '''
for profile in profile_list:
if profile not in all_profile_names:
raise ImageScannerClientError("Profile {0} is invalid"
.format(profile))
def load_uber(self):
''' Loads the uber json file'''
uber_obj = json.loads(open(self.uber_file_path).read())
return uber_obj
@staticmethod
def _sum_cves(scan_results_obj):
''' Returns the total number of CVEs found'''
num_cves = 0
sev_list = ['Critical', 'Important', 'Moderate', 'Low']
for sev in sev_list:
if sev in scan_results_obj.keys():
num_cves += scan_results_obj[sev]['num']
return num_cves
def mult_host_mini_pprint(self, uber_obj):
''' Pretty print the results of a multi host scan'''
print("\n")
print("{0:16} {1:15} {2:12}".format("Host", "Docker ID", "Results"))
print("-" * 50)
prev_host = None
for host in uber_obj.keys():
if 'error' in uber_obj[host]:
print("{0:16} {1:15} {2:12}"\
.format(host, "", json.loads(uber_obj[host])['error']))
print("")
continue
for scan_obj in uber_obj[host]['scanned_content']:
tmp_obj = uber_obj[host]['host_results'][scan_obj]
is_rhel = tmp_obj['isRHEL']
if is_rhel:
if len(tmp_obj['cve_summary']['scan_results'].keys()) < 1:
result = "Clean"
else:
num_cves = self._sum_cves(tmp_obj['cve_summary']
['scan_results'])
result = "Has {0} CVEs".format(num_cves)
else:
result = "Not based on RHEL"
if host is not prev_host:
out_host = host
prev_host = host
else:
out_host = ""
print("{0:16} {1:15} {2:12}".format(out_host, scan_obj[:12],
result))
print("")
openscap-daemon-0.1.10/openscap_daemon/cve_scanner/reporter.py 0000664 0000000 0000000 00000006403 13237071060 0024501 0 ustar 00root root 0000000 0000000 # Copyright (C) 2015 Brent Baude
# Copyright (C) 2015 Red Hat Inc., Durham, North Carolina.
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with openscap-daemon. If not, see .
'''Reporter Class'''
import collections
import os
class Reporter(object):
''' Does stdout reporting '''
def __init__(self, appc):
self.output = collections.namedtuple('Summary', 'iid, cid, os, sevs,'
'log, msg',)
self.list_of_outputs = []
self.ac = appc
self.report_dir = os.path.join(self.ac.reportdir, "reports")
self.ac.docker_state = os.path.join(self.report_dir,
"docker_state.json")
if not os.path.exists(self.report_dir):
os.mkdir(self.report_dir)
self.content = ""
def report_summary(self):
'''
This function is the primary function to output results
to stdout when running the image-scanner
'''
for image in self.list_of_outputs:
short_cid_list = []
image_json = {image.iid: {}}
image_json[image.iid]['xml_path'] = os.path.join(
self.report_dir, image.iid + ".xml")
if image.msg is None:
for cid in image.cid:
short_cid_list.append(cid[:12])
image_json[image.iid]['cids'] = short_cid_list
image_json[image.iid]['critical'] = image.sevs['Critical']
image_json[image.iid]['important'] = \
image.sevs['Important']
image_json[image.iid]['moderate'] = image.sevs['Moderate']
image_json[image.iid]['low'] = image.sevs['Low']
image_json[image.iid]['os'] = image.os
else:
image_json[image.iid]['msg'] = image.msg
self.ac.return_json[image.iid] = image_json[image.iid]
report_files = []
for image in self.list_of_outputs:
if image.msg is None:
short_image = image.iid[:12] + ".scap"
out = open(os.path.join(self.report_dir, short_image), 'w')
report_files.append(short_image)
out.write(image.log)
out.close()
for report in report_files:
os.path.join(self.report_dir, report)
def _get_dtype(self, iid):
''' Returns whether the given id is an image or container '''
# Images
for image in self.ac.allimages:
if image['Id'].startswith(iid):
return "Image"
# Containers
for con in self.ac.cons:
if con['Id'].startswith(iid):
return "Container"
return None
openscap-daemon-0.1.10/openscap_daemon/cve_scanner/scan.py 0000664 0000000 0000000 00000024612 13237071060 0023565 0 ustar 00root root 0000000 0000000 # Copyright (C) 2015 Brent Baude
# Copyright (C) 2015 Red Hat Inc., Durham, North Carolina.
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with openscap-daemon. If not, see .
import os
import collections
import time
import logging
import subprocess
import xml.etree.ElementTree as ET
import platform
import sys
import bz2
from threading import Lock
if sys.version_info < (3,):
from StringIO import StringIO
else:
from io import StringIO
class Scan(object):
# Fix race-condition in atomic mount/unmount
# We don't want to do mount and unmount simultaneously
_mount_lock = Lock()
def __init__(self, image_uuid, con_uuids, output, appc, mnt_dir="/tmp"):
self.mnt_dir = mnt_dir
self.image_name = image_uuid
self.ac = appc
self.CVEs = collections.namedtuple('CVEs', 'title, severity,'
'cve_ref_id, cve_ref_url,'
'rhsa_ref_id, rhsa_ref_url')
self.list_of_CVEs = []
self.con_uuids = con_uuids
self.output = output
self.report_dir = os.path.join(self.ac.workdir, "reports")
if not os.path.exists(self.report_dir):
os.mkdir(self.report_dir)
start = time.time()
from Atomic.mount import DockerMount
self.DM = DockerMount(self.mnt_dir, mnt_mkdir=True)
with Scan._mount_lock:
self.dm_results = self.DM.mount(image_uuid)
logging.debug("Created scanning chroot in {0}"
" seconds".format(time.time() - start))
self.dest = self.dm_results
def get_release(self):
etc_release_path = os.path.join(self.dest, "rootfs",
"etc/redhat-release")
if not os.path.exists(etc_release_path):
logging.info("{0} is not RHEL based".format(self.image_name))
return False
self.os_release = open(etc_release_path).read()
rhel = 'Red Hat Enterprise Linux'
if rhel in self.os_release:
logging.debug("{0} is {1}".format(self.image_name,
self.os_release.rstrip()))
return True
else:
logging.info("{0} is {1}".format(self.image_name,
self.os_release.rstrip()))
return False
def scan(self):
logging.debug("Scanning chroot {0}".format(self.image_name))
hostname = open("/etc/hostname").read().rstrip()
os.environ["OSCAP_PROBE_ARCHITECTURE"] = platform.processor()
os.environ["OSCAP_PROBE_ROOT"] = os.path.join(self.dest, "rootfs")
os.environ["OSCAP_PROBE_OS_NAME"] = platform.system()
os.environ["OSCAP_PROBE_OS_VERSION"] = platform.release()
os.environ["OSCAP_PROBE_"
"PRIMARY_HOST_NAME"] = "{0}:{1}".format(hostname,
self.image_name)
from oscap_docker_python.get_cve_input import getInputCVE
# We only support RHEL 6|7 in containers right now
osc = getInputCVE("/tmp")
if "Red Hat Enterprise Linux" in self.os_release:
if "7." in self.os_release:
self.chroot_cve_file = os.path.join(
self.ac.workdir, osc.dist_cve_name.format("7"))
if "6." in self.os_release:
self.chroot_cve_file = os.path.join(
self.ac.workdir, osc.dist_cve_name.format("6"))
cmd = ['oscap', 'oval', 'eval', '--report',
os.path.join(self.report_dir,
self.image_name + '.html'),
'--results',
os.path.join(self.report_dir,
self.image_name + '.xml'), self.chroot_cve_file]
logging.debug(
"Starting evaluation with command '%s'.",
" ".join(cmd))
try:
self.result = subprocess.check_output(cmd).decode("utf-8")
except Exception:
pass
# def capture_run(self, cmd):
# '''
# Subprocess command that captures and returns the output and
# return code.
# '''
# r = subprocess.Popen(cmd, stdout=subprocess.PIPE,
# stderr=subprocess.PIPE)
# return r.communicate(), r.returncode
def get_cons(self, fcons, short_iid):
cons = []
for image in fcons:
if image.startswith(short_iid):
for con in fcons[image]:
cons.append(con['uuid'][:12])
return cons
def report_results(self):
if not os.path.exists(self.chroot_cve_file):
from openscap_daemon.cve_scanner.scanner_error import ImageScannerClientError
raise ImageScannerClientError("Unable to find {0}"
.format(self.chroot_cve_file))
return False
cve_tree = ET.parse(bz2.BZ2File(self.chroot_cve_file))
self.cve_root = cve_tree.getroot()
for line in self.result.splitlines():
split_line = line.split(':')
# Not in love with how I did this
# Should find a better marked to know if it is a line
# a parsable line.
if (len(split_line) == 5) and ('true' in split_line[4]):
self._return_xml_values(line.split()[1][:-1])
sev_dict = {}
sum_log = StringIO()
sum_log.write("Image: {0} ({1})".format(self.image_name,
self.os_release))
cons = self.get_cons(self.ac.fcons, self.image_name)
sum_log.write("\nContainers based on this image ({0}): {1}\n"
.format(len(cons), ", ".join(cons)))
for sev in ['Critical', 'Important', 'Moderate', 'Low']:
sev_counter = 0
for cve in self.list_of_CVEs:
if cve.severity == sev:
sev_counter += 1
sum_log.write("\n")
fields = list(self.CVEs._fields)
fields.remove('title')
sum_log.write("{0}{1}: {2}\n"
.format(" " * 5, "Title",
getattr(cve, "title")))
for field in fields:
sum_log.write("{0}{1}: {2}\n"
.format(" " * 10, field.title(),
getattr(cve, field)))
sev_dict[sev] = sev_counter
self.output.list_of_outputs.append(
self.output.output(iid=self.image_name, cid=self.con_uuids,
os=self.os_release, sevs=sev_dict,
log=sum_log.getvalue(), msg=None))
sum_log.close()
def _report_not_rhel(self, image):
msg = "{0} is not based on RHEL".format(image[:8])
self.output.list_of_outputs.append(
self.output.output(iid=image, cid=None,
os=None, sevs=None,
log=None, msg=msg))
def _return_xml_values(self, cve):
cve_string = ("{http://oval.mitre.org/XMLSchema/oval-definitions-5}"
"definitions/*[@id='%s']" % cve)
cve_xml = self.cve_root.find(cve_string)
title = cve_xml.find("{http://oval.mitre.org/XMLSchema/oval-"
"definitions-5}metadata/"
"{http://oval.mitre.org/XMLSchema/"
"oval-definitions-5}title")
cve_id = cve_xml.find("{http://oval.mitre.org/XMLSchema/"
"oval-definitions-5}metadata/{http://oval.mitre."
"org/XMLSchema/oval-definitions-5}reference"
"[@source='CVE']")
sev = (cve_xml.find("{http://oval.mitre.org/XMLSchema/oval-definitions"
"-5}metadata/{http://oval.mitre.org/XMLSchema/oval"
"-definitions-5}advisory/")).text
if cve_id is not None:
cve_ref_id = cve_id.attrib['ref_id']
cve_ref_url = cve_id.attrib['ref_url']
else:
cve_ref_id = None
cve_ref_url = None
rhsa_id = cve_xml.find("{http://oval.mitre.org/XMLSchema/oval-"
"definitions-5}metadata/{http://oval.mitre.org"
"/XMLSchema/oval-definitions-5}reference"
"[@source='RHSA']")
if rhsa_id is not None:
rhsa_ref_id = rhsa_id.attrib['ref_id']
rhsa_ref_url = rhsa_id.attrib['ref_url']
else:
rhsa_ref_id = None
rhsa_ref_url = None
self.list_of_CVEs.append(
self.CVEs(title=title.text, cve_ref_id=cve_ref_id,
cve_ref_url=cve_ref_url, rhsa_ref_id=rhsa_ref_id,
rhsa_ref_url=rhsa_ref_url, severity=sev))
def _get_rpms(self):
# TODO: External dep!
import rpm
chroot_os = os.path.join(self.dest, "rootfs")
ts = rpm.TransactionSet(chroot_os)
ts.setVSFlags((rpm._RPMVSF_NOSIGNATURES | rpm._RPMVSF_NODIGESTS))
image_rpms = []
for hdr in ts.dbMatch(): # No sorting
if hdr['name'] == 'gpg-pubkey':
continue
else:
foo = "{0}-{1}-{2}-{3}-{4}".format(hdr['name'],
hdr['epochnum'],
hdr['version'],
hdr['release'],
hdr['arch'])
image_rpms.append(foo)
return image_rpms
def unmount(self):
with Scan._mount_lock:
self.DM.unmount_path(self.dest)
self.DM._clean_temp_container_by_path(self.dest)
os.rmdir(self.dest)
openscap-daemon-0.1.10/openscap_daemon/cve_scanner/scanner_client.py 0000664 0000000 0000000 00000012014 13237071060 0025621 0 ustar 00root root 0000000 0000000 # Copyright (C) 2015 Brent Baude
# Copyright (C) 2015 Red Hat Inc., Durham, North Carolina.
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with openscap-daemon. If not, see .
from openscap_daemon import dbus_utils
from openscap_daemon.cve_scanner.scanner_error import ImageScannerClientError
import os
import dbus
import dbus.mainloop.glib
import json
import collections
import docker
# TODO: external dep!
from slip.dbus import polkit
class Client(object):
''' The image-scanner client API '''
image_tmp = "/var/tmp/image-scanner"
db_timeout = 99999
tup_names = ['number', 'workdir', 'logfile', 'onlycache',
'reportdir']
tup = collections.namedtuple('args', tup_names)
def __init__(self, number=2,
logfile=os.path.join(image_tmp, "openscap.log"),
onlycache=False,
reportdir=image_tmp, workdir=image_tmp):
self.arg_tup = self.tup(number=number, logfile=logfile,
onlycache=onlycache, reportdir=reportdir,
workdir=workdir)
self.arg_dict = {'number': number, 'logfile': logfile,
'onlycache': onlycache, 'reportdir': reportdir,
'workdir': workdir}
self._docker_ping()
self.num_threads = number
self.bus = dbus.SessionBus()
self.dbus_object = self.bus.get_object(dbus_utils.BUS_NAME,
dbus_utils.OBJECT_PATH)
self.logfile = logfile
self.onlycache = onlycache
self.reportdir = reportdir
self.workdir = workdir
self.onlyactive = False
self.allcontainers = False
self.allimages = False
self.images = False
@staticmethod
def _docker_ping():
d_conn = docker.Client()
try:
d_conn.ping()
except Exception:
raise ImageScannerClientError("The docker daemon does not appear"
"to be running")
@polkit.enable_proxy
def inspect_container(self, cid):
ret = self.dbus_object.inspect_container(
cid,
dbus_interface=dbus_utils.DBUS_INTERFACE,
timeout=self.db_timeout
)
return json.loads(ret)
@polkit.enable_proxy
def get_images_info(self):
ret = self.dbus_object.images(
dbus_interface=dbus_utils.DBUS_INTERFACE,
timeout=self.db_timeout
)
return json.loads(ret)
@polkit.enable_proxy
def get_containers_info(self):
ret = self.dbus_object.containers(
dbus_interface=dbus_utils.DBUS_INTERFACE,
timeout=self.db_timeout
)
return json.loads(ret)
@polkit.enable_proxy
def inspect_image(self, iid):
ret = self.dbus_object.inspect_image(
iid,
dbus_interface=dbus_utils.DBUS_INTERFACE,
timeout=self.db_timeout
)
return json.loads(ret)
def debug_json(self, json_data):
''' Debug function that pretty prints json objects'''
print(json.dumps(json_data, indent=4, separators=(',', ': ')))
@polkit.enable_proxy
def scan_containers(self, only_active=False):
if only_active:
self.onlyactive = True
else:
self.allcontainers = True
ret = self.dbus_object.scan_containers(
self.onlyactive,
self.allcontainers,
self.num_threads,
dbus_interface=dbus_utils.DBUS_INTERFACE,
timeout=self.db_timeout
)
return json.loads(ret)
@polkit.enable_proxy
def scan_images(self, all_images=False):
if all_images:
self.allimages = True
else:
self.images = True
ret = self.dbus_object.scan_images(
self.allimages, self.images,
self.num_threads,
dbus_interface=dbus_utils.DBUS_INTERFACE,
timeout=self.db_timeout
)
return json.loads(ret)
@polkit.enable_proxy
def scan_list(self, scan_list):
if not isinstance(scan_list, list):
raise ImageScannerClientError("Input to scan_list must be in"
"the form of a list")
ret = self.dbus_object.scan_list(
scan_list, self.num_threads,
dbus_interface=dbus_utils.DBUS_INTERFACE,
timeout=self.db_timeout
)
return json.loads(ret)
openscap-daemon-0.1.10/openscap_daemon/cve_scanner/scanner_error.py 0000664 0000000 0000000 00000001621 13237071060 0025476 0 ustar 00root root 0000000 0000000 # Copyright (C) 2015 Brent Baude
# Copyright (C) 2015 Red Hat Inc., Durham, North Carolina.
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with openscap-daemon. If not, see .
import dbus
class ImageScannerClientError(dbus.DBusException):
"""ImageScanner error"""
dbus_error_name = 'org.atomic.Exception'
openscap-daemon-0.1.10/openscap_daemon/dbus_daemon.py 0000664 0000000 0000000 00000052163 13237071060 0022635 0 ustar 00root root 0000000 0000000 # Copyright 2015 Red Hat Inc., Durham, North Carolina.
# All Rights Reserved.
#
# openscap-daemon is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 2.1 of the License, or
# (at your option) any later version.
#
# openscap-daemon is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
# You should have received a copy of the GNU Lesser General Public License
# along with openscap-daemon. If not, see .
#
# Authors:
# Martin Preisler
from openscap_daemon import system
from openscap_daemon import EvaluationSpec
from openscap_daemon import dbus_utils
from openscap_daemon.cve_scanner.cve_scanner import Worker
from openscap_daemon import version
import dbus
import dbus.service
import threading
from datetime import datetime
import json
# Internal note: Python does not support unsigned long integer while dbus does,
# to avoid weird issues I just use 64bit integer in the interface signatures.
# "2^63-1 IDs should be enough for everyone."
class OpenSCAPDaemonDbus(dbus.service.Object):
def __init__(self, bus, config_file):
super(OpenSCAPDaemonDbus, self).__init__(bus, dbus_utils.OBJECT_PATH)
self.system = system.System(config_file)
self.system.load_tasks()
self.system_worker_thread = threading.Thread(
target=lambda: self.system.schedule_tasks_worker()
)
self.system_worker_thread.daemon = True
self.system_worker_thread.start()
@dbus.service.method(dbus_interface=dbus_utils.DBUS_INTERFACE,
in_signature="", out_signature="(nnn)")
def GetVersion(self):
"""Retrieves OpenSCAP-daemon version in a tuple format, suitable
for version comparisons.
"""
return (
version.VERSION_MAJOR,
version.VERSION_MINOR,
version.VERSION_PATCH
)
@dbus.service.method(dbus_interface=dbus_utils.DBUS_INTERFACE,
in_signature="", out_signature="as")
def GetSSGChoices(self):
"""Retrieves absolute paths of SSG source datastreams that are
available.
"""
return self.system.get_ssg_choices()
@dbus.service.method(dbus_interface=dbus_utils.DBUS_INTERFACE,
in_signature="ss", out_signature="a{ss}")
def GetProfileChoicesForInput(self, input_file, tailoring_file):
"""Figures out profile ID -> profile title mappings of all available
profiles given the input_file and (optionally) the tailoring_file.
"""
return self.system.get_profile_choices_for_input(
input_file, tailoring_file
)
@dbus.service.method(dbus_interface=dbus_utils.DBUS_INTERFACE,
in_signature="", out_signature="a(xsi)")
def GetAsyncActionsStatus(self):
return self.system.async.get_status()
@dbus.service.method(dbus_interface=dbus_utils.DBUS_INTERFACE,
in_signature="s", out_signature="(sssn)")
def EvaluateSpecXML(self, xml_source):
"""Deprecated, use EvaluateSpecXMLAsync instead
"""
spec = EvaluationSpec()
spec.load_from_xml_source(xml_source)
arf, stdout, stderr, exit_code = spec.evaluate(self.system.config)
return (arf, stdout, stderr, exit_code)
@dbus.service.method(dbus_interface=dbus_utils.DBUS_INTERFACE,
in_signature="s", out_signature="n")
def EvaluateSpecXMLAsync(self, xml_source):
spec = EvaluationSpec()
spec.load_from_xml_source(xml_source)
token = self.system.evaluate_spec_async(spec)
return token
@dbus.service.method(dbus_interface=dbus_utils.DBUS_INTERFACE,
in_signature="n", out_signature="(bsssn)")
def GetEvaluateSpecXMLAsyncResults(self, token):
try:
arf, stdout, stderr, exit_code = \
self.system.get_evaluate_spec_async_results(token)
return (True, arf, stdout, stderr, exit_code)
except system.ResultsNotAvailable:
return (False, "", "", "", 1)
@dbus.service.method(dbus_interface=dbus_utils.DBUS_INTERFACE,
in_signature="n", out_signature="")
def CancelEvaluateSpecXMLAsync(self, token):
# TODO
pass
@dbus.service.method(dbus_interface=dbus_utils.DBUS_INTERFACE,
in_signature="", out_signature="ax")
def ListTaskIDs(self):
"""Returns a list of IDs of tasks that System has loaded from config
files.
"""
return self.system.list_task_ids()
@dbus.service.method(dbus_interface=dbus_utils.DBUS_INTERFACE,
in_signature="xs", out_signature="")
def SetTaskTitle(self, task_id, title):
"""Set title of existing task with given ID.
The change is persistent after the function returns.
"""
return self.system.set_task_title(task_id, title)
@dbus.service.method(dbus_interface=dbus_utils.DBUS_INTERFACE,
in_signature="x", out_signature="s")
def GetTaskTitle(self, task_id):
"""Retrieves title of task with given ID.
"""
return self.system.get_task_title(task_id)
@dbus.service.method(dbus_interface=dbus_utils.DBUS_INTERFACE,
in_signature="x", out_signature="s")
def GenerateGuideForTask(self, task_id):
"""Generates and returns HTML guide for a task with given ID.
"""
return self.system.generate_guide_for_task(task_id)
@dbus.service.method(dbus_interface=dbus_utils.DBUS_INTERFACE,
in_signature="xs", out_signature="s")
def GenerateFixForTask(self, task_id, fix_type):
"""Generates and returns fix script for a task with given ID.
"""
return self.system.generate_fix_for_task(task_id, fix_type)
@dbus.service.method(dbus_interface=dbus_utils.DBUS_INTERFACE,
in_signature="x", out_signature="")
def RunTaskOutsideSchedule(self, task_id):
"""Given task will be run as soon as possible without affecting its
schedule. This feature is useful mainly for testing purposes.
"""
return self.system.run_task_outside_schedule(task_id)
@dbus.service.method(dbus_interface=dbus_utils.DBUS_INTERFACE,
in_signature="", out_signature="x")
def CreateTask(self):
"""Creates a new task with empty contents, the task is created
in a disabled state so it won't be run.
The task is not persistent until some of its attributes are changed.
Empty tasks are worthless, so we don't save them until they have at
least some data.
"""
return self.system.create_task()
@dbus.service.method(dbus_interface=dbus_utils.DBUS_INTERFACE,
in_signature="xb", out_signature="")
def RemoveTask(self, task_id, remove_results):
"""Removes task with given ID and deletes its config file. The task has
to be disabled, else the operation fails.
The change is persistent after the function returns.
"""
return self.system.remove_task(task_id, remove_results)
@dbus.service.method(dbus_interface=dbus_utils.DBUS_INTERFACE,
in_signature="xb", out_signature="")
def SetTaskEnabled(self, task_id, enabled):
"""Sets enabled flag of an existing task with given ID.
The change is persistent after the function returns.
"""
return self.system.set_task_enabled(task_id, enabled)
@dbus.service.method(dbus_interface=dbus_utils.DBUS_INTERFACE,
in_signature="x", out_signature="b")
def GetTaskEnabled(self, task_id):
"""Retrieves the enabled flag of an existing task with given ID.
"""
return self.system.get_task_enabled(task_id)
@dbus.service.method(dbus_interface=dbus_utils.DBUS_INTERFACE,
in_signature="xs", out_signature="")
def SetTaskTarget(self, task_id, target):
"""Set target of existing task with given ID.
The change is persistent after the function returns.
"""
return self.system.set_task_target(task_id, target)
@dbus.service.method(dbus_interface=dbus_utils.DBUS_INTERFACE,
in_signature="x", out_signature="s")
def GetTaskTarget(self, task_id):
"""Retrieves target of existing task with given ID.
"""
return self.system.get_task_target(task_id)
@dbus.service.method(dbus_interface=dbus_utils.DBUS_INTERFACE,
in_signature="x", out_signature="x")
def GetTaskCreatedTimestamp(self, task_id):
"""Get timestamp of task creation
"""
return self.system.get_task_created_timestamp(task_id)
@dbus.service.method(dbus_interface=dbus_utils.DBUS_INTERFACE,
in_signature="x", out_signature="x")
def GetTaskModifiedTimestamp(self, task_id):
"""Get timestamp of task modification
"""
return self.system.get_task_modified_timestamp(task_id)
@dbus.service.method(dbus_interface=dbus_utils.DBUS_INTERFACE,
in_signature="xs", out_signature="")
def SetTaskInput(self, task_id, input_):
"""Set input of existing task with given ID.
input can be absolute file path or the XML source itself, this is
is autodetected.
The change is persistent after the function returns.
"""
return self.system.set_task_input(
task_id, input_ if input_ != "" else None
)
@dbus.service.method(dbus_interface=dbus_utils.DBUS_INTERFACE,
in_signature="xs", out_signature="")
def SetTaskTailoring(self, task_id, tailoring):
"""Set tailoring of existing task with given ID.
tailoring can be absolute file path or the XML source itself, this is
is autodetected.
The change is persistent after the function returns.
"""
return self.system.set_task_tailoring(
task_id, tailoring if tailoring != "" else None
)
@dbus.service.method(dbus_interface=dbus_utils.DBUS_INTERFACE,
in_signature="xs", out_signature="")
def SetTaskProfileID(self, task_id, profile_id):
"""Set profile ID of existing task with given ID.
The change is persistent after the function returns.
"""
return self.system.set_task_profile_id(task_id, profile_id)
@dbus.service.method(dbus_interface=dbus_utils.DBUS_INTERFACE,
in_signature="xb", out_signature="")
def SetTaskOnlineRemediation(self, task_id, online_remediation):
"""Sets whether online remediation of existing task with given ID
is enabled.
The change is persistent after the function returns.
"""
return self.system.set_task_online_remediation(
task_id, online_remediation
)
@dbus.service.method(dbus_interface=dbus_utils.DBUS_INTERFACE,
in_signature="xs", out_signature="")
def SetTaskScheduleNotBefore(self, task_id, schedule_not_before_str):
"""Sets time when the task is next scheduled to run. The time is passed
as a string in format YYYY-MM-DDTHH:MM in UTC with no timezone info!
Example: 2015-05-14T13:49
The change is persistent after the function returns.
"""
schedule_not_before = datetime.strptime(
schedule_not_before_str,
"%Y-%m-%dT%H:%M"
)
return self.system.set_task_schedule_not_before(
task_id, schedule_not_before
)
@dbus.service.method(dbus_interface=dbus_utils.DBUS_INTERFACE,
in_signature="xx", out_signature="")
def SetTaskScheduleRepeatAfter(self, task_id, schedule_repeat_after):
"""Sets number of hours after which the task should be repeated.
For example 24 for daily tasks, 24*7 for weekly tasks, ...
The change is persistent after the function returns.
"""
return self.system.set_task_schedule_repeat_after(
task_id, schedule_repeat_after
)
@dbus.service.method(dbus_interface=dbus_utils.DBUS_INTERFACE,
in_signature="x", out_signature="ax")
def GetTaskResultIDs(self, task_id):
"""Retrieves list of available task result IDs.
"""
return self.system.get_task_result_ids(task_id)
@dbus.service.method(dbus_interface=dbus_utils.DBUS_INTERFACE,
in_signature="xx", out_signature="x")
def GetResultCreatedTimestamp(self, task_id, result_id):
"""Return timestamp of result creation
"""
return self.system.get_task_result_created_timestamp(task_id, result_id)
@dbus.service.method(dbus_interface=dbus_utils.DBUS_INTERFACE,
in_signature="xx", out_signature="s")
def GetXMLOfTaskResult(self, task_id, result_id):
"""Retrieves full XML of result of given task.
This can be an ARF or OVAL result file, depending on task EvaluationMode
Deprecated, use GetXMLOfTaskResult instead.
"""
return self.system.get_xml_of_task_result(task_id, result_id)
@dbus.service.method(dbus_interface=dbus_utils.DBUS_INTERFACE,
in_signature="xx", out_signature="s")
def GetARFOfTaskResult(self, task_id, result_id):
"""Retrieves full ARF of result of given task.
Deprecated, use GetXMLOfTaskResult instead.
"""
return self.system.get_xml_of_task_result(task_id, result_id)
@dbus.service.method(dbus_interface=dbus_utils.DBUS_INTERFACE,
in_signature="x", out_signature="")
def RemoveTaskResults(self, task_id):
"""Remove all results of given task.
"""
return self.system.remove_task_results(task_id)
@dbus.service.method(dbus_interface=dbus_utils.DBUS_INTERFACE,
in_signature="xx", out_signature="")
def RemoveTaskResult(self, task_id, result_id):
"""Remove result of given task.
"""
return self.system.remove_task_result(task_id, result_id)
@dbus.service.method(dbus_interface=dbus_utils.DBUS_INTERFACE,
in_signature="xx", out_signature="s")
def GetStdOutOfTaskResult(self, task_id, result_id):
"""Retrieves full stdout of result of given task.
"""
return self.system.get_stdout_of_task_result(task_id, result_id)
@dbus.service.method(dbus_interface=dbus_utils.DBUS_INTERFACE,
in_signature="xx", out_signature="s")
def GetStdErrOfTaskResult(self, task_id, result_id):
"""Retrieves full stderr of result of given task.
"""
return self.system.get_stderr_of_task_result(task_id, result_id)
@dbus.service.method(dbus_interface=dbus_utils.DBUS_INTERFACE,
in_signature="xx", out_signature="i")
def GetExitCodeOfTaskResult(self, task_id, result_id):
"""Retrieves exit code of result of given task.
"""
return self.system.get_exit_code_of_task_result(task_id, result_id)
@dbus.service.method(dbus_interface=dbus_utils.DBUS_INTERFACE,
in_signature="xx", out_signature="s")
def GenerateReportForTaskResult(self, task_id, result_id):
"""Generates and returns HTML report for report of given task.
"""
return self.system.generate_report_for_task_result(task_id, result_id)
@dbus.service.method(dbus_interface=dbus_utils.DBUS_INTERFACE,
in_signature="xxs", out_signature="s")
def GenerateFixForTaskResult(self, task_id, result_id, fix_type):
"""Generates and returns remediation script for result of given task.
"""
return self.system.generate_fix_for_task_result(task_id, result_id, fix_type)
@dbus.service.method(dbus_interface=dbus_utils.DBUS_INTERFACE, in_signature='s',
out_signature='s')
def inspect_container(self, cid):
"""Returns inspect data of a container.
Used by `atomic scan`. Do not break this interface!
"""
import docker
docker_conn = docker.Client()
inspect_data = docker_conn.inspect_container(cid)
return json.dumps(inspect_data)
@dbus.service.method(dbus_interface=dbus_utils.DBUS_INTERFACE, in_signature='s',
out_signature='s')
def inspect_image(self, iid):
"""Returns inspect data of an image.
Used by `atomic scan`. Do not break this interface!
"""
import docker
docker_conn = docker.Client()
inspect_data = docker_conn.inspect_image(iid)
return json.dumps(inspect_data)
@dbus.service.method(dbus_interface=dbus_utils.DBUS_INTERFACE, out_signature='s')
def images(self):
"""Used by `atomic scan`. Do not break this interface!
"""
import docker
docker_conn = docker.Client()
images = docker_conn.images(all=True)
return json.dumps(images)
@dbus.service.method(dbus_interface=dbus_utils.DBUS_INTERFACE, out_signature='s')
def containers(self):
"""Used by `atomic scan`. Do not break this interface!
"""
import docker
docker_conn = docker.Client()
cons = docker_conn.containers(all=True)
return json.dumps(cons)
@staticmethod
def _parse_only_cache(config, fetch_cve):
if fetch_cve == 2:
return config.fetch_cve
elif fetch_cve == 1:
return True
elif fetch_cve == 0:
return False
else:
raise RuntimeError("Invalid value %i for fetch_cve" % (fetch_cve))
@dbus.service.method(dbus_interface=dbus_utils.DBUS_INTERFACE,
in_signature='bbiy', out_signature='s')
def scan_containers(self, onlyactive, allcontainers, number, fetch_cve=2):
"""fetch_cve -
0 to enable CVE fetch
1 to disable CVE fetch
2 to use defaults from oscapd config file
"""
worker = Worker(onlyactive=onlyactive, allcontainers=allcontainers,
number=number,
fetch_cve=self._parse_only_cache(self.system.config, int(fetch_cve)),
fetch_cve_url=self.system.config.fetch_cve_url)
return_json = worker.start_application()
return json.dumps(return_json)
@dbus.service.method(dbus_interface=dbus_utils.DBUS_INTERFACE, in_signature='bbiy',
out_signature='s')
def scan_images(self, allimages, images, number, fetch_cve=2):
"""fetch_cve -
0 to enable CVE fetch
1 to disable CVE fetch
2 to use defaults from oscapd config file
"""
worker = Worker(allimages=allimages, images=images,
number=number,
fetch_cve=self._parse_only_cache(self.system.config, int(fetch_cve)),
fetch_cve_url=self.system.config.fetch_cve_url)
return_json = worker.start_application()
return json.dumps(return_json)
@dbus.service.method(dbus_interface=dbus_utils.DBUS_INTERFACE,
in_signature='asiy', out_signature='s')
def scan_list(self, scan_list, number, fetch_cve=2):
"""fetch_cve -
0 to enable CVE fetch
1 to disable CVE fetch
2 to use defaults from oscapd config file
Used by `atomic scan`. Do not break this interface!
Deprecated, please use CVEScanListAsync
"""
worker = Worker(scan=scan_list, number=number,
fetch_cve=self._parse_only_cache(self.system.config, int(fetch_cve)),
fetch_cve_url=self.system.config.fetch_cve_url)
return_json = worker.start_application()
return json.dumps(return_json)
@dbus.service.method(dbus_interface=dbus_utils.DBUS_INTERFACE,
in_signature='asiy', out_signature='n')
def CVEScanListAsync(self, scan_list, number, fetch_cve):
worker = Worker(
scan=scan_list, number=number,
fetch_cve=self._parse_only_cache(self.system.config, int(fetch_cve)),
fetch_cve_url=self.system.config.fetch_cve_url
)
return self.system.evaluate_cve_scanner_worker_async(worker)
@dbus.service.method(dbus_interface=dbus_utils.DBUS_INTERFACE,
in_signature="n", out_signature="(bs)")
def GetCVEScanListAsyncResults(self, token):
try:
json_results = \
self.system.get_evaluate_cve_scanner_worker_async_results(token)
return (True, json.dumps(json_results))
except system.ResultsNotAvailable:
return (False, "")
@dbus.service.method(dbus_interface=dbus_utils.DBUS_INTERFACE,
in_signature="n", out_signature="")
def CancelCVEScanListAsync(self, token):
# TODO
pass
openscap-daemon-0.1.10/openscap_daemon/dbus_utils.py 0000664 0000000 0000000 00000002143 13237071060 0022523 0 ustar 00root root 0000000 0000000 # Copyright 2015 Red Hat Inc., Durham, North Carolina.
# All Rights Reserved.
#
# openscap-daemon is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 2.1 of the License, or
# (at your option) any later version.
#
# openscap-daemon is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
# You should have received a copy of the GNU Lesser General Public License
# along with openscap-daemon. If not, see .
#
# Authors:
# Martin Preisler
import os
OBJECT_PATH = "/OpenSCAP/daemon"
DBUS_INTERFACE = "org.OpenSCAP.daemon.Interface"
BUS_NAME = "org.OpenSCAP.daemon"
def get_dbus():
import dbus
var_name = "OSCAPD_SESSION_BUS"
if var_name in os.environ and os.environ[var_name] == "1":
return dbus.SessionBus()
return dbus.SystemBus()
openscap-daemon-0.1.10/openscap_daemon/et_helpers.py 0000664 0000000 0000000 00000005076 13237071060 0022510 0 ustar 00root root 0000000 0000000 # Copyright 2015 Red Hat Inc., Durham, North Carolina.
# All Rights Reserved.
#
# openscap-daemon is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 2.1 of the License, or
# (at your option) any later version.
#
# openscap-daemon is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
# You should have received a copy of the GNU Lesser General Public License
# along with openscap-daemon. If not, see .
#
# Authors:
# Martin Preisler
def get_element_text(parent, element_name, default=None):
ret = None
for element in parent.findall(element_name):
if ret is not None:
raise RuntimeError(
"Found multiple '%s' elements." % (element_name)
)
ret = element.text
if ret is None:
return default
return ret
def get_element(parent, element_name):
ret = None
for element in parent.findall(element_name):
if ret is not None:
raise RuntimeError(
"Found multiple '%s' elements." %
(element_name)
)
ret = element
if ret is None:
raise RuntimeError(
"Found no element of tag '%s'!" %
(element_name)
)
return ret
def get_element_attr(parent, element_name, attr_name, default=None):
ret = None
for element in parent.findall(element_name):
if ret is not None:
raise RuntimeError(
"Found multiple '%s' elements with '%s' attributes." %
(element_name, attr_name)
)
ret = element.get(attr_name)
if ret is None:
return default
return ret
# taken from ElementLib and slightly tweaked for readability
def indent(elem, level=0, indent_char=" "):
i = "\n" + level * indent_char
if len(elem):
if not elem.text or not elem.text.strip():
elem.text = i + indent_char
last = None
for e in elem:
indent(e, level + 1)
if not e.tail or not e.tail.strip():
e.tail = i + indent_char
last = e
if not last.tail or not last.tail.strip():
last.tail = i
else:
if level and (not elem.tail or not elem.tail.strip()):
elem.tail = i
openscap-daemon-0.1.10/openscap_daemon/evaluation_spec.py 0000664 0000000 0000000 00000053561 13237071060 0023541 0 ustar 00root root 0000000 0000000 # Copyright 2015 Red Hat Inc., Durham, North Carolina.
# All Rights Reserved.
#
# openscap-daemon is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 2.1 of the License, or
# (at your option) any later version.
#
# openscap-daemon is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
# You should have received a copy of the GNU Lesser General Public License
# along with openscap-daemon. If not, see .
#
# Authors:
# Martin Preisler
from openscap_daemon import et_helpers
from openscap_daemon import oscap_helpers
from xml.etree import cElementTree as ElementTree
import os.path
import tempfile
import shutil
import io
class SCAPInput(object):
"""Encapsulates all sorts of SCAP input, either embedded in the spec
itself or separate in a file installed via RPM or other means.
This does not include tailoring! That is handled separately,
see SCAPTailoring class.
"""
def __init__(self):
self.file_path = None
self.temp_file = None
self.datastream_id = None
self.xccdf_id = None
def is_valid(self):
return self.file_path is not None
def get_xml_source(self):
if self.file_path is None:
return None
with io.open(self.file_path, "r", encoding="utf-8") as f:
return f.read()
def is_equivalent_to(self, other):
return \
self.get_xml_source() == other.get_xml_source() and \
self.datastream_id == other.datastream_id and \
self.xccdf_id == other.xccdf_id
def set_file_path(self, file_path):
"""Sets given file_path to be the input file. If you use this method
no temporary files will be allocated, the file_path will be passed to
`oscap` as is, in its absolute form.
"""
self.temp_file = None
if file_path is not None:
self.file_path = \
os.path.abspath(file_path) if file_path is not None else None
else:
self.file_path = None
def set_contents(self, input_contents):
"""Sets given input_contents XML to be the input source. This method
allocates a temporary file that exists for the lifetime of this
instance.
"""
if input_contents is not None:
self.temp_file = tempfile.NamedTemporaryFile()
self.temp_file.write(input_contents.encode("utf-8"))
self.temp_file.flush()
self.file_path = os.path.abspath(self.temp_file.name)
else:
self.file_path = None
def load_from_xml_element(self, element):
input_file = element.get("href")
if input_file is not None:
self.set_file_path(input_file)
else:
input_file_contents = element.text
self.set_contents(input_file_contents)
self.datastream_id = element.get("datastream_id")
self.xccdf_id = element.get("xccdf_id")
def to_xml_element(self):
if self.file_path is None:
return None
ret = ElementTree.Element("input")
if self.temp_file is None:
ret.set("href", self.file_path)
else:
with io.open(self.temp_file.name, "r", encoding="utf-8") as f:
ret.text = f.read()
if self.datastream_id is not None:
ret.set("datastream_id", self.datastream_id)
if self.xccdf_id is not None:
ret.set("xccdf_id", self.xccdf_id)
return ret
class SCAPTailoring(object):
"""Encapsulates SCAP tailoring. At this point we only support separate files
as tailorings, not the input SCAP file. The tailoring has to be plain
XCCDF tailoring, no datastreams!
"""
def __init__(self):
self.file_path = None
self.temp_file = None
def get_xml_source(self):
if self.file_path is None:
return None
with io.open(self.file_path, "r", encoding="utf-8") as f:
return f.read()
def is_equivalent_to(self, other):
return \
self.get_xml_source() == other.get_xml_source()
def set_file_path(self, file_path):
"""Sets given file_path to be the input file. If you use this method
no temporary files will be allocated, the file_path will be passed to
`oscap` as is, in its absolute form.
"""
self.temp_file = None
if file_path is not None:
self.file_path = \
os.path.abspath(file_path) if file_path is not None else None
else:
self.file_path = None
def set_contents(self, input_contents):
"""Sets given input_contents XML to be the input source. This method
allocates a temporary file that exists for the lifetime of this
instance.
"""
if input_contents is not None:
self.temp_file = tempfile.NamedTemporaryFile()
self.temp_file.write(input_contents.encode("utf-8"))
self.temp_file.flush()
self.file_path = os.path.abspath(self.temp_file.name)
else:
self.file_path = None
def load_from_xml_element(self, element):
input_file = element.get("href")
if input_file is not None:
self.set_file_path(input_file)
else:
input_file_contents = element.text
self.set_contents(input_file_contents)
def to_xml_element(self):
if self.file_path is None:
return None
ret = ElementTree.Element("tailoring")
if self.temp_file is None:
ret.set("href", self.file_path)
else:
with io.open(self.temp_file.name, "r", encoding="utf-8") as f:
ret.text = f.read()
return ret
class EvaluationSpec(object):
"""This class defined input content, tailoring, profile, ...
for an SCAP evaluation task. Everything expect schedule.
Example of a task:
Run USGCB evaluation on RHEL6 localhost machine
"""
def __init__(self):
self.mode = oscap_helpers.EvaluationMode.SOURCE_DATASTREAM
self.target = "localhost"
self.input_ = SCAPInput()
self.tailoring = SCAPTailoring()
self.result_format = "standard"
self.profile_id = None
self.online_remediation = False
self.cpe_hints = []
def __str__(self):
ret = "Evaluation spec\n"
ret += "- mode: \t%s\n" % \
(oscap_helpers.EvaluationMode.to_string(self.mode))
ret += "- target: \t%s\n" % (self.target)
ret += "- result format: \t%s\n" % (self.result_format)
ret += "- input:\n"
ret += " - file: \t%s\n" % (self.input_.file_path)
if self.input_.temp_file is not None:
ret += " - bundled"
ret += " - datastream_id: \t%s\n" % (self.input_.datastream_id)
ret += " - xccdf_id: \t%s\n" % (self.input_.xccdf_id)
ret += "- tailoring file: \t%s\n" % (self.tailoring.file_path)
if self.tailoring.temp_file is not None:
ret += " - bundled"
ret += "- profile ID: \t%s\n" % (self.profile_id)
ret += "- online remediation: \t%s\n" % \
("enabled" if self.online_remediation else "disabled")
ret += "- CPE hints: \t%s\n" % \
("none" if len(self.cpe_hints) == 0 else ", ".join(self.cpe_hints))
return ret
def is_valid(self):
if self.mode == oscap_helpers.EvaluationMode.UNKNOWN:
return False
if self.target is None:
return False
# cve_scan and standard_scan modes don't require the input element
if self.mode not in [oscap_helpers.EvaluationMode.CVE_SCAN,
oscap_helpers.EvaluationMode.STANDARD_SCAN] and \
not self.input_.is_valid():
return False
return True
def is_equivalent_to(self, other):
"""Checks that both "Task self" and "Task other" are the same except for
id_ and config_file.
"""
return \
self.mode == other.mode and \
self.target == other.target and \
self.input_.is_equivalent_to(other.input_) and \
self.tailoring.is_equivalent_to(other.tailoring) and \
self.profile_id == other.profile_id and \
self.online_remediation == other.online_remediation and \
self.cpe_hints == other.cpe_hints
def load_from_xml_element(self, element):
self.mode = oscap_helpers.EvaluationMode.from_string(
et_helpers.get_element_text(element, "mode", "sds")
)
self.target = et_helpers.get_element_text(element, "target")
self.input_ = SCAPInput()
self.input_.load_from_xml_element(
et_helpers.get_element(element, "input")
)
self.tailoring = SCAPTailoring()
try:
self.tailoring.load_from_xml_element(
et_helpers.get_element(element, "tailoring")
)
except RuntimeError:
# tailoring is optional, if it's not present just skip tailoring
pass
self.profile_id = et_helpers.get_element_text(element, "profile")
self.online_remediation = \
et_helpers.get_element_text(element, "online_remediation") == "true"
cpe_hints_str = et_helpers.get_element_text(element, "cpe_hints")
self.cpe_hints = []
if cpe_hints_str is not None:
for cpe_hint in cpe_hints_str.split(", "):
self.cpe_hints.append(cpe_hint)
def load_from_xml_source(self, xml_source):
element = ElementTree.fromstring(xml_source)
self.load_from_xml_element(element)
def load_from_xml_file(self, file_):
element = ElementTree.parse(file_)
self.load_from_xml_element(element)
def to_xml_element(self):
ret = ElementTree.Element("evaluation_spec")
mode_element = ElementTree.Element("mode")
mode_element.text = oscap_helpers.EvaluationMode.to_string(self.mode)
ret.append(mode_element)
target_element = ElementTree.Element("target")
target_element.text = self.target
ret.append(target_element)
input_element = self.input_.to_xml_element()
if input_element is not None:
ret.append(input_element)
tailoring_element = self.tailoring.to_xml_element()
if tailoring_element is not None:
ret.append(tailoring_element)
if self.profile_id is not None:
profile_element = ElementTree.Element("profile")
profile_element.text = self.profile_id
ret.append(profile_element)
online_remediation_element = ElementTree.Element("online_remediation")
online_remediation_element.text = \
"true" if self.online_remediation else "false"
ret.append(online_remediation_element)
if len(self.cpe_hints) > 0:
cpe_hints_element = ElementTree.Element("cpe_hints")
cpe_hints_element.text = ", ".join(self.cpe_hints)
ret.append(cpe_hints_element)
return ret
def to_xml_source(self):
element = self.to_xml_element()
return ElementTree.tostring(element, "utf-8")
def get_cpe_ids(self, config):
cpe_ids = self.cpe_hints
if len(cpe_ids) == 0:
cpe_ids = EvaluationSpec.detect_CPEs_of_target(
self.target, config
)
return cpe_ids
def select_profile_by_suffix(self, xccdf_id, profile_suffix):
input_file = self.input_.file_path
if input_file is None:
raise RuntimeError("No SCAP content file was set in the EvaluationSpec")
profiles = oscap_helpers.get_profile_choices_for_input(
input_file, None, xccdf_id
)
profile_id_match = False
for p in profiles:
if p.endswith(profile_suffix):
if profile_id_match:
raise ProfileSuffixMatchError(
"Found multiple profiles with suffix %s." %
profile_suffix
)
else:
self.profile_id = p
profile_id_match = True
if profile_id_match:
return self.profile_id
else:
raise ProfileSuffixMatchError(
"No profile with suffix %s" %
profile_suffix
)
def generate_guide(self, config):
if self.mode == oscap_helpers.EvaluationMode.SOURCE_DATASTREAM:
return oscap_helpers.generate_guide(self, config)
elif self.mode == oscap_helpers.EvaluationMode.OVAL:
# TODO: improve this
return "OVAL evaluation"
elif self.mode == oscap_helpers.EvaluationMode.CVE_SCAN:
# TODO: improve this
return "CVE scan evaluation"
elif self.mode == oscap_helpers.EvaluationMode.STANDARD_SCAN:
return oscap_helpers.generate_guide(self, config)
raise RuntimeError("Unknown EvaluationMode %i" % (self.mode))
def generate_fix(self, config, fix_type):
if self.mode in [oscap_helpers.EvaluationMode.SOURCE_DATASTREAM,
oscap_helpers.EvaluationMode.STANDARD_SCAN]:
return oscap_helpers.generate_fix(self, config, fix_type)
raise RuntimeError("Unsupported EvaluationMode %i" % (self.mode))
def get_oscap_guide_arguments(self, config):
ret = []
if self.mode == oscap_helpers.EvaluationMode.SOURCE_DATASTREAM:
# TODO: Is this supported in OpenSCAP?
if self.input_.datastream_id is not None:
ret.extend(["--datastream-id", self.input_.datastream_id])
# TODO: Is this supported in OpenSCAP?
if self.input_.xccdf_id is not None:
ret.extend(["--xccdf-id", self.input_.xccdf_id])
# TODO: Is this supported in OpenSCAP?
if self.tailoring.file_path is not None:
ret.extend(["--tailoring-file", self.tailoring.file_path])
if self.profile_id is not None:
ret.extend(["--profile", self.profile_id])
ret.append(self.input_.file_path)
elif self.mode == oscap_helpers.EvaluationMode.STANDARD_SCAN:
# TODO: Is this supported in OpenSCAP?
if self.tailoring.file_path is not None:
ret.extend(["--tailoring-file", self.tailoring.file_path])
ret.extend(["--profile",
"xccdf_org.ssgproject.content_profile_standard"])
ret.append(config.get_ssg_sds(self.get_cpe_ids(config)))
else:
raise NotImplementedError("This EvaluationMode is unsupported here!")
return ret
def get_oscap_arguments(self, config):
if self.mode == oscap_helpers.EvaluationMode.SOURCE_DATASTREAM:
ret = ["xccdf", "eval"]
if self.input_.datastream_id is not None:
ret.extend(["--datastream-id", self.input_.datastream_id])
if self.input_.xccdf_id is not None:
ret.extend(["--xccdf-id", self.input_.xccdf_id])
if self.tailoring.file_path is not None:
ret.extend(["--tailoring-file", self.tailoring.file_path])
if self.profile_id is not None:
ret.extend(["--profile", self.profile_id])
if self.online_remediation:
ret.append("--remediate")
# We are on purpose only interested in ARF, everything else can be
# generated from that.
ret.extend(["--results-arf", "results.xml"])
if self.result_format == "stig":
# STIG output can't be deduced from ARF output
ret.extend(["--stig-viewer", "results-stig.xml"])
ret.append(self.input_.file_path)
elif self.mode == oscap_helpers.EvaluationMode.OVAL:
ret = ["oval", "eval"]
ret.extend(["--results", "results.xml"])
# Again, we are only interested in OVAL results, everything else can
# be generated.
ret.append(self.input_.file_path)
elif self.mode == oscap_helpers.EvaluationMode.CVE_SCAN:
ret = ["oval", "eval"]
ret.extend(["--results", "results.xml"])
# Again, we are only interested in OVAL results, everything else can
# be generated.
ret.append(config.get_cve_feed(self.get_cpe_ids(config)))
elif self.mode == oscap_helpers.EvaluationMode.STANDARD_SCAN:
ret = ["xccdf", "eval"]
if self.tailoring.file_path is not None:
ret.extend(["--tailoring-file", self.tailoring.file_path])
if self.input_.xccdf_id is not None:
ret.extend(["--xccdf-id", self.input_.xccdf_id])
if self.profile_id is None:
ret.extend(["--profile",
"xccdf_org.ssgproject.content_profile_standard"])
else:
ret.extend(["--profile", self.profile_id])
if self.online_remediation:
ret.append("--remediate")
# We are on purpose only interested in ARF, everything else can be
# generated from that.
ret.extend(["--results-arf", "results.xml"])
if self.result_format == "stig":
# STIG output can't be deduced from ARF output
ret.extend(["--stig-viewer", "results-stig.xml"])
ret.append(config.get_ssg_sds(self.get_cpe_ids(config)))
else:
raise RuntimeError("Unknown evaluation mode %i" % (self.mode))
return ret
def evaluate_into_dir(self, config):
return oscap_helpers.evaluate(self, config)
def evaluate(self, config):
wip_result = self.evaluate_into_dir(config)
try:
exit_code = -1
with io.open(os.path.join(wip_result, "exit_code"), "r",
encoding="utf-8") as f:
exit_code = int(f.read())
stdout = ""
with io.open(os.path.join(wip_result, "stdout"), "r",
encoding="utf-8") as f:
stdout = f.read()
stderr = ""
with io.open(os.path.join(wip_result, "stderr"), "r",
encoding="utf-8") as f:
stderr = f.read()
results = dict()
try:
results["arf"] = ""
with io.open(os.path.join(wip_result, "results.xml"), "r",
encoding="utf-8") as f:
results["arf"] = f.read()
except Exception as e:
raise RuntimeError(
"Failed to read results.xml of EvaluationSpec evaluation.\n"
"stdout:\n%s\n\nstderr:\n%s\n\nexception: %s" %
(stdout, stderr, e)
)
try:
with io.open(os.path.join(wip_result, "results-stig.xml"), "r",
encoding="utf-8") as f:
results["stig"] = f.read()
except Exception as e:
# Results for the STIG viewer may not have been requested at all.
pass
return (results, stdout, stderr, exit_code)
finally:
shutil.rmtree(wip_result)
@staticmethod
def detect_CPEs_of_target(target, config):
"""Returns list of CPEs that are applicable on given target. For example
if the target is a Red Hat Enterprise Linux 7 machine this static method
would return:
["cpe:/o:redhat:enterprise_linux", "cpe:/o:redhat:enterprise_linux:7"]
"""
# We detect the CPEs by running the OpenSCAP CPE OVAL and looking at
# positive definitions.
if config.cpe_oval_path == "":
raise RuntimeError(
"Cannot detect CPEs without the OpenSCAP CPE OVAL. Please set "
"its path in the config file"
)
es = EvaluationSpec()
es.mode = oscap_helpers.EvaluationMode.OVAL
es.target = target
es.input_.set_file_path(config.cpe_oval_path)
all_results, stdout, stderr, exit_code = es.evaluate(config)
results = all_results["arf"]
if exit_code != 0:
raise RuntimeError("Failed to detect CPEs of target '%s'.\n\n"
"stdout:\n%s\n\nstderr:\n%s"
% (target, stdout, stderr))
namespaces = {
"ovalres": "http://oval.mitre.org/XMLSchema/oval-results-5",
"ovaldef": "http://oval.mitre.org/XMLSchema/oval-definitions-5"
}
results_tree = ElementTree.fromstring(results)
# first we collect all definition ids that resulted in true
definition_ids = []
for definition in results_tree.findall(
"./ovalres:results/ovalres:system/ovalres:definitions/"
"ovalres:definition[@result='true']", namespaces):
def_id_attr = definition.get("definition_id")
if def_id_attr is None:
continue
definition_ids.append(def_id_attr)
cpe_ids = []
# now we need to lookup the CPE ID for each definition id
for definition_id in definition_ids:
for reference in results_tree.findall(
"./ovaldef:oval_definitions/ovaldef:definitions/"
"ovaldef:definition[@id='%s']/ovaldef:metadata/"
"ovaldef:reference[@source='CPE']" % (definition_id),
namespaces):
ref_id = reference.get("ref_id")
if ref_id is None:
continue
cpe_ids.append(ref_id)
return cpe_ids
class ProfileSuffixMatchError(RuntimeError):
pass
openscap-daemon-0.1.10/openscap_daemon/oscap_helpers.py 0000664 0000000 0000000 00000042055 13237071060 0023203 0 ustar 00root root 0000000 0000000 # Copyright 2015 Red Hat Inc., Durham, North Carolina.
# All Rights Reserved.
#
# openscap-daemon is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 2.1 of the License, or
# (at your option) any later version.
#
# openscap-daemon is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
# You should have received a copy of the GNU Lesser General Public License
# along with openscap-daemon. If not, see .
#
# Authors:
# Martin Preisler
import subprocess
import tempfile
import os.path
import logging
import io
from xml.etree import cElementTree as ElementTree
from openscap_daemon import et_helpers
from openscap_daemon.compat import subprocess_check_output
class EvaluationMode(object):
UNKNOWN = -1
SOURCE_DATASTREAM = 1
OVAL = 2
CVE_SCAN = 3
STANDARD_SCAN = 4
@staticmethod
def to_string(value):
if value == EvaluationMode.SOURCE_DATASTREAM:
return "sds"
elif value == EvaluationMode.OVAL:
return "oval"
elif value == EvaluationMode.CVE_SCAN:
return "cve_scan"
elif value == EvaluationMode.STANDARD_SCAN:
return "standard_scan"
else:
return "unknown"
@staticmethod
def from_string(value):
if value == "sds":
return EvaluationMode.SOURCE_DATASTREAM
elif value == "oval":
return EvaluationMode.OVAL
elif value == "cve_scan":
return EvaluationMode.CVE_SCAN
elif value == "standard_scan":
return EvaluationMode.STANDARD_SCAN
else:
return EvaluationMode.UNKNOWN
def get_profile_choices_for_input(input_file, tailoring_file, xccdf_id):
# Ideally oscap would have a command line to do this, but as of now it
# doesn't so we have to implement it ourselves. Importing openscap Python
# bindings is nasty and overkill for this.
logging.debug(
"Looking for profile choices in '%s' with tailoring file '%s'.",
input_file, tailoring_file
)
ret = {}
def scrape_profiles(tree, xccdf_id, xccdf_ns, profile_ns, dest):
xlink_href = "{http://www.w3.org/1999/xlink}href"
xccdfs = []
if xccdf_id is None:
# If xccdf_id is not specified look for profiles only in the first
# xccdf component found in the datastream.
xccdfs = tree.findall(
".//{%s}checklists/{%s}component-ref[1]" % (xccdf_ns, xccdf_ns)
)
else:
xccdfs = tree.findall(
".//{%s}checklists/{%s}component-ref/[@id='%s']"
% (xccdf_ns, xccdf_ns, xccdf_id)
)
for x in xccdfs:
c = x.attrib[xlink_href]
c = c[1:] # Removes starting '#' character.
for elem in tree.findall(".//{%s}component/[@id='%s']//{%s}Profile"
% (xccdf_ns, c, profile_ns)):
id_ = elem.get("id")
title = et_helpers.get_element_text(
elem, "{%s}title" % (profile_ns), ""
)
dest[id_] = title
try:
input_tree = ElementTree.parse(input_file)
except IOError:
# The file doesn't exist, therefore there are no profile options
logging.exception(
"IOError encountered while trying to determine profile choices "
"for '%s'.", input_file
)
return ret
except ElementTree.ParseError:
logging.exception(
"ParserError encountered while trying to determine profile choices "
"for '%s'.", input_file
)
return ret
scrape_profiles(
input_tree,
xccdf_id,
"http://scap.nist.gov/schema/scap/source/1.1",
"http://checklists.nist.gov/xccdf/1.1",
ret
)
scrape_profiles(
input_tree,
xccdf_id,
"http://scap.nist.gov/schema/scap/source/1.2",
"http://checklists.nist.gov/xccdf/1.2",
ret
)
if tailoring_file:
tailoring_tree = ElementTree.parse(tailoring_file)
scrape_profiles(
tailoring_tree, "http://checklists.nist.gov/xccdf/1.1", ret
)
scrape_profiles(
tailoring_tree, "http://checklists.nist.gov/xccdf/1.2", ret
)
ret[""] = "(default)"
logging.info(
"Found %i profile choices in '%s' with tailoring file '%s'.",
len(ret), input_file, tailoring_file
)
return ret
def get_generate_guide_args(spec, config):
ret = [config.oscap_path, "xccdf", "generate", "guide"]
ret.extend(spec.get_oscap_guide_arguments(config))
return ret
def generate_guide(spec, config):
if spec.mode not in [EvaluationMode.SOURCE_DATASTREAM,
EvaluationMode.STANDARD_SCAN]:
raise RuntimeError(
"Can't generate guide for an EvaluationSpec with mode '%s'. "
"Generating an HTML guide only works for 'sds' and 'standard_scan' "
"modes."
% (EvaluationMode.to_string(spec.mode))
)
if not spec.is_valid():
raise RuntimeError(
"Can't generate guide for an invalid EvaluationSpec."
)
args = get_generate_guide_args(spec, config)
logging.debug(
"Generating guide for evaluation spec with command '%s'.",
" ".join(args)
)
ret = subprocess_check_output(
args,
shell=False
).decode("utf-8")
logging.info("Generated guide for evaluation spec.")
return ret
def split_ssh_target(target):
if not target.startswith("ssh://") and not target.startswith("ssh+sudo://"):
raise RuntimeError(
"Can't split ssh target."
)
if target.startswith("ssh+sudo://"):
without_prefix = target[11:]
else:
without_prefix = target[6:]
if ":" in without_prefix:
host, port_str = without_prefix.split(":")
return host, int(port_str)
else:
return without_prefix, 22
def get_evaluation_args(spec, config):
ret = []
if spec.target == "localhost":
if config.oscap_path == "":
raise RuntimeError(
"Target '%s' requires the oscap tool which hasn't been found" %
(spec.target)
)
ret.extend([config.oscap_path])
elif spec.target.startswith("ssh://"):
if config.oscap_ssh_path == "":
raise RuntimeError(
"Target '%s' requires the oscap-ssh tool which hasn't been "
"found" % (spec.target)
)
host, port = split_ssh_target(spec.target)
ret.extend([config.oscap_ssh_path, host, str(port)])
elif spec.target.startswith("ssh+sudo://"):
if config.oscap_ssh_path == "":
raise RuntimeError(
"Target '%s' requires the oscap-ssh tool which hasn't been "
"found" % (spec.target)
)
host, port = split_ssh_target(spec.target)
ret.extend([config.oscap_ssh_path, '--sudo', host, str(port)])
elif spec.target.startswith("docker-image://"):
if config.oscap_ssh_path == "":
raise RuntimeError(
"Target '%s' requires the oscap-docker tool which hasn't been "
"found" % (spec.target)
)
image_name = spec.target[len("docker-image://"):]
ret.extend([config.oscap_docker_path, "image", image_name])
elif spec.target.startswith("docker-container://"):
if config.oscap_ssh_path == "":
raise RuntimeError(
"Target '%s' requires the oscap-docker tool which hasn't been "
"found" % (spec.target)
)
container_name = spec.target[len("docker-container://"):]
ret.extend([config.oscap_docker_path, "container", container_name])
elif spec.target.startswith("vm-domain://"):
if config.oscap_vm_path == "":
raise RuntimeError(
"Target '%s' requires the oscap-vm tool which hasn't been "
"found" % (spec.target)
)
domain_name = spec.target[len("vm-domain://"):]
ret.extend([config.oscap_vm_path, "domain", domain_name])
elif spec.target.startswith("vm-image://"):
if config.oscap_vm_path == "":
raise RuntimeError(
"Target '%s' requires the oscap-vm tool which hasn't been "
"found" % (spec.target)
)
storage_name = spec.target[len("vm-image://"):]
ret.extend([config.oscap_vm_path, "image", storage_name])
elif spec.target.startswith("chroot://"):
if config.oscap_chroot_path == "":
raise RuntimeError(
"Target '%s' requires the oscap-chroot tool which hasn't been "
"found" % (spec.target)
)
path = spec.target[len("chroot://"):]
ret.extend([config.oscap_chroot_path, path])
else:
raise RuntimeError(
"Unrecognized target '%s' in evaluation spec." % (spec.target)
)
ret.extend(spec.get_oscap_arguments(config))
return ret
def evaluate(spec, config):
"""Calls oscap to evaluate given task, creates a uniquely named directory
in given results_dir for it. Returns absolute path to that directory in
case of success.
Throws exception in case of failure.
"""
if not spec.is_valid():
raise RuntimeError("Can't evaluate an invalid EvaluationSpec.")
working_directory = tempfile.mkdtemp(
prefix="", suffix="",
dir=config.work_in_progress_dir
)
stdout_file = io.open(os.path.join(working_directory, "stdout"), "w",
encoding="utf-8")
stderr_file = io.open(os.path.join(working_directory, "stderr"), "w",
encoding="utf-8")
args = get_evaluation_args(spec, config)
logging.debug(
"Starting evaluation with command '%s'.",
" ".join(args)
)
exit_code = 1
try:
exit_code = subprocess.call(
args,
cwd=working_directory,
stdout=stdout_file,
stderr=stderr_file,
shell=False
)
except:
logging.exception(
"Failed to execute 'oscap' while evaluating EvaluationSpec."
)
stdout_file.flush()
stderr_file.flush()
with io.open(os.path.join(working_directory, "exit_code"), "w",
encoding="utf-8") as f:
f.write(u"%i" % (exit_code))
# Exit code 0 means evaluation was successful and machine is compliant.
# Exit code 1 means there was an error while evaluating.
# Exit code 2 means there were no errors but the machine is not compliant.
if exit_code == 0:
logging.info(
"Evaluated EvaluationSpec, exit_code=0."
)
# TODO: Assert that arf was generated
elif exit_code == 2:
logging.warning(
"Evaluated EvaluationSpec, exit_code=2."
)
# TODO: Assert that arf was generated
elif exit_code == 1:
logging.error(
"EvaluationSpec failed to evaluate, oscap returned 1 as exit code, "
"it may not be possible to get ARF/OVAL results or generate reports"
" for this result!"
)
# TODO: Assert that arf was NOT generated
else:
logging.error(
"Evaluated EvaluationSpec, unknown exit code %i!.", exit_code
)
return working_directory
def get_generate_report_args_for_results(spec, results_path, config):
if spec.mode == EvaluationMode.SOURCE_DATASTREAM:
# results_path is an ARF XML file
return [config.oscap_path, "xccdf", "generate", "report", results_path]
elif spec.mode == EvaluationMode.OVAL:
# results_path is an OVAL results XML file
return [config.oscap_path, "oval", "generate", "report", results_path]
elif spec.mode == EvaluationMode.CVE_SCAN:
# results_path is an OVAL results XML file
return [config.oscap_path, "oval", "generate", "report", results_path]
elif spec.mode == EvaluationMode.STANDARD_SCAN:
# results_path is an ARF XML file
return [config.oscap_path, "xccdf", "generate", "report", results_path]
else:
raise RuntimeError("Unknown evaluation mode")
def generate_report_for_result(spec, results_dir, result_id, config):
"""This function assumes that the ARF was generated using evaluate
in this same package. That's why we can avoid --datastream-id, ...
The behavior is undefined for generic ARFs!
"""
if not spec.is_valid():
raise RuntimeError("Can't generate report for any result of an "
"invalid EvaluationSpec.")
results_path = os.path.join(results_dir, str(result_id), "results.xml")
if not os.path.exists(results_path):
raise RuntimeError("Can't generate report for result '%s'. Expected "
"results XML at '%s' but the file doesn't exist."
% (result_id, results_path))
args = get_generate_report_args_for_results(spec, results_path, config)
logging.debug(
"Generating report for result %i of EvaluationSpec with command '%s'.",
result_id, " ".join(args)
)
ret = subprocess_check_output(
args,
shell=False
).decode("utf-8")
logging.info(
"Generated report for result %i of EvaluationSpec.", result_id
)
return ret
def get_status_from_exit_code(exit_code):
"""Returns human readable status based on given `oscap` exit_code
"""
status = "Unknown (exit_code = %i)" % (exit_code)
if exit_code == 0:
status = "Compliant"
elif exit_code == 1:
status = "Evaluation Error"
elif exit_code == 2:
status = "Non-Compliant"
return status
def _fix_type_to_template(fix_type):
fix_templates = {"bash": "urn:xccdf:fix:script:sh",
"ansible": "urn:xccdf:fix:script:ansible",
"puppet": "urn:xccdf:fix:script:puppet"}
template = fix_templates[fix_type]
return template
def _get_result_id(results_path):
tree = ElementTree.parse(results_path)
root = tree.getroot()
ns = {"xccdf": "http://checklists.nist.gov/xccdf/1.2"}
test_result = root.find(".//xccdf:TestResult", ns)
if test_result is None:
raise RuntimeError("Results XML '%s' doesn't contain any results."
% results_path)
return test_result.attrib["id"]
def generate_fix_for_result(config, results_path, fix_type, xccdf_id=None):
if not os.path.exists(results_path):
raise RuntimeError("Can't generate fix for scan result. Expected "
"results XML at '%s' but the file doesn't exist."
% results_path)
result_id = _get_result_id(results_path)
template = _fix_type_to_template(fix_type)
args = [config.oscap_path, "xccdf", "generate", "fix",
"--result-id", result_id,
"--template", template]
if xccdf_id is not None:
args.extend(["--xccdf-id", xccdf_id])
args.append(results_path)
fix_text = subprocess_check_output(args).decode("utf-8")
return fix_text
def generate_html_report_for_result(config, results_path):
if not os.path.exists(results_path):
raise RuntimeError("Can't generate report for scan result. Expected "
"results XML at '%s' but the file doesn't exist."
% results_path)
result_id = _get_result_id(results_path)
args = [config.oscap_path, "xccdf", "generate", "report",
"--result-id", result_id, results_path]
report_text = subprocess_check_output(args).decode("utf-8")
return report_text
def generate_fix(spec, config, fix_type):
if spec.mode not in [EvaluationMode.SOURCE_DATASTREAM,
EvaluationMode.STANDARD_SCAN]:
raise RuntimeError(
"Can't generate fix for an EvaluationSpec with mode '%s'. "
"Generating a fix script only works for 'sds' and 'standard_scan' "
"modes."
% (EvaluationMode.to_string(spec.mode))
)
if not spec.is_valid():
raise RuntimeError(
"Can't generate fix for an invalid EvaluationSpec."
)
template = _fix_type_to_template(fix_type)
args = [config.oscap_path, "xccdf", "generate", "fix",
"--profile", spec.profile_id,
"--template", template,
spec.input_.file_path]
logging.debug(
"Generating fix script for evaluation spec with command '%s'.",
" ".join(args)
)
ret = subprocess_check_output(args).decode("utf-8")
logging.info("Generated fix script for evaluation spec.")
return ret
__all__ = [
"get_profile_choices_for_input",
"generate_guide",
"generate_fix",
"evaluate",
"generate_report_for_result",
"get_status_from_exit_code",
"generate_fix_for_result"
]
openscap-daemon-0.1.10/openscap_daemon/system.py 0000664 0000000 0000000 00000053466 13237071060 0021710 0 ustar 00root root 0000000 0000000 # Copyright 2015 Red Hat Inc., Durham, North Carolina.
# All Rights Reserved.
#
# openscap-daemon is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 2.1 of the License, or
# (at your option) any later version.
#
# openscap-daemon is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
# You should have received a copy of the GNU Lesser General Public License
# along with openscap-daemon. If not, see .
#
# Authors:
# Martin Preisler
import os
import os.path
from datetime import datetime
import threading
import logging
from openscap_daemon.task import Task
from openscap_daemon.config import Configuration
from openscap_daemon import oscap_helpers
from openscap_daemon import async
class ResultsNotAvailable(Exception):
def __init__(self):
super(ResultsNotAvailable, self).__init__()
EVALUATION_PRIORITY = 0
TASK_ACTION_PRIORITY = 10
class System(object):
def __init__(self, config_file):
self.async = async.AsyncManager()
logging.info("Loading configuration from '%s'.", config_file)
self.config = Configuration()
self.config.load(config_file)
self.config.autodetect_tool_paths()
self.config.autodetect_content_paths()
self.config.prepare_dirs()
self.config.sanity_check()
self.async_eval_spec_results = dict()
self.async_eval_spec_results_lock = threading.Lock()
self.tasks = dict()
self.tasks_lock = threading.Lock()
# a set of tasks that have already been scheduled, we keep this so that
# we don't schedule a task twice in a row
self.tasks_scheduled = set()
self.update_wait_cond = threading.Condition()
self.async_eval_cve_scanner_worker_results = dict()
self.async_eval_cve_scanner_worker_results_lock = threading.Lock()
def get_ssg_choices(self):
ret = []
if self.config.ssg_path == "":
return ret
if not os.path.isdir(self.config.ssg_path):
return ret
for ssg_file in os.listdir(self.config.ssg_path):
full_path = os.path.join(self.config.ssg_path, ssg_file)
if not os.path.isfile(full_path):
continue
if not full_path.endswith("-ds.xml"):
continue
ret.append(full_path)
return sorted(ret)
def get_profile_choices_for_input(self, input_file, tailoring_file):
return oscap_helpers.get_profile_choices_for_input(
input_file, tailoring_file, None
)
class AsyncEvaluateSpecAction(async.AsyncAction):
def __init__(self, system, spec):
super(System.AsyncEvaluateSpecAction, self).__init__()
self.system = system
self.spec = spec
def run(self):
all_results, stdout, stderr, exit_code = \
self.spec.evaluate(self.system.config)
arf = None
if all_results is not None:
arf = all_results["arf"]
with self.system.async_eval_spec_results_lock:
self.system.async_eval_spec_results[self.token] = \
(arf, stdout, stderr, exit_code)
def __str__(self):
return "Evaluate Spec '%s'" % (self.spec)
def evaluate_spec_async(self, spec):
return self.async.enqueue(
System.AsyncEvaluateSpecAction(
self,
spec
),
EVALUATION_PRIORITY
)
def get_evaluate_spec_async_results(self, token):
with self.async_eval_spec_results_lock:
if token not in self.async_eval_spec_results:
raise ResultsNotAvailable()
arf, stdout, stderr, exit_code = self.async_eval_spec_results[token]
del self.async_eval_spec_results[token]
return arf, stdout, stderr, exit_code
def load_tasks(self):
logging.info("Loading task definitions from '%s'...",
self.config.tasks_dir)
task_files = os.listdir(self.config.tasks_dir)
task_count = 0
for task_file in task_files:
if not task_file.endswith(".xml"):
logging.warning(
"Found '%s' in task definitions directory '%s'. Paths "
"not ending with '.xml' are unexpected in the task "
"definitions directory ", task_file, self.config.tasks_dir
)
continue
full_path = os.path.join(self.config.tasks_dir, task_file)
if not os.path.isfile(full_path):
logging.warning(
"Found '%s' in task definitions directory '%s'. This path "
"is not a file. Only files are expected in the task "
"definitions directory ", full_path, self.config.tasks_dir
)
continue
id_ = Task.get_task_id_from_filepath(full_path)
with self.tasks_lock:
if id_ not in self.tasks:
self.tasks[id_] = Task()
self.tasks[id_].load(full_path)
task_count += 1
with self.update_wait_cond:
self.update_wait_cond.notify_all()
logging.info(
"Successfully loaded %i task definitions.", task_count
)
def save_tasks(self):
logging.info("Saving task definitions to '%s'...",
self.config.tasks_dir)
task_count = 0
with self.tasks_lock:
for _, task in self.tasks.items():
task.save()
task_count += 1
logging.info(
"Successfully saved %i task definitions.", task_count
)
def list_task_ids(self):
ret = []
with self.tasks_lock:
ret = self.tasks.keys()
return ret
def create_task(self):
task_id = 1
with self.tasks_lock:
while task_id in self.tasks:
task_id += 1
task = Task()
task.id_ = task_id
task.config_file = os.path.join(
self.config.tasks_dir, "%i.xml" % (task_id)
)
self.tasks[task_id] = task
# We do not save the task on purpose, empty tasks are worthless.
# The task will be saved to disk as soon as one of its properties is
# set.
# task.save()
logging.info("Created a new empty task with ID '%i'.", task_id)
# Do not notify the update_wait_cond, the task is disabled so it
# doesn't affect the schedule in any way
# with self.update_wait_cond:
# self.update_wait_cond.notify_all()
return task_id
def remove_task(self, task_id, remove_results):
task = None
with self.tasks_lock:
task = self.tasks[task_id]
if task.enabled:
raise RuntimeError(
"Can't remove enabled task '%i'. Please disable it first." %
(task_id)
)
if not remove_results:
result_ids = task.list_result_ids(self.config.results_dir)
if len(result_ids) > 0:
raise RuntimeError(
"Can't remove task '%i', in has %i results stored. "
"Please remove all the results first." %
(task_id, len(result_ids))
)
else:
logging.debug("Remove task results before.")
task.remove_results(self.config)
del self.tasks[task_id]
os.remove(self._get_task_file_path(task_id))
logging.info("Removed task '%i'.", task_id)
def _get_task_file_path(self, task_id):
return os.path.join(self.config.tasks_dir, "%i.xml" % (task_id))
def remove_task_results(self, task_id):
task = None
with self.tasks_lock:
task = self.tasks[task_id]
with task.update_lock:
task.remove_results(self.config)
def remove_task_result(self, task_id, result_id):
task = None
with self.tasks_lock:
task = self.tasks[task_id]
with task.update_lock:
task.remove_result(result_id, self.config)
def set_task_enabled(self, task_id, enabled):
task = None
with self.tasks_lock:
task = self.tasks[task_id]
with task.update_lock:
task.enabled = bool(enabled)
task.save()
logging.info(
"%s task with ID %i.",
"Enabled" if enabled else "Disabled", task_id
)
if task.enabled:
with self.update_wait_cond:
self.update_wait_cond.notify_all()
def get_task_enabled(self, task_id):
task = None
with self.tasks_lock:
task = self.tasks[task_id]
return task.enabled
def set_task_title(self, task_id, title):
task = None
with self.tasks_lock:
task = self.tasks[task_id]
with task.update_lock:
task.title = title
task.save()
logging.info("Set title of task with ID %i to '%s'.", task_id, title)
def get_task_title(self, task_id):
task = None
with self.tasks_lock:
task = self.tasks[task_id]
return task.title
def set_task_target(self, task_id, target):
task = None
with self.tasks_lock:
task = self.tasks[task_id]
with task.update_lock:
task.evaluation_spec.target = target
task.save()
logging.info("Set target of task with ID %i to '%s'.", task_id, target)
def get_task_target(self, task_id):
task = None
with self.tasks_lock:
task = self.tasks[task_id]
return task.evaluation_spec.target
def get_task_created_timestamp(self, task_id):
task_path = self._get_task_file_path(task_id)
return os.path.getctime(task_path)
def get_task_modified_timestamp(self, task_id):
task_path = self._get_task_file_path(task_id)
return os.path.getmtime(task_path)
def set_task_input(self, task_id, input_):
"""input can be an absolute file path or the XML source itself. This is
autodetected.
"""
task = None
with self.tasks_lock:
task = self.tasks[task_id]
with task.update_lock:
if input_ is None or os.path.isabs(input_):
task.evaluation_spec.input_.set_file_path(input_)
logging.info(
"Set input content of task with ID %i to file '%s'.",
task_id, input_
)
else:
task.evaluation_spec.input_.set_contents(input_)
logging.info(
"Set input content of task with ID %i to custom XML.",
task_id
)
task.save()
def set_task_tailoring(self, task_id, tailoring):
"""tailoring can be an absolute file path or the XML source itself.
This is autodetected.
"""
task = None
with self.tasks_lock:
task = self.tasks[task_id]
with task.update_lock:
if tailoring is None or os.path.isabs(tailoring):
task.evaluation_spec.tailoring.set_file_path(tailoring)
logging.info(
"Set tailoring content of task with ID %i to file '%s'.",
task_id, tailoring
)
else:
task.evaluation_spec.tailoring.set_contents(tailoring)
logging.info(
"Set tailoring content of task with ID %i to custom XML.",
task_id
)
task.save()
def set_task_profile_id(self, task_id, profile_id):
task = None
if profile_id == "":
profile_id = None
with self.tasks_lock:
task = self.tasks[task_id]
with task.update_lock:
task.evaluation_spec.profile_id = profile_id
task.save()
logging.info(
"Set profile ID of task with ID %i to '%s'.", task_id, profile_id
)
def set_task_online_remediation(self, task_id, remediation_enabled):
task = None
with self.tasks_lock:
task = self.tasks[task_id]
with task.update_lock:
task.evaluation_spec.online_remediation = bool(remediation_enabled)
task.save()
logging.info(
"%s online remediation of task with ID %i.",
"Enabled" if remediation_enabled else "Disabled", task_id
)
def set_task_schedule_not_before(self, task_id, schedule_not_before):
task = None
with self.tasks_lock:
task = self.tasks[task_id]
with task.update_lock:
task.schedule.not_before = schedule_not_before
task.save()
logging.info(
"Set schedule not before of task with ID %i to %s.",
task_id, schedule_not_before
)
# This changes the schedule which potentially obsoletes the precomputed
# schedule. Make sure we re-schedule everything.
if task.enabled:
with self.update_wait_cond:
self.update_wait_cond.notify_all()
def set_task_schedule_repeat_after(self, task_id, schedule_repeat_after):
task = None
with self.tasks_lock:
task = self.tasks[task_id]
with task.update_lock:
task.schedule.repeat_after = schedule_repeat_after
task.save()
logging.info(
"Set schedule repeat after of task with ID %i to %s.",
task_id, schedule_repeat_after
)
# This changes the schedule which potentially obsoletes the precomputed
# schedule. Make sure we re-schedule everything.
if task.enabled:
with self.update_wait_cond:
self.update_wait_cond.notify_all()
def get_closest_datetime(self, reference_datetime):
ret = None
with self.tasks_lock:
for task in self.tasks.values():
if task.id_ in self.tasks_scheduled:
continue
next_update_time = task.get_next_update_time(reference_datetime)
if next_update_time is None:
continue
if ret is None or next_update_time < ret:
ret = next_update_time
return ret
class AsyncUpdateTaskAction(async.AsyncAction):
def __init__(self, system, task_id, reference_datetime):
super(System.AsyncUpdateTaskAction, self).__init__()
self.system = system
self.task_id = task_id
self.reference_datetime = reference_datetime
def run(self):
task = None
with self.system.tasks_lock:
task = self.system.tasks[self.task_id]
task.update(self.reference_datetime, self.system.config)
with self.system.tasks_lock:
self.system.tasks_scheduled.remove(task.id_)
def __str__(self):
return "Update Task '%i' with reference_datetime='%s'" \
% (self.task_id, self.reference_datetime)
def schedule_tasks(self, reference_datetime=None):
"""Evaluates all currently outstanding tasks and returns.
Outstanding task means it's not_before is lower than reference_datetime,
and it is not disabled. Tasks can be processed in parallel if their
targets differ. No two tasks with the same target will be run in
parallel regardless of max_jobs setting.
reference_datetime - Which date/time should be used to plan tasks.
max_jobs - Use at most this amount of threads to evaluate.
"""
if reference_datetime is None:
reference_datetime = datetime.utcnow()
logging.debug(
"Scheduling task updates, reference_datetime='%s'.",
str(reference_datetime)
)
with self.tasks_lock:
for task in self.tasks.values():
if task.id_ in self.tasks_scheduled:
continue
if task.should_be_updated(reference_datetime):
self.tasks_scheduled.add(task.id_)
self.async.enqueue(
System.AsyncUpdateTaskAction(
self,
task.id_,
reference_datetime
),
TASK_ACTION_PRIORITY
)
def schedule_tasks_worker(self):
while True:
reference_datetime = datetime.now()
closest_datetime = self.get_closest_datetime(reference_datetime)
if closest_datetime is None:
with self.update_wait_cond:
logging.debug(
"No task is scheduled to run. Sleeping for an hour. "
"Interruptible if task specs change."
)
self.update_wait_cond.wait(60 * 60)
else:
time_to_wait = closest_datetime - reference_datetime
# because of ntp, daylight savings, etc, lets be safe
# and reschedule every hour at least
seconds_to_wait = min(60 * 60, time_to_wait.total_seconds())
if seconds_to_wait > 0:
with self.update_wait_cond:
logging.debug(
"Closest task action in %s. Sleeping until then. "
"Interruptible if task specs change.", time_to_wait
)
self.update_wait_cond.wait(seconds_to_wait)
self.schedule_tasks(reference_datetime)
def generate_guide_for_task(self, task_id):
task = None
with self.tasks_lock:
task = self.tasks[task_id]
return task.evaluation_spec.generate_guide(self.config)
def generate_fix_for_task(self, task_id, fix_type):
task = None
with self.tasks_lock:
task = self.tasks[task_id]
return task.evaluation_spec.generate_fix(self.config, fix_type)
def run_task_outside_schedule(self, task_id):
task = None
with self.tasks_lock:
task = self.tasks[task_id]
task.run_outside_schedule()
with self.update_wait_cond:
self.update_wait_cond.notify_all()
def get_task_result_ids(self, task_id):
task = None
with self.tasks_lock:
task = self.tasks[task_id]
# TODO: Is this a race condition? look into task.update
return task.list_result_ids(self.config.results_dir)
def get_task_result_created_timestamp(self, task_id, result_id):
task = None
with self.tasks_lock:
task = self.tasks[task_id]
return task.get_result_created_timestamp(result_id, self.config)
def get_xml_of_task_result(self, task_id, result_id):
task = None
with self.tasks_lock:
task = self.tasks[task_id]
return task.get_xml_of_result(result_id, self.config)
def get_stdout_of_task_result(self, task_id, result_id):
task = None
with self.tasks_lock:
task = self.tasks[task_id]
return task.get_stdout_of_result(result_id, self.config)
def get_stderr_of_task_result(self, task_id, result_id):
task = None
with self.tasks_lock:
task = self.tasks[task_id]
return task.get_stderr_of_result(result_id, self.config)
def get_exit_code_of_task_result(self, task_id, result_id):
task = None
with self.tasks_lock:
task = self.tasks[task_id]
return task.get_exit_code_of_result(result_id, self.config)
def generate_report_for_task_result(self, task_id, result_id):
task = None
with self.tasks_lock:
task = self.tasks[task_id]
return task.generate_report_for_result(
result_id,
self.config
)
def generate_fix_for_task_result(self, task_id, result_id, fix_type):
task = None
with self.tasks_lock:
task = self.tasks[task_id]
return task.generate_fix_for_result(
result_id,
self.config,
fix_type
)
class AsyncEvaluateCVEScannerWorkerAction(async.AsyncAction):
def __init__(self, system, worker):
super(System.AsyncEvaluateCVEScannerWorkerAction, self).__init__()
self.system = system
self.worker = worker
def run(self):
json_result = self.worker.start_application()
with self.system.async_eval_cve_scanner_worker_results_lock:
self.system.async_eval_cve_scanner_worker_results[self.token] = \
json_result
def __str__(self):
return "Evaluate CVE Scanner Worker '%s'" % (self.worker)
def evaluate_cve_scanner_worker_async(self, worker):
return self.async.enqueue(
System.AsyncEvaluateCVEScannerWorkerAction(
self,
worker
),
EVALUATION_PRIORITY
)
def get_evaluate_cve_scanner_worker_async_results(self, token):
with self.async_eval_cve_scanner_worker_results_lock:
if token not in self.async_eval_cve_scanner_worker_results:
raise ResultsNotAvailable()
json_results = self.async_eval_cve_scanner_worker_results[token]
del self.async_eval_cve_scanner_worker_results[token]
return json_results
openscap-daemon-0.1.10/openscap_daemon/task.py 0000664 0000000 0000000 00000047147 13237071060 0021325 0 ustar 00root root 0000000 0000000 # Copyright 2015 Red Hat Inc., Durham, North Carolina.
# All Rights Reserved.
#
# openscap-daemon is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 2.1 of the License, or
# (at your option) any later version.
#
# openscap-daemon is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
# You should have received a copy of the GNU Lesser General Public License
# along with openscap-daemon. If not, see .
#
# Authors:
# Martin Preisler
from openscap_daemon import et_helpers
from openscap_daemon import oscap_helpers
from openscap_daemon import evaluation_spec
from xml.etree import cElementTree as ElementTree
from datetime import datetime, timedelta
import os.path
import shutil
import threading
import logging
import io
class SlipMode(object):
"""This enum describes how to behave when scheduling repeated tasks.
Consider task 1 which is scheduled to run hourly every hour. Last run was
at 23:00. Schedule is to run 0:00, 1:00, 2:00, ... After last run, the
machine was turned off for 3 hours. Time is now 2:05.
With no_slip we will run 3 evaluations and the next schedule is 4:00.
With slip_missed we will run 1 evaluation and the next schedule is 4:05.
With slip_missed_aligned we will run 1 evaluation the next schedule is 4:00.
The de-facto standard is drop_missed_aligned. The tools will try their best
to be right on the timetable. In case of misses they will run one task ASAP
and try to adhere precisely to the timetable again.
"""
UNKNOWN = 0
NO_SLIP = 1
DROP_MISSED = 2
DROP_MISSED_ALIGNED = 3
@staticmethod
def from_string(slip_mode):
if slip_mode == "no_slip":
return SlipMode.NO_SLIP
elif slip_mode == "drop_missed":
return SlipMode.DROP_MISSED
elif slip_mode == "drop_missed_aligned":
return SlipMode.DROP_MISSED_ALIGNED
return SlipMode.UNKNOWN
@staticmethod
def to_string(slip_mode):
if slip_mode == SlipMode.NO_SLIP:
return "no_slip"
elif slip_mode == SlipMode.DROP_MISSED:
return "drop_missed"
elif slip_mode == SlipMode.DROP_MISSED_ALIGNED:
return "drop_missed_aligned"
return "unknown"
class Schedule(object):
def __init__(self):
self.not_before = None
self.repeat_after = 0
self.slip_mode = SlipMode.DROP_MISSED_ALIGNED
def is_equivalent_to(self, other):
return \
self.not_before == other.not_before and \
self.repeat_after == other.repeat_after and \
self.slip_mode == other.slip_mode
def load_from_xml_element(self, element):
schedule_not_before_attr = element.get("not_before")
# we expect UTC, no timezone shifts
if schedule_not_before_attr is not None:
self.not_before = datetime.strptime(
schedule_not_before_attr,
"%Y-%m-%dT%H:%M"
)
else:
self.not_before = None
schedule_repeat_after_attr = element.get("repeat_after")
if schedule_repeat_after_attr is not None:
self.repeat_after = int(schedule_repeat_after_attr)
else:
self.repeat_after = None
self.slip_mode = SlipMode.from_string(
element.get("slip_mode", "drop_missed_aligned")
)
def to_xml_element(self):
ret = ElementTree.Element("schedule")
if self.not_before is not None:
ret.set("not_before", self.not_before.strftime("%Y-%m-%dT%H:%M"))
ret.set("repeat_after", str(self.repeat_after))
ret.set("slip_mode", SlipMode.to_string(self.slip_mode))
return ret
def next_not_before(self, reference_datetime):
"""Calculates the next schedule_not_before based on
schedule_repeat_after and schedule_slip_mode.
"""
if self.not_before is None:
# the task is already disabled, no need to schedule next run
return None
if self.repeat_after is None:
# task repetition is disabled
return None
if self.slip_mode == SlipMode.NO_SLIP:
return self.not_before + timedelta(hours=self.repeat_after)
elif self.slip_mode == SlipMode.DROP_MISSED:
return reference_datetime + timedelta(hours=self.repeat_after)
elif self.slip_mode == SlipMode.DROP_MISSED_ALIGNED:
candidate = self.not_before + timedelta(hours=self.repeat_after)
while candidate <= reference_datetime:
candidate += timedelta(hours=self.repeat_after)
return candidate
else:
raise RuntimeError("Unrecognized slip_mode.")
class Task(object):
"""This class defined input content, tailoring, profile, ..., and schedule
for an SCAP evaluation task.
Example of a task:
Run USGCB evaluation on RHEL6 localhost machine, every day at 1:00.
Task is composed of EvaluationSpec and Schedule
"""
def __init__(self):
self.id_ = None
self.config_file = None
self.enabled = False
self.title = None
self.evaluation_spec = evaluation_spec.EvaluationSpec()
# How many results should we keep before pruning old results
# -1 means use the default from config
# -2 means never prune any results
self.max_results_to_keep = -1
self.schedule = Schedule()
# If True, this task will be evaluated once without affecting the
# schedule. This feature is important for test runs. This variable does
# not persist because it is not saved to the config file!
self.run_outside_schedule_once = False
# Prevents multiple updates of the same task running
self.update_lock = threading.Lock()
def __str__(self):
ret = "Task from config file '%s' with:\n" % (self.config_file)
ret += "- ID: \t%i\n" % (self.id_)
ret += "- title: \t%s\n" % (self.title)
ret += str(self.evaluation_spec) + "\n"
ret += "- max results to keep: \t%s\n" % \
("default" if self.max_results_to_keep == -1
else str(self.max_results_to_keep))
ret += "- schedule:\n"
ret += " - not before: \t%s\n" % (self.schedule.not_before)
ret += " - repeat after: \t%s\n" % (self.schedule.repeat_after)
ret += " - slip mode: \t%s\n" %\
(SlipMode.to_string(self.schedule.slip_mode))
return ret
def is_valid(self):
if not self.evaluation_spec.is_valid():
return False
return True
def is_equivalent_to(self, other):
"""Checks that both "Task self" and "Task other" are the same except for
id_ and config_file.
"""
return \
self.evaluation_spec.is_equivalent_to(other.evaluation_spec) and \
self.title == other.title and \
self.max_results_to_keep == other.max_results_to_keep and \
self.schedule.is_equivalent_to(other.schedule) and \
self.run_outside_schedule_once == other.run_outside_schedule_once
@staticmethod
def get_task_id_from_filepath(filepath):
filename, extension = os.path.splitext(
os.path.basename(filepath)
)
ret = int(filename)
assert(ret > 0)
return ret
def load_from_xml_element(self, root, config_file):
self.id_ = Task.get_task_id_from_filepath(config_file)
self.enabled = root.get("enabled", "false") == "true"
self.title = et_helpers.get_element_text(root, "title")
self.evaluation_spec = evaluation_spec.EvaluationSpec()
self.evaluation_spec.load_from_xml_element(
et_helpers.get_element(root, "evaluation_spec")
)
self.max_results_to_keep = \
int(et_helpers.get_element_text(root, "max-results-to-keep", "-1"))
self.schedule = Schedule()
self.schedule.load_from_xml_element(
et_helpers.get_element(root, "schedule")
)
self.config_file = config_file
def load(self, config_file):
tree = ElementTree.parse(config_file)
root = tree.getroot()
self.load_from_xml_element(root, config_file)
def reload(self):
if self.config_file is not None:
raise RuntimeError("Can't reload, config_file is not set.")
self.load(self.config_file)
def to_xml_element(self):
root = ElementTree.Element("task")
root.set("enabled", "true" if self.enabled else "false")
if self.title is not None:
title_element = ElementTree.Element("title")
title_element.text = self.title
root.append(title_element)
evaluation_spec_element = self.evaluation_spec.to_xml_element()
root.append(evaluation_spec_element)
if self.max_results_to_keep != -1:
max_results_element = ElementTree.Element("max-results-to-keep")
max_results_element.text = str(self.max_results_to_keep)
root.append(max_results_element)
schedule_element = self.schedule.to_xml_element()
root.append(schedule_element)
return root
def save_as(self, config_file):
root = self.to_xml_element()
et_helpers.indent(root)
xml_source = ElementTree.tostring(root, encoding="utf-8")
with io.open(config_file, "w", encoding="utf-8") as f:
f.write(u"\n")
f.write(xml_source.decode("utf-8"))
def save(self):
assert(self.config_file is not None)
self.save_as(self.config_file)
def next_schedule_not_before(self, reference_datetime):
# TODO: Get rid of this delegate
return self.schedule.next_not_before(reference_datetime)
def _get_task_results_dir(self, results_dir):
ret = os.path.join(results_dir, str(self.id_))
if not os.path.exists(ret):
os.mkdir(ret)
return ret
def list_result_ids(self, results_dir):
"""IDs are returned in reverse order sorted by strings as if they were
integers.
for example: ['10', '9', '8', '1']
"""
# The lambda is there to make sure we don't consider 2 "larger"
# than 10. For example to avoid sorted lists such as:
# ['9', '8', '10', '1'] where we wanted ['10', '9', '8', '1']
return sorted(
os.listdir(self._get_task_results_dir(results_dir)), reverse=True,
key=lambda s: (len(s), s)
)
def get_result_created_timestamp(self, result_id, config):
"""Return timestamp of result creation.
"""
# todo refactor - the path is used from many places
file_path = os.path.join(
self._get_task_results_dir(config.results_dir),
str(result_id),
"exit_code"
)
timestamp = os.path.getctime(file_path)
return timestamp
def _get_next_target_dir(self, results_dir):
# We may consider having a file that contains the last ID in the
# future. I considered that but right now I think a result with more
# than a few thousand results is unlikely. User will use results
# purging. Sorting a couple thousand results is still very quick.
# Having a file with the last ID makes this operation O(1) instead
# of O(n*log(n)).
# result_ids are guaranteed to be reverse sorted by int
result_ids = self.list_result_ids(results_dir)
last = 0
for last_candidate in result_ids:
try:
last = int(last_candidate)
break
except:
pass
ret = os.path.join(
self._get_task_results_dir(results_dir),
str(last + 1)
)
assert(not os.path.exists(ret))
return ret
def remove_results(self, config):
logging.debug("Removing all results of task '%s'.", self.id_)
task_results_dir = self._get_task_results_dir(config.results_dir)
shutil.rmtree(task_results_dir, False)
def remove_result(self, result_id, config):
# todo needs refactoring - the path is used from many places
result_path = os.path.join(
self._get_task_results_dir(config.results_dir),
str(result_id),
)
logging.debug(
"Removing ARF of result '%s' of task '%i', expected path '%s'.",
str(result_id), self.id_, result_path
)
shutil.rmtree(result_path, False)
logging.info(
"Removed result '%s' of task '%i'.", str(result_id), self.id_
)
def get_next_update_time(self, reference_datetime, log=False):
if not self.enabled:
if log:
logging.debug(
"Task '%i' is disabled, not updating it.", self.id_
)
return None
if self.run_outside_schedule_once:
if log:
logging.debug(
"Evaluating task '%i'. It was set to be run once outside "
"its schedule.", self.id_
)
return reference_datetime
if self.schedule.not_before is None:
if log:
logging.debug(
"Task '%i' is enabled but schedule.not_before is None. "
"It won't be run automatically.", self.id_
)
return self.schedule.not_before
def should_be_updated(self, reference_datetime, log=False):
next_update_time = self.get_next_update_time(reference_datetime, log)
if next_update_time is not None and \
next_update_time <= reference_datetime:
if log:
logging.debug(
"Evaluating task '%i'. It was scheduled to be "
"evaluated later than %s, reference_datetime %s is "
"higher than or equal.",
self.id_, next_update_time, reference_datetime
)
return True
return False
def prune_old_results(self, config):
max_results_to_keep = self.max_results_to_keep
if max_results_to_keep == -1:
max_results_to_keep = config.max_results_to_keep
if max_results_to_keep < 0:
# pruning is disabled
return
result_ids = self.list_result_ids(config.results_dir)
result_ids_to_remove = result_ids[max_results_to_keep:]
if result_ids_to_remove:
logging.info("Pruning old results of task '%i'...", self.id_)
for result_id in reversed(result_ids_to_remove):
self.remove_result(result_id, config)
def update(self, reference_datetime, config):
"""Figures out if the task should be run right now, alters the schedule
values accordingly.
reference datetime is passed mainly because of easier diagnostics.
It prevents some tasks being run and others not even though they have
the same not_before value.
Assumption: tick is never in parallel on the same Task. It can be run
in parallel on different tasks but at most once for 1 Task instance.
"""
with self.update_lock:
if not self.is_valid():
raise RuntimeError("Can't update an invalid Task.")
if self.should_be_updated(reference_datetime, True):
wip_result = self.evaluation_spec.evaluate_into_dir(config)
# We already have update_lock, there is no risk of a race
# condition between acquiring target dir and moving the results
# there.
target_dir = self._get_next_target_dir(config.results_dir)
logging.debug(
"Moving results of task '%s' from '%s' to '%s'.",
self.id_, wip_result, target_dir
)
shutil.move(wip_result, target_dir)
logging.info(
"Evaluated task '%s', new result in '%s'.",
self.id_, target_dir
)
if not self.run_outside_schedule_once:
self.schedule.not_before = \
self.schedule.next_not_before(reference_datetime)
self.save()
else:
self.run_outside_schedule_once = False
# we have one extra result, let's prune old results
self.prune_old_results(config)
def generate_guide(self, config):
return self.evaluation_spec.generate_guide(config)
def run_outside_schedule(self):
if not self.enabled:
raise RuntimeError(
"This task is disabled. Enable it first if you want to run it "
"once outside the schedule!"
)
if self.run_outside_schedule_once:
raise RuntimeError(
"This task was already scheduled to be run once "
"outside the schedule!"
)
self.run_outside_schedule_once = True
logging.info(
"Set task '%i' to be run once outside the schedule.", self.id_
)
def get_xml_of_result(self, result_id, config):
# TODO: This needs refactoring in the future, the secret that the file
# is called "results.xml" is all over the place.
path = os.path.join(
self._get_task_results_dir(config.results_dir),
str(result_id),
"results.xml"
)
logging.debug(
"Retrieving XML of result '%i' of task '%i', expected path '%s'.",
result_id, self.id_, path
)
ret = ""
with io.open(path, "r", encoding="utf-8") as f:
ret = f.read()
logging.info(
"Retrieved XML of result '%i' of task '%i'.",
result_id, self.id_
)
return ret
def get_stdout_of_result(self, result_id, config):
path = os.path.join(
self._get_task_results_dir(config.results_dir),
str(result_id),
"stderr"
)
ret = ""
with io.open(path, "r", encoding="utf-8") as f:
ret = f.read()
return ret
def get_stderr_of_result(self, result_id, config):
path = os.path.join(
self._get_task_results_dir(config.results_dir),
str(result_id),
"stderr"
)
ret = ""
with io.open(path, "r", encoding="utf-8") as f:
ret = f.read()
return ret
def get_exit_code_of_result(self, result_id, config):
path = os.path.join(
self._get_task_results_dir(config.results_dir),
str(result_id),
"exit_code"
)
ret = ""
with io.open(path, "r", encoding="utf-8") as f:
ret = f.read()
return int(ret.strip())
def generate_report_for_result(self, result_id, config):
return oscap_helpers.generate_report_for_result(
self.evaluation_spec,
self._get_task_results_dir(config.results_dir),
result_id,
config
)
def generate_fix_for_result(self, result_id, config, fix_type):
results_dir = self._get_task_results_dir(config.results_dir)
results_path = os.path.join(results_dir, str(result_id), "results.xml")
return oscap_helpers.generate_fix_for_result(
config,
results_path,
fix_type,
None
)
openscap-daemon-0.1.10/openscap_daemon/version.py 0000664 0000000 0000000 00000001766 13237071060 0022045 0 ustar 00root root 0000000 0000000 # Copyright 2017 Red Hat Inc., Durham, North Carolina.
# All Rights Reserved.
#
# openscap-daemon is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 2.1 of the License, or
# (at your option) any later version.
#
# openscap-daemon is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
# You should have received a copy of the GNU Lesser General Public License
# along with openscap-daemon. If not, see .
#
# Authors:
# Martin Preisler
VERSION_MAJOR = 0
VERSION_MINOR = 1
VERSION_PATCH = 10
VERSION_STRING = "%i.%i.%i" % (VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH)
__all__ = ["VERSION_MAJOR", "VERSION_MINOR", "VERSION_PATCH", "VERSION_STRING"]
openscap-daemon-0.1.10/org.oscapd.conf 0000664 0000000 0000000 00000001103 13237071060 0017542 0 ustar 00root root 0000000 0000000
openscap-daemon-0.1.10/oscapd.service 0000664 0000000 0000000 00000000315 13237071060 0017473 0 ustar 00root root 0000000 0000000 [Unit]
Description=OpenSCAP Daemon
Documentation=http://open-scap.org/tools/openscap-daemon
[Service]
Type=dbus
BusName=org.OpenSCAP.daemon
ExecStart=/usr/bin/oscapd
[Install]
WantedBy=multi-user.target
openscap-daemon-0.1.10/perform-static-analysis 0000775 0000000 0000000 00000001614 13237071060 0021351 0 ustar 00root root 0000000 0000000 #!/usr/bin/env bash
OUTPUT_FILE="static-analysis-output"
which pylint && which pychecker && which pyflakes
if [ $? -ne 0 ]; then
echo "One or more dependencies were not found!"
exit 1
fi
echo "Output from static analysis tools" > $OUTPUT_FILE
echo "=================================" >> $OUTPUT_FILE
echo >> $OUTPUT_FILE
echo "Running pylint 1/3..."
echo "pylint:" >> $OUTPUT_FILE
echo >> $OUTPUT_FILE
pylint --rcfile pylint.cfg openscap_daemon >> $OUTPUT_FILE
echo >> $OUTPUT_FILE
echo "Running pychecker 2/3..."
echo "pychecker:" >> $OUTPUT_FILE
echo >> $OUTPUT_FILE
find openscap_daemon/ -name "*\.py" -print0 | xargs --null pychecker --limit 0 2>&1 >> $OUTPUT_FILE
echo >> $OUTPUT_FILE
echo "Running pyflakes 3/3..."
echo "pyflakes:" >> $OUTPUT_FILE
echo >> $OUTPUT_FILE
pyflakes openscap_daemon >> $OUTPUT_FILE
echo >> $OUTPUT_FILE
echo "Static analysis finished, output in $OUTPUT_FILE"
openscap-daemon-0.1.10/pylint.cfg 0000664 0000000 0000000 00000013720 13237071060 0016644 0 ustar 00root root 0000000 0000000 [MASTER]
# Specify a configuration file.
#rcfile=
# Python code to execute, usually for sys.path manipulation such as
# pygtk.require().
#init-hook=
# Profiled execution.
profile=no
# Add files or directories to the blacklist. They should be base names, not
# paths.
ignore=.git
# Pickle collected data for later comparisons.
persistent=yes
# List of plugins (as comma separated values of python modules names) to load,
# usually to register additional checkers.
load-plugins=
[MESSAGES CONTROL]
# Enable the message, report, category or checker with the given id(s). You can
# either give multiple identifier separated by comma (,) or put this option
# multiple time.
#enable=
# Disable the message, report, category or checker with the given id(s). You
# can either give multiple identifier separated by comma (,) or put this option
# multiple time (only on the command line, not in the configuration file where
# it should appear only once).
# line too long, no docstring, too many members
disable=C0301, C0111, R0904
[REPORTS]
# Set the output format. Available formats are text, parseable, colorized, msvs
# (visual studio) and html
output-format=text
# Include message's id in output
include-ids=no
# Put messages in a separate file for each module / package specified on the
# command line instead of printing them on stdout. Reports (if any) will be
# written in a file name "pylint_global.[txt|html]".
files-output=no
# Tells whether to display a full report or only the messages
reports=yes
# Python expression which should return a note less than 10 (10 is the highest
# note). You have access to the variables errors warning, statement which
# respectively contain the number of errors / warnings messages and the total
# number of statements analyzed. This is used by the global evaluation report
# (RP0004).
evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10)
# Add a comment according to your evaluation note. This is used by the global
# evaluation report (RP0004).
comment=no
[TYPECHECK]
# Tells whether missing members accessed in mixin class should be ignored. A
# mixin class is detected if its name ends with "mixin" (case insensitive).
ignore-mixin-members=yes
# List of classes names for which member attributes should not be checked
# (useful for classes with attributes dynamically set).
ignored-classes=
# When zope mode is activated, add a predefined set of Zope acquired attributes
# to generated-members.
zope=no
# List of members which are set dynamically and missed by pylint inference
# system, and so shouldn't trigger E0201 when accessed. Python regular
# expressions are accepted.
generated-members=REQUEST,acl_users,aq_parent
[BASIC]
# Required attributes for module, separated by a comma
required-attributes=
# List of builtins function names that should not be used, separated by a comma
bad-functions=map,filter,apply,input
# Good variable names which should always be accepted, separated by a comma
good-names=i,j,k,ex,_
# Bad variable names which should always be refused, separated by a comma
bad-names=foo,bar,baz,toto,tutu,tata
# Regular expression which should only match functions or classes name which do
# not require a docstring
no-docstring-rgx=__.*__
[SIMILARITIES]
# Minimum lines number of a similarity.
min-similarity-lines=4
# Ignore comments when computing similarities.
ignore-comments=yes
# Ignore docstrings when computing similarities.
ignore-docstrings=yes
[FORMAT]
# Maximum number of characters on a single line.
max-line-length=80
# Maximum number of lines in a module
max-module-lines=1000
# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1
# tab).
indent-string=' '
[VARIABLES]
# Tells whether we should check for unused import in __init__ files.
init-import=no
# A regular expression matching the beginning of the name of dummy variables
# (i.e. not used).
dummy-variables-rgx=_|dummy
# List of additional names supposed to be defined in builtins. Remember that
# you should avoid to define new builtins when possible.
additional-builtins=
[MISCELLANEOUS]
# List of note tags to take in consideration, separated by a comma.
notes=FIXME,XXX,TODO
[CLASSES]
# List of interface methods to ignore, separated by a comma. This is used for
# instance to not check methods defines in Zope's Interface base class.
ignore-iface-methods=isImplementedBy,deferred,extends,names,namesAndDescriptions,queryDescriptionFor,getBases,getDescriptionFor,getDoc,getName,getTaggedValue,getTaggedValueTags,isEqualOrExtendedBy,setTaggedValue,isImplementedByInstancesOf,adaptWith,is_implemented_by
# List of method names used to declare (i.e. assign) instance attributes.
defining-attr-methods=__init__,__new__,setUp
[IMPORTS]
# Deprecated modules which should not be used, separated by a comma
deprecated-modules=regsub,string,TERMIOS,Bastion,rexec
# Create a graph of every (i.e. internal and external) dependencies in the
# given file (report RP0402 must not be disabled)
import-graph=
# Create a graph of external dependencies in the given file (report RP0402 must
# not be disabled)
ext-import-graph=
# Create a graph of internal dependencies in the given file (report RP0402 must
# not be disabled)
int-import-graph=
[DESIGN]
# Maximum number of arguments for function / method
max-args=5
# Argument names that match this expression will be ignored. Default to name
# with leading underscore
ignored-argument-names=_.*
# Maximum number of locals for function / method body
max-locals=15
# Maximum number of return / yield for function / method body
max-returns=6
# Maximum number of branch for function / method body
max-branchs=12
# Maximum number of statements in function / method body
max-statements=50
# Maximum number of parents for a class (see R0901).
max-parents=7
# Maximum number of attributes for a class (see R0902).
max-attributes=20
# Minimum number of public methods for a class (see R0903).
min-public-methods=2
# Maximum number of public methods for a class (see R0904).
max-public-methods=30
openscap-daemon-0.1.10/runwrapper.sh 0000775 0000000 0000000 00000002411 13237071060 0017403 0 ustar 00root root 0000000 0000000 #!/bin/bash
# Copyright 2015 Red Hat Inc., Durham, North Carolina.
# All Rights Reserved.
#
# openscap-daemon is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 2.1 of the License, or
# (at your option) any later version.
#
# openscap-daemon is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
# You should have received a copy of the GNU Lesser General Public License
# along with openscap-daemon. If not, see .
#
# Authors:
# Martin Preisler
# parent dir of this script
PARENT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
# add directory with "openscap_daemon" to $PYTHONPATH
export PYTHONPATH=$PARENT_DIR:$PYTHONPATH
# force python to print using utf-8
export PYTHONIOENCODING=UTF-8
export OSCAPD_CONFIG_FILE="$PARENT_DIR/tests/data_dir_template/config.ini"
export OSCAPD_SESSION_BUS="1"
if [ "x$RUNWRAPPER_NO_FORK" != "x1" ]; then
# fork a new shell to avoid polluting the environment
bash
fi
openscap-daemon-0.1.10/setup.py 0000775 0000000 0000000 00000004170 13237071060 0016360 0 ustar 00root root 0000000 0000000 #!/usr/bin/python
# Copyright 2015 Red Hat Inc., Durham, North Carolina.
# All Rights Reserved.
#
# openscap-daemon is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 2.1 of the License, or
# (at your option) any later version.
#
# openscap-daemon is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
# You should have received a copy of the GNU Lesser General Public License
# along with openscap-daemon. If not, see .
#
# Authors:
# Martin Preisler
import os
import os.path
from openscap_daemon import version
from distutils.core import setup
def get_packages():
# Distutils requires us to list all packages, this is very tedious and prone
# to errors. This method crawls the hierarchy and gathers all packages.
ret = ["openscap_daemon"]
for dirpath, _, files in os.walk("openscap_daemon"):
if "__init__.py" in files:
ret.append(dirpath.replace(os.path.sep, "."))
return ret
setup(
name="openscap_daemon",
version=version.VERSION_STRING,
author="Martin Preisler, Brent Baude and others",
author_email="mpreisle@redhat.com",
description="...",
license="LGPL2.1+",
url="http://www.open-scap.org/",
packages=get_packages(),
scripts=[
os.path.join("bin", "oscapd"),
os.path.join("bin", "oscapd-cli"),
os.path.join("bin", "oscapd-evaluate")
],
data_files=[
(os.path.join("/", "etc", "dbus-1", "system.d"),
["org.oscapd.conf"]),
(os.path.join("/", "usr", "lib", "systemd", "system"),
["oscapd.service"]),
(os.path.join("/", "usr", "share", "doc", "openscap-daemon"),
["README.md", "LICENSE"]),
(os.path.join("/", "usr", "share", "man", "man8"),
["man/oscapd.8", "man/oscapd-cli.8", "man/oscapd-evaluate.8"]),
],
)
openscap-daemon-0.1.10/tests/ 0000775 0000000 0000000 00000000000 13237071060 0016003 5 ustar 00root root 0000000 0000000 openscap-daemon-0.1.10/tests/data_dir_template/ 0000775 0000000 0000000 00000000000 13237071060 0021445 5 ustar 00root root 0000000 0000000 openscap-daemon-0.1.10/tests/data_dir_template/config.ini 0000664 0000000 0000000 00000000363 13237071060 0023415 0 ustar 00root root 0000000 0000000 [General]
tasks-dir=./tasks
results-dir=./results
work-in-progress-dir=./work_in_progress
cve-feeds-dir=./cve_feeds
jobs=4
max-results-to-keep=100
[Tools]
oscap=
oscap-ssh=
oscap-vm=
oscap-docker=
[Content]
ssg=
[CVEScanner]
fetch-cve-url=
openscap-daemon-0.1.10/tests/data_dir_template/config_test.ini 0000664 0000000 0000000 00000000345 13237071060 0024454 0 ustar 00root root 0000000 0000000 [General]
jobs=8
[Tools]
oscap=/a/b/c/oscap
oscap-ssh=/d/e/f/oscap-ssh
oscap-vm=/openscap/bin/oscap-vm
oscap-docker=/g/h/i/j/oscap-docker
[Content]
ssg=/g/h/i/ssg/content
[CVEScanner]
fetch-cve-url=http://a.b.com/some/folder/
openscap-daemon-0.1.10/tests/data_dir_template/tasks/ 0000775 0000000 0000000 00000000000 13237071060 0022572 5 ustar 00root root 0000000 0000000 openscap-daemon-0.1.10/tests/data_dir_template/tasks/1.xml 0000664 0000000 0000000 00002746572 13237071060 0023503 0 ustar 00root root 0000000 0000000
Weekly SCAP Security Guide Evaluationsdslocalhost
<?xml version="1.0" encoding="UTF-8"?>
<ds:data-stream-collection xmlns:ds="http://scap.nist.gov/schema/scap/source/1.2" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:cat="urn:oasis:names:tc:entity:xmlns:xml:catalog" id="scap_org.open-scap_collection_from_xccdf_ssg-fedora-xccdf-1.2.xml" schematron-version="1.0">
<ds:data-stream id="scap_org.open-scap_datastream_from_xccdf_ssg-fedora-xccdf-1.2.xml" scap-version="1.2" use-case="OTHER">
<ds:dictionaries>
<ds:component-ref id="scap_org.open-scap_cref_output--ssg-fedora-cpe-dictionary.xml" xlink:href="#scap_org.open-scap_comp_output--ssg-fedora-cpe-dictionary.xml">
<cat:catalog>
<cat:uri name="ssg-fedora-cpe-oval.xml" uri="#scap_org.open-scap_cref_output--ssg-fedora-cpe-oval.xml"/>
</cat:catalog>
</ds:component-ref>
</ds:dictionaries>
<ds:checklists>
<ds:component-ref id="scap_org.open-scap_cref_ssg-fedora-xccdf-1.2.xml" xlink:href="#scap_org.open-scap_comp_ssg-fedora-xccdf-1.2.xml">
<cat:catalog>
<cat:uri name="ssg-fedora-oval.xml" uri="#scap_org.open-scap_cref_ssg-fedora-oval.xml"/>
</cat:catalog>
</ds:component-ref>
</ds:checklists>
<ds:checks>
<ds:component-ref id="scap_org.open-scap_cref_ssg-fedora-oval.xml" xlink:href="#scap_org.open-scap_comp_ssg-fedora-oval.xml"/>
<ds:component-ref id="scap_org.open-scap_cref_output--ssg-fedora-cpe-oval.xml" xlink:href="#scap_org.open-scap_comp_output--ssg-fedora-cpe-oval.xml"/>
<ds:component-ref id="scap_org.open-scap_cref_output--ssg-fedora-oval.xml" xlink:href="#scap_org.open-scap_comp_output--ssg-fedora-oval.xml"/></ds:checks>
</ds:data-stream>
<ds:component id="scap_org.open-scap_comp_ssg-fedora-oval.xml" timestamp="2015-03-17T12:23:34">
<oval_definitions xmlns="http://oval.mitre.org/XMLSchema/oval-definitions-5" xmlns:oval="http://oval.mitre.org/XMLSchema/oval-common-5" xmlns:ind="http://oval.mitre.org/XMLSchema/oval-definitions-5#independent" xmlns:unix="http://oval.mitre.org/XMLSchema/oval-definitions-5#unix" xmlns:linux="http://oval.mitre.org/XMLSchema/oval-definitions-5#linux" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://oval.mitre.org/XMLSchema/oval-common-5 oval-common-schema.xsd http://oval.mitre.org/XMLSchema/oval-definitions-5 oval-definitions-schema.xsd http://oval.mitre.org/XMLSchema/oval-definitions-5#independent independent-definitions-schema.xsd http://oval.mitre.org/XMLSchema/oval-definitions-5#unix unix-definitions-schema.xsd http://oval.mitre.org/XMLSchema/oval-definitions-5#linux linux-definitions-schema.xsd">
<generator>
<oval:product_name>python</oval:product_name>
<oval:product_version>2.6.6</oval:product_version>
<oval:schema_version>5.10</oval:schema_version>
<oval:timestamp>2011-09-21T13:44:00</oval:timestamp>
</generator>
<definitions>
<definition class="compliance" id="oval:ssg:def:125" version="1">
<metadata>
<title>Specify a Remote NTP Server for Time Data</title>
<affected family="unix">
<platform>Red Hat Enterprise Linux 6</platform>
<platform>Red Hat Enterprise Linux 7</platform>
<platform>Fedora 20</platform>
</affected>
<description>Multiple NTP Servers for time synchronization should be
specified</description>
<reference source="galford" ref_id="20141107" ref_url="test_attestation"/>
<reference ref_id="ntpd_specify_multiple_servers" source="ssg"/></metadata>
<criteria comment="ntp.conf conditions are met">
<criterion test_ref="oval:ssg:tst:126"/>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:127" version="1">
<metadata>
<title>No nullok Option in /etc/pam.d/system-auth</title>
<affected family="unix">
<platform>Red Hat Enterprise Linux 6</platform>
<platform>Red Hat Enterprise Linux 7</platform>
<platform>Fedora 20</platform>
</affected>
<description>The file /etc/pam.d/system-auth should not contain the nullok option</description>
<reference source="swells" ref_id="20130918" ref_url="test_attestation"/>
<reference ref_id="no_empty_passwords" source="ssg"/></metadata>
<criteria>
<criterion comment="make sure the nullok option is not used in /etc/pam.d/system-auth" test_ref="oval:ssg:tst:128"/>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:129" version="1">
<metadata>
<title>Set Password minclass Requirements</title>
<affected family="unix">
<platform>Red Hat Enterprise Linux 7</platform>
<platform>Fedora 20</platform>
</affected>
<description>The password minclass should meet the minimum requirements</description>
<reference source="galford" ref_id="20141010" ref_url="test_attestation"/>
<reference ref_id="accounts_password_pam_minclass" source="ssg"/></metadata>
<criteria operator="AND" comment="conditions for minclass are satisfied">
<extend_definition comment="pwquality.so exists in system-auth" definition_ref="oval:ssg:def:130"/>
<criterion comment="pwquality.conf" test_ref="oval:ssg:tst:131"/>
</criteria>
</definition>
<definition class="inventory" id="oval:ssg:def:100" version="1">
<metadata>
<title>Fedora release 19 (Schrödinger's Cat)</title>
<affected family="unix">
<platform>Fedora 19</platform>
</affected>
<reference ref_id="cpe:/o:fedoraproject:fedora:19" source="CPE"/>
<description>The operating system installed on the system is
Fedora release 19 (Schrödinger's Cat)</description>
<reference ref_id="installed_OS_is_fedora19" source="ssg"/></metadata>
<criteria>
<criterion comment="Installed operating system is part of the unix family" test_ref="oval:ssg:tst:101"/>
<criterion comment="Fedora release 19 is installed" test_ref="oval:ssg:tst:102"/>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:132" version="1">
<metadata>
<title>Package openssh-server Removed</title>
<affected family="unix">
<platform>Fedora 19</platform>
<platform>Red Hat Enterprise Linux 6</platform>
<platform>Red Hat Enterprise Linux 7</platform>
</affected>
<description>The RPM package openssh-server should be removed.</description>
<reference source="swells" ref_id="20130829" ref_url="test_attestation"/>
<reference ref_id="package_openssh-server_removed" source="ssg"/></metadata>
<criteria>
<criterion comment="package openssh-server is removed" test_ref="oval:ssg:tst:133"/>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:134" version="1">
<metadata>
<title>Package dconf Installed</title>
<affected family="unix">
<platform>Red Hat Enterprise Linux 7</platform>
<platform>Fedora 20</platform>
</affected>
<description>The RPM package dconf should be installed.</description>
<reference source="galford" ref_id="20140424" ref_url="test_attestation"/>
<reference ref_id="package_dconf_installed" source="ssg"/></metadata>
<criteria>
<criterion comment="package dconf is installed" test_ref="oval:ssg:tst:135"/>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:136" version="3">
<metadata>
<title>Set Password Expiration Parameters</title>
<affected family="unix">
<platform>Red Hat Enterprise Linux 6</platform>
<platform>Red Hat Enterprise Linux 7</platform>
<platform>Fedora 20</platform>
</affected>
<description>The maximum password age policy should meet minimum requirements.</description>
<reference source="JL" ref_id="RHEL6_20150130" ref_url="test_attestation"/>
<reference source="JL" ref_id="RHEL7_20150130" ref_url="test_attestation"/>
<reference source="JL" ref_id="FEDORA20_20150130" ref_url="test_attestation"/>
<reference ref_id="accounts_maximum_age_login_defs" source="ssg"/></metadata>
<criteria comment="The value PASS_MAX_DAYS should be set appropriately in /etc/login.defs">
<criterion test_ref="oval:ssg:tst:137"/>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:138" version="1">
<metadata>
<title>Verify that System Executables Have Root Ownership</title>
<affected family="unix">
<platform>Fedora 19</platform>
<platform>Red Hat Enterprise Linux 6</platform>
<platform>Red Hat Enterprise Linux 7</platform>
</affected>
<description>
Checks that /bin, /sbin, /usr/bin, /usr/sbin, /usr/local/bin,
/usr/local/sbin, and objects therein, are owned by root.
</description>
<reference ref_id="file_ownership_binary_dirs" source="ssg"/></metadata>
<criteria operator="AND">
<criterion test_ref="oval:ssg:tst:139"/>
<criterion test_ref="oval:ssg:tst:140"/>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:141" version="1">
<metadata>
<title>Set OpenSSH Idle Timeout Interval</title>
<affected family="unix">
<platform>Red Hat Enterprise Linux 6</platform>
<platform>Red Hat Enterprise Linux 7</platform>
<platform>Fedora 20</platform>
</affected>
<description>The SSH idle timeout interval should be set to an
appropriate value.</description>
<reference source="JL" ref_id="20140414" ref_url="test_attestation"/>
<!-- Fedora 20: <reference source="JL" ref_id="20140224" ref_url="test_attestation" /> -->
<reference ref_id="sshd_set_idle_timeout" source="ssg"/></metadata>
<criteria comment="SSH is not being used or conditions are met" operator="OR">
<extend_definition comment="sshd service is disabled" definition_ref="oval:ssg:def:142"/>
<criterion comment="Check ClientAliveInterval in /etc/ssh/sshd_config" test_ref="oval:ssg:tst:143"/>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:144" version="1">
<metadata>
<title>Enable GNOME3 Login Warning Banner</title>
<affected family="unix">
<platform>Red Hat Enterprise Linux 7</platform>
<platform>Fedora 20</platform>
</affected>
<description>Enable the GNOME3 Login warning banner.</description>
<reference source="galford" ref_id="20140823" ref_url="test_attestation"/>
<reference ref_id="dconf_gnome_banner_enabled" source="ssg"/></metadata>
<criteria operator="OR">
<extend_definition comment="dconf installed" definition_ref="oval:ssg:def:134" negate="true"/>
<criteria comment="Enable GUI banner and prevent user from changing it" operator="AND">
<extend_definition comment="dconf user profile exists" definition_ref="oval:ssg:def:145"/>
<criterion comment="Enable GUI banner" test_ref="oval:ssg:tst:146"/>
<criterion comment="Prevent user from disabling banner" test_ref="oval:ssg:tst:147"/>
</criteria>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:148" version="1">
<metadata>
<title>Verify that Shared Library Files Have Root Ownership</title>
<affected family="unix">
<platform>Fedora 19</platform>
<platform>Red Hat Enterprise Linux 6</platform>
<platform>Red Hat Enterprise Linux 7</platform>
</affected>
<description>
Checks that /lib, /lib64, /usr/lib, /usr/lib64, /lib/modules, and
objects therein, are owned by root.
</description>
<reference ref_id="file_ownership_library_dirs" source="ssg"/></metadata>
<criteria operator="AND">
<criterion test_ref="oval:ssg:tst:149"/>
<criterion test_ref="oval:ssg:tst:150"/>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:151" version="2">
<metadata>
<title>Disable Prelinking</title>
<affected family="unix">
<platform>Red Hat Enterprise Linux 6</platform>
<platform>Fedora 20</platform>
</affected>
<description>The prelinking feature can interfere with the operation of
checksum integrity tools (e.g. AIDE), mitigates the protection provided
by ASLR, and requires additional CPU cycles by software upgrades.
</description>
<reference source="JL" ref_id="20140313" ref_url="test_attestation"/>
<!-- Fedora 20: <reference source="JL" ref_id="20140313" ref_url="test_attestation" /> -->
<reference ref_id="disable_prelink" source="ssg"/></metadata>
<criteria>
<criterion comment="Ensure prelinking is disabled" test_ref="oval:ssg:tst:152"/>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:153" version="2">
<metadata>
<title>Set SHA512 Password Hashing Algorithm in /etc/login.defs</title>
<affected family="unix">
<platform>Red Hat Enterprise Linux 6</platform>
<platform>Red Hat Enterprise Linux 7</platform>
</affected>
<description>The password hashing algorithm should be set correctly in /etc/login.defs.</description>
<reference source="JL" ref_id="RHEL6_20150201" ref_url="test_attestation"/>
<reference source="JL" ref_id="RHEL7_20150201" ref_url="test_attestation"/>
<reference source="JL" ref_id="FEDORA20_20150201" ref_url="test_attestation"/>
<reference ref_id="set_password_hashing_algorithm_logindefs" source="ssg"/></metadata>
<criteria operator="AND">
<criterion test_ref="oval:ssg:tst:154"/>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:155" version="1">
<metadata>
<title>Proper Permissions User Home Directories</title>
<affected family="unix">
<platform>Red Hat Enterprise Linux 6</platform>
<platform>Red Hat Enterprise Linux 7</platform>
<platform>Fedora 20</platform>
</affected>
<description>File permissions should be set correctly for the home directories for all user accounts.</description>
<reference source="JL" ref_id="RHEL6_20141106" ref_url="test_attestation"/>
<reference source="JL" ref_id="RHEL7_20141106" ref_url="test_attestation"/>
<reference source="JL" ref_id="Fedora20_20141106" ref_url="test_attestation"/>
<reference ref_id="file_permissions_home_dirs" source="ssg"/></metadata>
<criteria>
<criterion comment="home directories" test_ref="oval:ssg:tst:156" negate="true"/>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:157" version="3">
<metadata>
<title>Lock out account after failed login attempts</title>
<affected family="unix">
<platform>Red Hat Enterprise Linux 6</platform>
<platform>Red Hat Enterprise Linux 7</platform>
<platform>Fedora 20</platform>
</affected>
<description>The number of allowed failed logins should be set correctly.</description>
<reference source="JL" ref_id="RHEL6_20150122" ref_url="test_attestation"/>
<reference source="JL" ref_id="RHEL7_20150122" ref_url="test_attestation"/>
<reference source="JL" ref_id="FEDORA20_20150122" ref_url="test_attestation"/>
<reference ref_id="accounts_passwords_pam_faillock_deny" source="ssg"/></metadata>
<criteria>
<criterion test_ref="oval:ssg:tst:158" comment="pam_faillock.so preauth silent set in system-auth"/>
<criterion test_ref="oval:ssg:tst:159" comment="pam_faillock.so authfail deny value set in system-auth"/>
<criterion test_ref="oval:ssg:tst:160" comment="pam_faillock.so set in account phase of system-auth"/>
<criterion test_ref="oval:ssg:tst:161" comment="pam_faillock.so preauth silent set in password-auth"/>
<criterion test_ref="oval:ssg:tst:162" comment="pam_faillock.so authfail deny value set in password-auth"/>
<criterion test_ref="oval:ssg:tst:163" comment="pam_faillock.so set in account phase of password-auth"/>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:164" version="2">
<metadata>
<title>SNMP use newer protocols</title>
<affected family="unix">
<platform>Red Hat Enterprise Linux 6</platform>
<platform>Red Hat Enterprise Linux 7</platform>
<platform>Fedora 20</platform>
</affected>
<description>SNMP version 1 and 2c must not be enabled.</description>
<reference source="galford" ref_id="20140813" ref_url="test_attestation"/>
<reference ref_id="snmpd_use_newer_protocol" source="ssg"/></metadata>
<criteria operator="OR">
<extend_definition comment="SMNP installed" definition_ref="oval:ssg:def:165"/>
<criterion comment="SNMP protocols" test_ref="oval:ssg:tst:166"/>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:167" version="1">
<metadata>
<title>Banner for FTP Users</title>
<affected family="unix">
<platform>Red Hat Enterprise Linux 6</platform>
<platform>Red Hat Enterprise Linux 7</platform>
<platform>Fedora 20</platform>
</affected>
<description>To trace malicious activity facilitated by the FTP
service, it must be configured to ensure that all commands sent to
the FTP server are logged using the verbose vsftpd log format.
</description>
<reference source="galford" ref_id="20140812" ref_url="test_attestation"/>
<reference ref_id="ftp_log_transactions" source="ssg"/></metadata>
<criteria comment="FTP is not being used or the conditions are met" operator="OR">
<extend_definition comment="vsftp package is not installed" definition_ref="oval:ssg:def:168" negate="true"/>
<criteria comment="FTP configuration conditions are not set or are met" operator="AND">
<criterion comment="log ftp transactions enable" test_ref="oval:ssg:tst:169"/>
<criterion comment="log ftp transactions format" test_ref="oval:ssg:tst:170"/>
<criterion comment="log ftp transactions protocol" test_ref="oval:ssg:tst:171"/>
</criteria>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:172" version="1">
<metadata>
<title>Implement Blank Screensaver</title>
<affected family="unix">
<platform>Red Hat Enterprise Linux 7</platform>
<platform>Fedora 20</platform>
</affected>
<description>The GNOME3 screensaver should be blank.</description>
<reference source="galford" ref_id="20140824" ref_url="test_attestation"/>
<reference ref_id="dconf_gnome_screensaver_mode_blank" source="ssg"/></metadata>
<criteria operator="OR">
<extend_definition comment="dconf installed" definition_ref="oval:ssg:def:134" negate="true"/>
<criteria comment="Enable blank screensaver and prevent user from changing it" operator="AND">
<extend_definition comment="dconf user profile exists" definition_ref="oval:ssg:def:145"/>
<criterion comment="screensaver is blank" test_ref="oval:ssg:tst:173"/>
<criterion comment="screensaver prevent user from changing mode" test_ref="oval:ssg:tst:174"/>
</criteria>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:175" version="2">
<metadata>
<title>Kernel Runtime Parameter "kernel.exec-shield" Check</title>
<affected family="unix">
<platform>Red Hat Enterprise Linux 7</platform>
<platform>Fedora 20</platform>
</affected>
<description>The kernel runtime parameter "kernel.exec-shield" should not be disabled and set to 1 on 32-bit systems.</description>
<reference source="galford" ref_id="201410" ref_url="test_attestation"/>
<reference ref_id="sysctl_kernel_exec_shield" source="ssg"/></metadata>
<criteria operator="OR">
<criteria operator="AND" comment="system is RHEL6">
<extend_definition comment="RHEL6 installed" definition_ref="oval:ssg:def:104"/>
<criterion comment="kernel runtime parameter kernel.exec-shield set to 1" test_ref="oval:ssg:tst:176"/>
<criterion comment="kernel /etc/sysctl.conf parameter kernel.exec-shield set to 1" test_ref="oval:ssg:tst:177"/>
</criteria>
<criteria operator="AND">
<extend_definition comment="32-bit system" definition_ref="oval:ssg:def:178"/>
<criterion comment="kernel runtime parameter kernel.exec-shield set to 1" test_ref="oval:ssg:tst:176"/>
<criterion comment="kernel /etc/sysctl.conf parameter kernel.exec-shield set to 1" test_ref="oval:ssg:tst:177"/>
</criteria>
<criteria operator="AND">
<extend_definition comment="64-bit system" definition_ref="oval:ssg:def:179"/>
<criterion comment="NX is supported and is not disabled" test_ref="oval:ssg:tst:180"/>
</criteria>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:181" version="1">
<metadata>
<title>Package ntp Installed</title>
<affected family="unix">
<platform>Fedora 19</platform>
<platform>Red Hat Enterprise Linux 6</platform>
<platform>Red Hat Enterprise Linux 7</platform>
</affected>
<description>The RPM package ntp should be installed.</description>
<reference source="swells" ref_id="20130829" ref_url="test_attestation"/>
<reference ref_id="package_ntp_installed" source="ssg"/></metadata>
<criteria>
<criterion comment="package ntp is installed" test_ref="oval:ssg:tst:182"/>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:165" version="1">
<metadata>
<title>Package net-snmp Removed</title>
<affected family="unix">
<platform>Red Hat Enterprise Linux 6</platform>
<platform>Red Hat Enterprise Linux 7</platform>
<platform>Fedora 20</platform>
</affected>
<description>The RPM package net-snmp should be removed.</description>
<reference source="swells" ref_id="20130829" ref_url="test_attestation"/>
<reference ref_id="package_net-snmp_removed" source="ssg"/></metadata>
<criteria>
<criterion comment="package net-snmp is removed" test_ref="oval:ssg:tst:183"/>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:179" version="1">
<!-- Note that this does not meet requirements for class=inventory as
that only tests for patches per 5.10.1 Revision 1 -->
<metadata>
<title>Test for x86_64 Architecture</title>
<affected family="unix">
<platform>Red Hat Enterprise Linux 6</platform>
<platform>Red Hat Enterprise Linux 7</platform>
</affected>
<description>Generic test for x86_64 architecture to be used by other tests</description>
<reference source="MED" ref_id="20130819" ref_url="test_attestation"/>
<reference ref_id="system_info_architecture_x86_64" source="ssg"/></metadata>
<criteria>
<criterion comment="Generic test for x86_64 architecture" test_ref="oval:ssg:tst:184"/>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:185" version="1">
<metadata>
<title>Set Password retry Requirements</title>
<affected family="unix">
<platform>Red Hat Enterprise Linux 6</platform>
<platform>Red Hat Enterprise Linux 7</platform>
<platform>Fedora 20</platform>
</affected>
<description>The password retry should meet minimum
requirements</description>
<reference source="swells" ref_id="20140925" ref_url="test_attestation"/>
<reference ref_id="accounts_password_pam_retry" source="ssg"/></metadata>
<criteria operator="OR" comment="Conditions for retry are satisfied">
<criteria operator="AND" comment="system is RHEL6 with pam_cracklib configured">
<extend_definition comment="RHEL6 installed" definition_ref="oval:ssg:def:104"/>
<criterion comment="rhel6 pam_cracklib" test_ref="oval:ssg:tst:186"/>
</criteria>
<criteria operator="AND" comment="system is RHEL7 with pam_pwquality configured">
<extend_definition comment="RHEL7 installed" definition_ref="oval:ssg:def:107"/>
<criterion comment="rhel7 pam_pwquality" test_ref="oval:ssg:tst:187"/>
</criteria>
<criteria operator="AND" comment="system is Fedora with pam_pwquality configured">
<extend_definition comment="Fedora installed" definition_ref="oval:ssg:def:100"/>
<criterion comment="Fedora pam_pwquality" test_ref="oval:ssg:tst:187"/>
</criteria>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:188" version="1">
<metadata>
<title>Package Antivirus Installed</title>
<affected family="unix">
<platform>Red Hat Enterprise Linux 6</platform>
<platform>Red Hat Enterprise Linux 7</platform>
<platform>Fedora 20</platform>
</affected>
<description>Antivirus software should be installed.</description>
<reference source="galford" ref_id="20140813" ref_url="test_attestation"/>
<reference ref_id="install_antivirus" source="ssg"/></metadata>
<criteria comment="Antivirus is not being used or conditions are met">
<criterion comment="Linuxshield AntiVirus package is installed" test_ref="oval:ssg:tst:189"/>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:190" version="1">
<metadata>
<title>Set Password minlen Requirements</title>
<affected family="unix">
<platform>Red Hat Enterprise Linux 7</platform>
<platform>Fedora 20</platform>
</affected>
<description>The password minlen should meet minimum requirements</description>
<reference source="galford" ref_id="20141010" ref_url="test_attestation"/>
<reference ref_id="accounts_password_pam_minlen" source="ssg"/></metadata>
<criteria operator="AND" comment="system uses pam_pwquality configured">
<extend_definition comment="pwquality.so exists in system-auth" definition_ref="oval:ssg:def:130"/>
<criterion comment="pam_pwquality" test_ref="oval:ssg:tst:191"/>
</criteria>
</definition>
<definition class="inventory" id="oval:ssg:def:103" version="1">
<metadata>
<title>Fedora release 20 (Schrödinger's Cat)</title>
<affected family="unix">
<platform>Fedora 20</platform>
</affected>
<reference ref_id="cpe:/o:fedoraproject:fedora:20" source="CPE"/>
<description>The operating system installed on the system is
Fedora release 20 (Schrödinger's Cat)</description>
<reference ref_id="installed_OS_is_fedora20" source="ssg"/></metadata>
<criteria>
<criterion comment="Installed operating system is part of the unix family" test_ref="oval:ssg:tst:101"/>
<criterion comment="Fedora release 20 is installed" test_ref="oval:ssg:tst:102"/>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:192" version="1">
<metadata>
<title>File grub.cfg Permissions</title>
<affected family="unix">
<platform>Red Hat Enterprise Linux 7</platform>
<platform>Fedora 20</platform>
</affected>
<description>File permissions for grub.cfg should be set to 0600 (or stronger). By default, this file is located at /boot/grub2/grub.cfg or, for EFI systems, at /boot/efi/EFI/redhat/grub.cfg</description>
<reference source="galford" ref_id="20140909" ref_url="test_attestation"/>
<reference ref_id="file_permissions_grub2_cfg" source="ssg"/></metadata>
<criteria operator="OR">
<criterion test_ref="oval:ssg:tst:193"/>
<criterion test_ref="oval:ssg:tst:194"/>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:195" version="1">
<metadata>
<title>Ensure gpgcheck Enabled For All Yum Package Repositories</title>
<affected family="unix">
<platform>Red Hat Enterprise Linux 6</platform>
<platform>Red Hat Enterprise Linux 7</platform>
<platform>Fedora 20</platform>
</affected>
<description>Ensure all yum repositories utilize signature checking.</description>
<reference source="MED" ref_id="20130807" ref_url="test_attestation"/>
<!-- rhel7 <reference source="SDW" ref_id="20131223" ref_url="test_attestation" /> -->
<reference ref_id="ensure_gpgcheck_never_disabled" source="ssg"/></metadata>
<criteria comment="ensure all yum repositories utilize signiature checking" operator="AND">
<criterion comment="verify no gpgpcheck=0 present in /etc/yum.repos.d files" test_ref="oval:ssg:tst:196"/>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:197" version="1">
<metadata>
<title>Enable GUI Warning Banner</title>
<affected family="unix">
<platform>Red Hat Enterprise Linux 7</platform>
<platform>Fedora 20</platform>
</affected>
<description>Enable the GUI warning banner.</description>
<reference source="galford" ref_id="20140902" ref_url="test_attestation"/>
<reference ref_id="dconf_gnome_login_banner_text" source="ssg"/></metadata>
<criteria operator="OR">
<extend_definition comment="dconf installed" definition_ref="oval:ssg:def:134" negate="true"/>
<criteria comment="Enable GUI banner and prevent user from changing it" operator="AND">
<extend_definition comment="dconf user profile exists" definition_ref="oval:ssg:def:145"/>
<criterion comment="Prevent user from changing banner" test_ref="oval:ssg:tst:198"/>
<criterion comment="Login banner is correctly set" test_ref="oval:ssg:tst:199"/>
</criteria>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:200" version="1">
<metadata>
<title>Verify No netrc Files Exist</title>
<affected family="unix">
<platform>Red Hat Enterprise Linux 6</platform>
<platform>Red Hat Enterprise Linux 7</platform>
<platform>Fedora 20</platform>
</affected>
<description>The .netrc files contain login information used to auto-login into FTP servers and reside in the user's home directory. Any .netrc files should be removed.</description>
<reference source="galford" ref_id="20141114" ref_url="test_attestation"/>
<reference ref_id="no_netrc_files" source="ssg"/></metadata>
<criteria>
<criterion test_ref="oval:ssg:tst:201" negate="true"/>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:178" version="1">
<!-- Note that this does not meet requirements for class=inventory as
that only tests for patches per 5.10.1 Revision 1 -->
<metadata>
<title>Test for x86 Architecture</title>
<affected family="unix">
<platform>Red Hat Enterprise Linux 6</platform>
<platform>Red Hat Enterprise Linux 7</platform>
</affected>
<description>Generic test for x86 architecture to be used by other tests</description>
<reference source="MED" ref_id="20130819" ref_url="test_attestation"/>
<reference ref_id="system_info_architecture_x86" source="ssg"/></metadata>
<criteria>
<criterion comment="Generic test for x86 architecture" test_ref="oval:ssg:tst:202"/>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:203" version="1">
<metadata>
<title>Specify a Remote NTP Server for Time Data</title>
<affected family="unix">
<platform>Red Hat Enterprise Linux 6</platform>
<platform>Red Hat Enterprise Linux 7</platform>
<platform>Fedora 20</platform>
</affected>
<description>A remote NTP Server for time synchronization should be
specified (and dependencies are met)</description>
<reference source="galford" ref_id="20141111" ref_url="test_attestation"/>
<reference ref_id="ntpd_specify_remote_server" source="ssg"/></metadata>
<criteria comment="ntp.conf conditions are met">
<criterion test_ref="oval:ssg:tst:204"/>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:205" version="1">
<metadata>
<title>Set ClientAliveCountMax for User Logins</title>
<affected family="unix">
<platform>Red Hat Enterprise Linux 6</platform>
<platform>Red Hat Enterprise Linux 7</platform>
<platform>Fedora 20</platform>
</affected>
<description>The SSH ClientAliveCountMax should be set to an appropriate
value (and dependencies are met)</description>
<reference source="JL" ref_id="20140414" ref_url="test_attestation"/>
<reference ref_id="sshd_set_keepalive" source="ssg"/></metadata>
<criteria comment="SSH is not being used or conditions are met" operator="OR">
<extend_definition comment="sshd service is disabled" definition_ref="oval:ssg:def:142"/>
<criterion comment="Check ClientAliveCountMax in /etc/ssh/sshd_config" test_ref="oval:ssg:tst:206"/>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:207" version="1">
<metadata>
<title>System Accounts Do Not Run a Shell</title>
<affected family="unix">
<platform>Red Hat Enterprise Linux 6</platform>
<platform>Red Hat Enterprise Linux 7</platform>
<platform>Fedora 20</platform>
</affected>
<description>The root account is the only system account that should have a login shell.</description>
<reference source="swells" ref_id="20130918" ref_url="test_attestation"/>
<reference ref_id="no_shelllogin_for_systemaccounts" source="ssg"/></metadata>
<criteria>
<criterion comment="tests for the presence of login shells (not /sbin/nologin) for system accounts in /etc/passwd file" test_ref="oval:ssg:tst:208"/>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:168" version="1">
<metadata>
<title>Package vsftpd Installed</title>
<affected family="unix">
<platform>Red Hat Enterprise Linux 6</platform>
<platform>Red Hat Enterprise Linux 7</platform>
</affected>
<description>The RPM package vsftpd should be installed.</description>
<reference source="JL" ref_id="20140522" ref_url="test_attestation"/>
<reference ref_id="package_vsftpd_installed" source="ssg"/></metadata>
<criteria>
<criterion comment="package vsftpd is installed" test_ref="oval:ssg:tst:209"/>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:210" version="1">
<metadata>
<title>Ensure insecure_locks is disabled</title>
<affected family="unix">
<platform>Red Hat Enterprise Linux 6</platform>
<platform>Red Hat Enterprise Linux 7</platform>
<platform>Fedora 20</platform>
</affected>
<description>Allowing insecure file locking could allow for sensitive
data to be viewed or edited by an unauthorized user.</description>
<reference source="galford" ref_id="20140813" ref_url="test_attestation"/>
<reference ref_id="no_insecure_locks_exports" source="ssg"/></metadata>
<criteria>
<criterion comment="Check for insecure NFS locks in /etc/exports" test_ref="oval:ssg:tst:211"/>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:212" version="2">
<metadata>
<title>SNMP default communities disabled</title>
<affected family="unix">
<platform>Red Hat Enterprise Linux 6</platform>
<platform>Red Hat Enterprise Linux 7</platform>
<platform>Fedora 20</platform>
</affected>
<description>SNMP default communities must be removed.</description>
<reference source="galford" ref_id="20140813" ref_url="test_attestation"/>
<reference ref_id="snmpd_not_default_password" source="ssg"/></metadata>
<criteria operator="OR">
<extend_definition comment="SMNP installed" definition_ref="oval:ssg:def:165"/>
<criterion comment="SNMP communities" test_ref="oval:ssg:tst:213"/>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:214" version="2">
<metadata>
<title>Set Password ucredit Requirements</title>
<affected family="unix">
<platform>Red Hat Enterprise Linux 7</platform>
<platform>Fedora 20</platform>
</affected>
<description>The password ucredit should meet minimum requirements</description>
<reference source="galford" ref_id="20141010" ref_url="test_attestation"/>
<reference ref_id="accounts_password_pam_ucredit" source="ssg"/></metadata>
<criteria operator="AND" comment="conditions for ucredit are satisfied">
<extend_definition comment="pwquality.so exists in system-auth" definition_ref="oval:ssg:def:130"/>
<criterion comment="pwquality.conf" test_ref="oval:ssg:tst:215"/>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:130" version="1">
<metadata>
<title>Check pam_pwquality Existence in system-auth</title>
<affected family="unix">
<platform>Red Hat Enterprise Linux 6</platform>
</affected>
<description>Check that pam_pwquality.so exists in system-auth</description>
<reference source="galford" ref_id="20141010" ref_url="test_attestation"/>
<reference ref_id="accounts_password_pam_pwquality" source="ssg"/></metadata>
<criteria>
<criterion comment="Conditions for pam_pwquality are satisfied" test_ref="oval:ssg:tst:216"/>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:217" version="1">
<metadata>
<title>Disable GNOME3 Automounting</title>
<affected family="unix">
<platform>Red Hat Enterprise Linux 7</platform>
<platform>Fedora 20</platform>
</affected>
<description>The system's default desktop environment, GNOME3, will mount
devices and removable media (such as DVDs, CDs and USB flash drives)
whenever they are inserted into the system. Disable automount and autorun
within GNOME3.</description>
<reference source="galford" ref_id="20140824" ref_url="test_attestation"/>
<reference ref_id="dconf_gnome_disable_automount" source="ssg"/></metadata>
<criteria operator="OR">
<extend_definition comment="dconf installed" definition_ref="oval:ssg:def:134" negate="true"/>
<criteria comment="Disable GNOME3 automount/autorun and prevent user from changing it" operator="AND">
<extend_definition comment="dconf user profile exists" definition_ref="oval:ssg:def:145"/>
<criterion comment="Disable automount in GNOME3" test_ref="oval:ssg:tst:218"/>
<criterion comment="Disable automount-open in GNOME3" test_ref="oval:ssg:tst:219"/>
<criterion comment="Disable autorun in GNOME3" test_ref="oval:ssg:tst:220"/>
<criterion comment="Prevent user from changing automount setting" test_ref="oval:ssg:tst:221"/>
<criterion comment="Prevent user from changing automount-open setting" test_ref="oval:ssg:tst:222"/>
<criterion comment="Prevent user from changing autorun setting" test_ref="oval:ssg:tst:223"/>
</criteria>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:142" version="1">
<metadata>
<title>Service sshd Disabled</title>
<affected family="unix">
<platform>Fedora 19</platform>
</affected>
<description>
The sshd service should be disabled.
</description>
<reference ref_id="service_sshd_disabled" source="ssg"/></metadata>
<criteria comment="package openssh-server removed or service sshd is not configured to start" operator="OR">
<extend_definition comment="openssh-server removed" definition_ref="oval:ssg:def:132"/>
<criterion comment="sshd disabled in multi-user.target" test_ref="oval:ssg:tst:224"/>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:225" version="1">
<metadata>
<title>Limit Password Reuse</title>
<affected family="unix">
<platform>Red Hat Enterprise Linux 6</platform>
<platform>Red Hat Enterprise Linux 7</platform>
</affected>
<description>The passwords to remember should be set correctly.</description>
<reference source="SDW" ref_id="20131025" ref_url="test_attestation"/>
<reference ref_id="accounts_password_pam_unix_remember" source="ssg"/></metadata>
<criteria>
<criterion comment="remember parameter is set to 0" test_ref="oval:ssg:tst:226"/>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:227" version="1">
<metadata>
<title>Disable Empty Passwords</title>
<affected family="unix">
<platform>Red Hat Enterprise Linux 6</platform>
<platform>Red Hat Enterprise Linux 7</platform>
<platform>Fedora 20</platform>
</affected>
<description>Remote connections from accounts with empty passwords should
be disabled (and dependencies are met)</description>
<reference source="JL" ref_id="20140414" ref_url="test_attestation"/>
<reference ref_id="sshd_disable_empty_passwords" source="ssg"/></metadata>
<criteria comment="SSH is not being used or conditions are met" operator="OR">
<extend_definition comment="sshd service is disabled" definition_ref="oval:ssg:def:142"/>
<criterion comment="Check PermitEmptyPasswords in /etc/ssh/sshd_config" negate="true" test_ref="oval:ssg:tst:228"/>
</criteria>
</definition>
<definition class="inventory" id="oval:ssg:def:104" version="1">
<metadata>
<title>Red Hat Enterprise Linux 6</title>
<affected family="unix">
<platform>Red Hat Enterprise Linux 6</platform>
</affected>
<reference ref_id="cpe:/o:redhat:enterprise_linux:6" source="CPE"/>
<description>The operating system installed on the system is
Red Hat Enterprise Linux 6</description>
<reference ref_id="installed_OS_is_rhel6" source="ssg"/></metadata>
<criteria>
<criterion comment="Installed operating system is part of the unix family" test_ref="oval:ssg:tst:101"/>
<criteria operator="OR">
<criterion comment="Red Hat Enterprise Linux 6 Workstation is installed" test_ref="oval:ssg:tst:105"/>
<criterion comment="Red Hat Enterprise Linux 6 Server is installed" test_ref="oval:ssg:tst:106"/>
</criteria>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:229" version="2">
<metadata>
<title>Set Password ocredit Requirements</title>
<affected family="unix">
<platform>Red Hat Enterprise Linux 7</platform>
<platform>Fedora 20</platform>
</affected>
<description>The password ocredit should meet minimum requirements</description>
<reference source="galford" ref_id="20141010" ref_url="test_attestation"/>
<reference ref_id="accounts_password_pam_ocredit" source="ssg"/></metadata>
<criteria operator="AND" comment="conditions for ocredit are satisfied">
<extend_definition comment="pwquality.so exists in system-auth" definition_ref="oval:ssg:def:130"/>
<criterion comment="pwquality.conf" test_ref="oval:ssg:tst:230"/>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:231" version="3">
<metadata>
<title>Set Password Expiration Parameters</title>
<affected family="unix">
<platform>Red Hat Enterprise Linux 6</platform>
<platform>Red Hat Enterprise Linux 7</platform>
<platform>Fedora 20</platform>
</affected>
<description>The password expiration warning age should be set appropriately.</description>
<reference source="JL" ref_id="RHEL6_20150201" ref_url="test_attestation"/>
<reference source="JL" ref_id="RHEL7_20150201" ref_url="test_attestation"/>
<reference source="JL" ref_id="FEDORA20_20150201" ref_url="test_attestation"/>
<reference ref_id="accounts_password_warn_age_login_defs" source="ssg"/></metadata>
<criteria>
<criterion test_ref="oval:ssg:tst:232"/>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:233" version="1">
<metadata>
<title>Verify that System Executables Have Restrictive Permissions</title>
<affected family="unix">
<platform>Fedora 19</platform>
<platform>Red Hat Enterprise Linux 6</platform>
<platform>Red Hat Enterprise Linux 7</platform>
</affected>
<description>
Checks that binary files under /bin, /sbin, /usr/bin, /usr/sbin,
/usr/local/bin, and /usr/local/sbin, are not group-writable or world-writable.
</description>
<reference ref_id="file_permissions_binary_dirs" source="ssg"/></metadata>
<criteria operator="AND">
<criterion test_ref="oval:ssg:tst:234"/>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:235" version="1">
<metadata>
<title>Set Password maxrepeat Requirements</title>
<affected family="unix">
<platform>Red Hat Enterprise Linux 7</platform>
<platform>Fedora 20</platform>
</affected>
<description>The password maxrepeat should meet minimum
requirements using pam_pwquality</description>
<reference source="galford" ref_id="20141006" ref_url="test_attestation"/>
<reference ref_id="accounts_password_pam_maxrepeat" source="ssg"/></metadata>
<criteria operator="AND" comment="conditions for maxrepeat are satisfied">
<extend_definition comment="pwquality.so exists in system-auth" definition_ref="oval:ssg:def:130"/>
<criterion comment="pwquality.conf" test_ref="oval:ssg:tst:236"/>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:237" version="1">
<metadata>
<title>File grub.cfg Owned By root User</title>
<affected family="unix">
<platform>Red Hat Enterprise Linux 7</platform>
<platform>Fedora 20</platform>
</affected>
<description>The grub.cfg file should be owned by the root user. By default, this file is located at /boot/grub2/grub.cfg or, for EFI systems, at /boot/efi/EFI/redhat/grub.cfg</description>
<reference source="galford" ref_id="20140909" ref_url="test_attestation"/>
<reference ref_id="file_user_owner_grub2_cfg" source="ssg"/></metadata>
<criteria operator="OR">
<criterion test_ref="oval:ssg:tst:238"/>
<criterion test_ref="oval:ssg:tst:239"/>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:240" version="1">
<metadata>
<title>Verify that Shared Library Files Have Restrictive Permissions</title>
<affected family="unix">
<platform>Fedora 19</platform>
<platform>Red Hat Enterprise Linux 6</platform>
<platform>Red Hat Enterprise Linux 7</platform>
</affected>
<description>
Checks that /lib, /lib64, /usr/lib, /usr/lib64, /lib/modules, and
objects therein, are not group-writable or world-writable.
</description>
<reference ref_id="file_permissions_library_dirs" source="ssg"/></metadata>
<criteria operator="AND">
<criterion test_ref="oval:ssg:tst:241"/>
<criterion test_ref="oval:ssg:tst:242"/>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:243" version="1">
<metadata>
<title>Disable root Login via SSH</title>
<affected family="unix">
<platform>Red Hat Enterprise Linux 6</platform>
<platform>Red Hat Enterprise Linux 7</platform>
<platform>Fedora 20</platform>
</affected>
<description>Root login via SSH should be disabled (and dependencies are
met)</description>
<reference source="JL" ref_id="20140414" ref_url="test_attestation"/>
<reference ref_id="sshd_disable_root_login" source="ssg"/></metadata>
<criteria comment="SSH is not being used or conditions are met" operator="OR">
<extend_definition comment="sshd service is disabled" definition_ref="oval:ssg:def:142"/>
<criterion comment="Check PermitRootLogin in /etc/ssh/sshd_config" negate="true" test_ref="oval:ssg:tst:244"/>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:245" version="1">
<metadata>
<title>Restrict Serial Port Root Logins</title>
<affected family="unix">
<platform>Red Hat Enterprise Linux 6</platform>
<platform>Red Hat Enterprise Linux 7</platform>
<platform>Fedora 20</platform>
</affected>
<description>Preventing direct root login to serial port interfaces helps
ensure accountability for actions taken on the system using the root
account.</description>
<reference source="galford" ref_id="20141114" ref_url="test_attestation"/>
<reference ref_id="restrict_serial_port_logins" source="ssg"/></metadata>
<criteria>
<criterion comment="serial ports /etc/securetty" test_ref="oval:ssg:tst:246" negate="true"/>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:247" version="2">
<metadata>
<title>Set Password difok Requirements</title>
<affected family="unix">
<platform>Red Hat Enterprise Linux 7</platform>
<platform>Fedora 20</platform>
</affected>
<description>The password difok should meet minimum requirements</description>
<reference source="galford" ref_id="20141010" ref_url="test_attestation"/>
<reference ref_id="accounts_password_pam_difok" source="ssg"/></metadata>
<criteria operator="AND" comment="conditions for difok are satisfied">
<extend_definition comment="pwquality.so exists in system-auth" definition_ref="oval:ssg:def:130"/>
<criterion comment="pwquality.conf" test_ref="oval:ssg:tst:248"/>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:249" version="1">
<metadata>
<title>Ensure Yum gpgcheck Globally Activated</title>
<affected family="unix">
<platform>Red Hat Enterprise Linux 6</platform>
<platform>Red Hat Enterprise Linux 7</platform>
<platform>Fedora 20</platform>
</affected>
<description>The gpgcheck option should be used to ensure that checking
of an RPM package's signature always occurs prior to its
installation.</description>
<reference source="MED" ref_id="20130807" ref_url="test_attestation"/>
<!-- rhel7: <reference source="SDW" ref_id="20131223" ref_url="test_attestation" /> -->
<reference ref_id="ensure_gpgcheck_globally_activated" source="ssg"/></metadata>
<criteria>
<criterion comment="check value of gpgcheck in /etc/yum.conf" test_ref="oval:ssg:tst:250"/>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:251" version="3">
<metadata>
<title>Set Password Expiration Parameters</title>
<affected family="unix">
<platform>Red Hat Enterprise Linux 6</platform>
<platform>Red Hat Enterprise Linux 7</platform>
<platform>Fedora 20</platform>
</affected>
<description>The password minimum length should be set appropriately.</description>
<reference source="JL" ref_id="RHEL6_20150201" ref_url="test_attestation"/>
<reference source="JL" ref_id="RHEL7_20150201" ref_url="test_attestation"/>
<reference source="JL" ref_id="FEDORA20_20150201" ref_url="test_attestation"/>
<reference ref_id="accounts_password_minlen_login_defs" source="ssg"/></metadata>
<criteria operator="AND">
<criterion test_ref="oval:ssg:tst:252"/>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:253" version="2">
<metadata>
<title>System Login Banner Compliance</title>
<affected family="unix">
<platform>Red Hat Enterprise Linux 6</platform>
<platform>Red Hat Enterprise Linux 7</platform>
</affected>
<description>The system login banner text should be set correctly.</description>
<reference source="MED" ref_id="20130819" ref_url="test_attestation"/>
<reference ref_id="banner_etc_issue" source="ssg"/></metadata>
<criteria>
<criterion comment="/etc/issue is set appropriately" test_ref="oval:ssg:tst:254"/>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:255" version="1">
<metadata>
<title>Disable All GNOME3 Thumbnailers</title>
<affected family="unix">
<platform>Red Hat Enterprise Linux 7</platform>
<platform>Fedora 20</platform>
</affected>
<description>The system's default desktop environment, GNOME3, uses a
number of different thumbnailer programs to generate thumbnails for any
new or modified content in an opened folder. Disable the execution of
these thumbnail applications within GNOME3.</description>
<reference source="galford" ref_id="20140824" ref_url="test_attestation"/>
<reference ref_id="dconf_gnome_disable_thumbnailers" source="ssg"/></metadata>
<criteria operator="OR">
<extend_definition comment="dconf installed" definition_ref="oval:ssg:def:134" negate="true"/>
<criteria comment="Disable Gnome3 Thumbnailers and prevent user from enabling" operator="AND">
<extend_definition comment="dconf user profile exists" definition_ref="oval:ssg:def:145"/>
<criterion comment="Disable thumbnailers in GNOME3" test_ref="oval:ssg:tst:256"/>
<criterion comment="prevent user from changing idle delay" test_ref="oval:ssg:tst:257"/>
</criteria>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:145" version="1">
<metadata>
<title>Implement Local DB for DConf User Profile</title>
<affected family="unix">
<platform>Red Hat Enterprise Linux 7</platform>
<platform>Fedora 20</platform>
</affected>
<description>The DConf User profile should have the local DB configured.</description>
<reference source="galford" ref_id="20140824" ref_url="test_attestation"/>
<reference ref_id="enable_dconf_user_profile" source="ssg"/></metadata>
<criteria>
<criterion comment="dconf user profile exists" test_ref="oval:ssg:tst:258"/>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:259" version="2">
<metadata>
<title>Kernel Runtime Parameter IPv6 Check</title>
<affected family="unix">
<platform>Red Hat Enterprise Linux 7</platform>
<platform>Fedora 20</platform>
</affected>
<description>Disables IPv6 for all network interfaces.</description>
<reference source="galford" ref_id="20141015" ref_url="test_attestation"/>
<reference ref_id="sysctl_kernel_ipv6_disable" source="ssg"/></metadata>
<criteria operator="AND">
<criterion comment="Disable IPv6 runtime check" test_ref="oval:ssg:tst:260"/>
<criterion comment="Disable IPv6 in sysctl.d conf file" test_ref="oval:ssg:tst:261"/>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:262" version="2">
<metadata>
<title>Set Password lcredit Requirements</title>
<affected family="unix">
<platform>Red Hat Enterprise Linux 7</platform>
<platform>Fedora 20</platform>
</affected>
<description>The password lcredit should meet minimum requirements</description>
<reference source="swells" ref_id="20140926" ref_url="test_attestation"/>
<reference ref_id="accounts_password_pam_lcredit" source="ssg"/></metadata>
<criteria operator="AND" comment="conditions for lcredit are satisfied">
<extend_definition comment="pwquality.so exists in system-auth" definition_ref="oval:ssg:def:130"/>
<criterion comment="pwquality.conf" test_ref="oval:ssg:tst:263"/>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:264" version="1">
<metadata>
<title>Set Boot Loader Password</title>
<affected family="unix">
<platform>Red Hat Enterprise Linux 7</platform>
<platform>Fedora 20</platform>
</affected>
<description>The grub2 boot loader should have password protection enabled.</description>
<reference source="galford" ref_id="20140909" ref_url="test_attestation"/>
<reference ref_id="bootloader_password" source="ssg"/></metadata>
<criteria operator="AND">
<criterion comment="make sure a password is defined in /etc/grub2.cfg" test_ref="oval:ssg:tst:265"/>
<criterion comment="make sure a superuser is defined in /etc/grub2.cfg" test_ref="oval:ssg:tst:266"/>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:267" version="1">
<metadata>
<title>All Password Hashes Shadowed</title>
<affected family="unix">
<platform>Red Hat Enterprise Linux 6</platform>
<platform>Red Hat Enterprise Linux 7</platform>
<platform>Fedora 20</platform>
</affected>
<description>All password hashes should be shadowed.</description>
<reference source="swells" ref_id="20130918" ref_url="test_attestation"/>
<reference ref_id="accounts_password_all_shadowed" source="ssg"/></metadata>
<criteria>
<criterion comment="password hashes are shadowed" test_ref="oval:ssg:tst:268"/>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:269" version="1">
<metadata>
<title>Enable GNOME3 Screensaver Idle Activation</title>
<affected family="unix">
<platform>Red Hat Enterprise Linux 7</platform>
<platform>Fedora 20</platform>
</affected>
<description>Idle activation of the screen saver should be enabled.</description>
<reference source="galford" ref_id="20140824" ref_url="test_attestation"/>
<reference ref_id="dconf_gnome_screensaver_idle_activation_enabled" source="ssg"/></metadata>
<criteria operator="OR">
<extend_definition comment="dconf installed" definition_ref="oval:ssg:def:134" negate="true"/>
<criteria comment="check screensaver idle activation and prevent user from changing it" operator="AND">
<extend_definition comment="dconf user profile exists" definition_ref="oval:ssg:def:145"/>
<criterion comment="idle activation has been configured" test_ref="oval:ssg:tst:270"/>
<criterion comment="prevent user from changing idle delay" test_ref="oval:ssg:tst:271"/>
</criteria>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:272" version="1">
<metadata>
<title>Service ntpd Enabled</title>
<affected family="unix">
<platform>Fedora 19</platform>
</affected>
<description>
The ntpd service should be enabled.
</description>
<reference ref_id="service_ntpd_enabled" source="ssg"/></metadata>
<criteria comment="package ntp installed and service ntpd is configured to start" operator="AND">
<extend_definition comment="ntp installed" definition_ref="oval:ssg:def:181"/>
<criterion comment="ntpd multi-user.target" test_ref="oval:ssg:tst:273"/>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:274" version="2">
<metadata>
<title>Write permissions are disabled for group and other in all
directories in Root's Path</title>
<affected family="unix">
<platform>Red Hat Enterprise Linux 6</platform>
<platform>Red Hat Enterprise Linux 7</platform>
<platform>Fedora 20</platform>
</affected>
<description>Check each directory in root's path and make use it does
not grant write permission to group and other</description>
<reference source="JL" ref_id="RHEL6_20141119" ref_url="test_attestation"/>
<reference source="JL" ref_id="RHEL7_20141119" ref_url="test_attestation"/>
<reference source="JL" ref_id="FEDORA20_20141119" ref_url="test_attestation"/>
<reference ref_id="accounts_root_path_dirs_no_write" source="ssg"/></metadata>
<criteria comment="Check that write permission to group and other in root's path is denied">
<criterion comment="Check for write permission to group and other in root's path" test_ref="oval:ssg:tst:275"/>
</criteria>
</definition>
<definition class="inventory" id="oval:ssg:def:107" version="1">
<metadata>
<title>Red Hat Enterprise Linux 7</title>
<affected family="unix">
<platform>Red Hat Enterprise Linux 7</platform>
</affected>
<reference ref_id="cpe:/o:redhat:enterprise_linux:7" source="CPE"/>
<description>The operating system installed on the system is
Red Hat Enterprise Linux 7</description>
<reference ref_id="installed_OS_is_rhel7" source="ssg"/></metadata>
<criteria>
<criterion comment="Installed operating system is part of the unix family" test_ref="oval:ssg:tst:108"/>
<criteria operator="OR">
<criterion comment="Red Hat Enterprise Linux 7 Workstation is installed" test_ref="oval:ssg:tst:109"/>
<criterion comment="Red Hat Enterprise Linux 7 Server is installed" test_ref="oval:ssg:tst:110"/>
</criteria>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:276" version="1">
<metadata>
<title>UID 0 Belongs Only To Root</title>
<affected family="unix">
<platform>Red Hat Enterprise Linux 6</platform>
<platform>Red Hat Enterprise Linux 7</platform>
<platform>Fedora 20</platform>
</affected>
<description>Only the root account should be assigned a user id of 0.</description>
<reference source="MED" ref_id="20130807" ref_url="test_attestation"/>
<!-- Fedora 20: <reference source="JL" ref_id="20140303" ref_url="test_attestation" /> -->
<reference ref_id="accounts_no_uid_except_zero" source="ssg"/></metadata>
<criteria>
<criterion comment="tests that there are no accounts with UID 0 except root in the /etc/passwd file" test_ref="oval:ssg:tst:277"/>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:278" version="1">
<metadata>
<title>File grub.cfg Owned By root Group </title>
<affected family="unix">
<platform>Red Hat Enterprise Linux 7</platform>
<platform>Fedora 20</platform>
</affected>
<description>The grub.cfg file should be owned by the root group. By default, this file is located at /boot/grub2/grub.cfg or, for EFI systems, at /boot/efi/EFI/redhat/grub.cfg</description>
<reference source="galford" ref_id="20140909" ref_url="test_attestation"/>
<reference ref_id="file_group_owner_grub2_cfg" source="ssg"/></metadata>
<criteria operator="OR">
<criterion test_ref="oval:ssg:tst:279"/>
<criterion test_ref="oval:ssg:tst:280"/>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:281" version="1">
<metadata>
<title>Restrict Virtual Console Root Logins</title>
<affected family="unix">
<platform>Red Hat Enterprise Linux 6</platform>
<platform>Red Hat Enterprise Linux 7</platform>
<platform>Fedora 20</platform>
</affected>
<description>Preventing direct root login to virtual console devices
helps ensure accountability for actions taken on the system using the
root account.</description>
<reference source="galford" ref_id="20141114" ref_url="test_attestation"/>
<reference ref_id="securetty_root_login_console_only" source="ssg"/></metadata>
<criteria>
<criterion comment="virtual consoles /etc/securetty" test_ref="oval:ssg:tst:282"/>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:283" version="3">
<metadata>
<title>Set Password Expiration Parameters</title>
<affected family="unix">
<platform>Red Hat Enterprise Linux 6</platform>
<platform>Red Hat Enterprise Linux 7</platform>
<platform>Fedora 20</platform>
</affected>
<description>The minimum password age policy should be set appropriately.</description>
<reference source="JL" ref_id="RHEL6_20150201" ref_url="test_attestation"/>
<reference source="JL" ref_id="RHEL7_20150201" ref_url="test_attestation"/>
<reference source="JL" ref_id="FEDORA20_20150201" ref_url="test_attestation"/>
<reference ref_id="accounts_minimum_age_login_defs" source="ssg"/></metadata>
<criteria comment="The value of PASS_MIN_DAYS should be set appropriately in /etc/login.defs">
<criterion test_ref="oval:ssg:tst:284"/>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:285" version="1">
<metadata>
<title>Set Password dcredit Requirements</title>
<affected family="unix">
<platform>Red Hat Enterprise Linux 7</platform>
<platform>Fedora 20</platform>
</affected>
<description>The password dcredit should meet minimum requirements</description>
<reference source="galford" ref_id="20141010" ref_url="test_attestation"/>
<reference ref_id="accounts_password_pam_dcredit" source="ssg"/></metadata>
<criteria operator="AND" comment="conditions for dcredit are satisfied">
<extend_definition comment="pwquality.so exists in system-auth" definition_ref="oval:ssg:def:130"/>
<criterion comment="pwquality.conf" test_ref="oval:ssg:tst:286"/>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:287" version="1">
<metadata>
<title>Enable GNOME3 Screensaver Lock After Idle Period</title>
<affected family="unix">
<platform>Red Hat Enterprise Linux 7</platform>
<platform>Fedora 20</platform>
</affected>
<description>Idle activation of the screen lock should be enabled.</description>
<reference source="galford" ref_id="20140824" ref_url="test_attestation"/>
<reference ref_id="dconf_gnome_screensaver_lock_enabled" source="ssg"/></metadata>
<criteria operator="OR">
<extend_definition comment="dconf installed" definition_ref="oval:ssg:def:134" negate="true"/>
<criteria comment="Enable screensaver lock and prevent user from changing it" operator="AND">
<extend_definition comment="dconf user profile exists" definition_ref="oval:ssg:def:145"/>
<criterion comment="screensaver lock is enabled" test_ref="oval:ssg:tst:288"/>
<criterion comment="screensaver lock prevent user from changing" test_ref="oval:ssg:tst:289"/>
<criterion comment="screensaver lock delay is set correctly" test_ref="oval:ssg:tst:290"/>
<criterion comment="prevent user from changing screensaver lock delay" test_ref="oval:ssg:tst:291"/>
<criterion comment="screensaver lock delay is set correctly" test_ref="oval:ssg:tst:290"/>
<criterion comment="prevent user from changing screensaver lock delay" test_ref="oval:ssg:tst:291"/>
</criteria>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:292" version="1">
<metadata>
<title>Banner for FTP Users</title>
<affected family="unix">
<platform>Red Hat Enterprise Linux 6</platform>
<platform>Red Hat Enterprise Linux 7</platform>
<platform>Fedora 20</platform>
</affected>
<description>This setting will cause the system greeting banner to be
used for FTP connections as well.</description>
<reference source="galford" ref_id="20140812" ref_url="test_attestation"/>
<reference ref_id="ftp_present_banner" source="ssg"/></metadata>
<criteria operator="OR">
<extend_definition comment="vsftpd package is not installed" negate="true" definition_ref="oval:ssg:def:168"/>
<criterion comment="Banner for FTP Users" test_ref="oval:ssg:tst:293"/>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:294" version="1">
<metadata>
<title>Configure the GNOME3 GUI Screen locking</title>
<affected family="unix">
<platform>Red Hat Enterprise Linux 7</platform>
<platform>Fedora 20</platform>
</affected>
<description>The allowed period of inactivity before the screensaver is activated.</description>
<reference source="galford" ref_id="20140824" ref_url="test_attestation"/>
<reference ref_id="dconf_gnome_screensaver_idle_delay" source="ssg"/></metadata>
<criteria operator="OR">
<extend_definition comment="dconf installed" definition_ref="oval:ssg:def:134" negate="true"/>
<criteria comment="check screensaver idle delay and prevent user from changing it" operator="AND">
<extend_definition comment="dconf user profile exists" definition_ref="oval:ssg:def:145"/>
<criterion comment="idle delay has been configured" test_ref="oval:ssg:tst:295"/>
<criterion comment="prevent user from changing idle delay" test_ref="oval:ssg:tst:296"/>
<criterion comment="idle delay is set correctly" test_ref="oval:ssg:tst:297"/>
</criteria>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:298" version="1">
<metadata>
<title>Require Authentication for Single-User Mode</title>
<affected family="unix">
<platform>Red Hat Enterprise Linux 7</platform>
<platform>Fedora 20</platform>
</affected>
<description>The requirement for a password to boot into single-user mode
should be configured correctly.</description>
<reference source="galford" ref_id="20140926" ref_url="test_attestation"/>
<reference ref_id="require_singleuser_auth" source="ssg"/></metadata>
<criteria operator="AND">
<criterion comment="Conditions are satisfied" test_ref="oval:ssg:tst:299"/>
<criterion test_ref="oval:ssg:tst:300"/>
<criterion test_ref="oval:ssg:tst:301" negate="true"/>
<criterion test_ref="oval:ssg:tst:302" negate="true"/>
</criteria>
</definition>
</definitions>
<tests>
<ind:textfilecontent54_test check="all" check_existence="all_exist" comment="Ensure at least one NTP server is set" id="oval:ssg:tst:126" version="1">
<ind:object object_ref="oval:ssg:obj:303"/>
</ind:textfilecontent54_test>
<ind:textfilecontent54_test check="all" check_existence="none_exist" comment="make sure nullok is not used in /etc/pam.d/system-auth" id="oval:ssg:tst:128" version="1">
<ind:object object_ref="oval:ssg:obj:304"/>
</ind:textfilecontent54_test>
<ind:textfilecontent54_test check="all" comment="check the configuration of /etc/security/pwquality.conf" id="oval:ssg:tst:131" version="1">
<ind:object object_ref="oval:ssg:obj:305"/>
<ind:state state_ref="oval:ssg:ste:306"/>
</ind:textfilecontent54_test>
<ind:family_test check="all" check_existence="at_least_one_exists" comment="installed OS part of unix family" id="oval:ssg:tst:101" version="1">
<ind:object object_ref="oval:ssg:obj:111"/>
<ind:state state_ref="oval:ssg:ste:112"/>
</ind:family_test>
<linux:rpminfo_test check="all" check_existence="only_one_exists" comment="fedora-release is version 19" id="oval:ssg:tst:102" version="1">
<linux:object object_ref="oval:ssg:obj:113"/>
<linux:state state_ref="oval:ssg:ste:114"/>
</linux:rpminfo_test>
<linux:rpminfo_test check="all" check_existence="none_exist" id="oval:ssg:tst:133" version="1" comment="package openssh-server is removed">
<linux:object object_ref="oval:ssg:obj:307"/>
</linux:rpminfo_test>
<linux:rpminfo_test check="all" check_existence="all_exist" id="oval:ssg:tst:135" version="1" comment="package dconf is installed">
<linux:object object_ref="oval:ssg:obj:308"/>
</linux:rpminfo_test>
<ind:variable_test id="oval:ssg:tst:137" check="all" comment="The value of PASS_MAX_DAYS should be set appropriately in /etc/login.defs" version="1">
<ind:object object_ref="oval:ssg:obj:309"/>
<ind:state state_ref="oval:ssg:ste:310"/>
</ind:variable_test>
<unix:file_test check="all" check_existence="none_exist" comment="binary directories uid root" id="oval:ssg:tst:139" version="1">
<unix:object object_ref="oval:ssg:obj:311"/>
</unix:file_test>
<unix:file_test check="all" check_existence="none_exist" comment="binary files uid root" id="oval:ssg:tst:140" version="1">
<unix:object object_ref="oval:ssg:obj:312"/>
</unix:file_test>
<ind:textfilecontent54_test check="all" check_existence="all_exist" comment="timeout is configured" id="oval:ssg:tst:143" version="1">
<ind:object object_ref="oval:ssg:obj:313"/>
<ind:state state_ref="oval:ssg:ste:314"/>
<ind:state state_ref="oval:ssg:ste:315"/>
</ind:textfilecontent54_test>
<ind:textfilecontent54_test check="all" check_existence="all_exist" comment="GUI banner is enabled" id="oval:ssg:tst:146" version="1">
<ind:object object_ref="oval:ssg:obj:316"/>
</ind:textfilecontent54_test>
<ind:textfilecontent54_test check="all" check_existence="all_exist" comment="GUI banner cannot be changed by user" id="oval:ssg:tst:147" version="1">
<ind:object object_ref="oval:ssg:obj:317"/>
</ind:textfilecontent54_test>
<unix:file_test check="all" check_existence="none_exist" comment="library directories uid root" id="oval:ssg:tst:149" version="1">
<unix:object object_ref="oval:ssg:obj:318"/>
</unix:file_test>
<unix:file_test check="all" check_existence="none_exist" comment="library files uid root" id="oval:ssg:tst:150" version="1">
<unix:object object_ref="oval:ssg:obj:319"/>
</unix:file_test>
<ind:textfilecontent54_test check="all" check_existence="all_exist" comment="Tests whether prelinking is disabled" id="oval:ssg:tst:152" version="1">
<ind:object object_ref="oval:ssg:obj:320"/>
</ind:textfilecontent54_test>
<ind:variable_test id="oval:ssg:tst:154" check="all" comment="The value of ENCRYPT_METHOD should be set appropriately in /etc/login.defs" version="1">
<ind:object object_ref="oval:ssg:obj:321"/>
<ind:state state_ref="oval:ssg:ste:322"/>
</ind:variable_test>
<unix:file_test check="all" check_existence="at_least_one_exists" comment="home directories" id="oval:ssg:tst:156" version="1">
<unix:object object_ref="oval:ssg:obj:323"/>
<unix:state state_ref="oval:ssg:ste:324"/>
</unix:file_test>
<ind:textfilecontent54_test id="oval:ssg:tst:158" check="all" check_existence="all_exist" comment="Check pam_faillock.so preauth silent present in /etc/pam.d/system-auth" version="1">
<ind:object object_ref="oval:ssg:obj:325"/>
<ind:state state_ref="oval:ssg:ste:326"/>
</ind:textfilecontent54_test>
<ind:textfilecontent54_test id="oval:ssg:tst:159" check="all" check_existence="all_exist" comment="Check maximum failed login attempts allowed in /etc/pam.d/system-auth (authfail)" version="1">
<ind:object object_ref="oval:ssg:obj:327"/>
<ind:state state_ref="oval:ssg:ste:326"/>
</ind:textfilecontent54_test>
<ind:textfilecontent54_test id="oval:ssg:tst:160" check="all" check_existence="all_exist" comment="Check if pam_faillock_so is called in account phase of /etc/pam.d/system-auth" version="1">
<ind:object object_ref="oval:ssg:obj:328"/>
</ind:textfilecontent54_test>
<ind:textfilecontent54_test id="oval:ssg:tst:161" check="all" check_existence="all_exist" comment="Check pam_faillock.so preauth silent present in /etc/pam.d/password-auth" version="1">
<ind:object object_ref="oval:ssg:obj:329"/>
<ind:state state_ref="oval:ssg:ste:326"/>
</ind:textfilecontent54_test>
<ind:textfilecontent54_test id="oval:ssg:tst:162" check="all" check_existence="all_exist" comment="Check maximum failed login attempts allowed in /etc/pam.d/password-auth (authfail)" version="1">
<ind:object object_ref="oval:ssg:obj:330"/>
<ind:state state_ref="oval:ssg:ste:326"/>
</ind:textfilecontent54_test>
<ind:textfilecontent54_test id="oval:ssg:tst:163" check="all" check_existence="all_exist" comment="Check if pam_faillock_so is called in account phase of /etc/pam.d/password-auth" version="1">
<ind:object object_ref="oval:ssg:obj:331"/>
</ind:textfilecontent54_test>
<ind:textfilecontent54_test check="all" check_existence="none_exist" comment="Check snmpd configuration" id="oval:ssg:tst:166" version="1">
<ind:object object_ref="oval:ssg:obj:332"/>
</ind:textfilecontent54_test>
<ind:textfilecontent54_test check="all" check_existence="all_exist" comment="log ftp transactions" id="oval:ssg:tst:169" version="1">
<ind:object object_ref="oval:ssg:obj:333"/>
</ind:textfilecontent54_test>
<ind:textfilecontent54_test check="all" check_existence="all_exist" comment="log ftp transactions" id="oval:ssg:tst:170" version="1">
<ind:object object_ref="oval:ssg:obj:334"/>
</ind:textfilecontent54_test>
<ind:textfilecontent54_test check="all" check_existence="all_exist" comment="log ftp transactions" id="oval:ssg:tst:171" version="1">
<ind:object object_ref="oval:ssg:obj:335"/>
</ind:textfilecontent54_test>
<ind:textfilecontent54_test check="all" check_existence="all_exist" comment="screensaver mode is blank" id="oval:ssg:tst:173" version="1">
<ind:object object_ref="oval:ssg:obj:336"/>
</ind:textfilecontent54_test>
<ind:textfilecontent54_test check="all" check_existence="all_exist" comment="blank screensaver cannot be changed by user" id="oval:ssg:tst:174" version="1">
<ind:object object_ref="oval:ssg:obj:337"/>
</ind:textfilecontent54_test>
<unix:sysctl_test check="all" check_existence="all_exist" comment="kernel runtime parameter kernel.exec-shield set to 1" id="oval:ssg:tst:176" version="1">
<unix:object object_ref="oval:ssg:obj:338"/>
<unix:state state_ref="oval:ssg:ste:339"/>
</unix:sysctl_test>
<ind:textfilecontent54_test check="all" check_existence="all_exist" comment="kernel.exec-shield static configuration" id="oval:ssg:tst:177" version="1">
<ind:object object_ref="oval:ssg:obj:340"/>
</ind:textfilecontent54_test>
<ind:textfilecontent54_test check="all" check_existence="none_exist" comment="NX is disabled" id="oval:ssg:tst:180" version="1">
<ind:object object_ref="oval:ssg:obj:341"/>
</ind:textfilecontent54_test>
<linux:rpminfo_test check="all" check_existence="all_exist" id="oval:ssg:tst:182" version="1" comment="package ntp is installed">
<linux:object object_ref="oval:ssg:obj:342"/>
</linux:rpminfo_test>
<linux:rpminfo_test check="all" check_existence="none_exist" id="oval:ssg:tst:183" version="1" comment="package net-snmp is removed">
<linux:object object_ref="oval:ssg:obj:343"/>
</linux:rpminfo_test>
<unix:uname_test check="all" comment="64 bit architecture" id="oval:ssg:tst:184" version="1">
<unix:object object_ref="oval:ssg:obj:344"/>
<unix:state state_ref="oval:ssg:ste:345"/>
</unix:uname_test>
<ind:textfilecontent54_test check="all" comment="check the configuration of /etc/pam.d/system-auth" id="oval:ssg:tst:186" version="1">
<ind:object object_ref="oval:ssg:obj:346"/>
<ind:state state_ref="oval:ssg:ste:347"/>
</ind:textfilecontent54_test>
<ind:textfilecontent54_test check="all" comment="check the configuration of /etc/pam.d/system-auth" id="oval:ssg:tst:187" version="1">
<ind:object object_ref="oval:ssg:obj:348"/>
<ind:state state_ref="oval:ssg:ste:347"/>
</ind:textfilecontent54_test>
<linux:rpminfo_test check="all" check_existence="all_exist" id="oval:ssg:tst:189" version="1" comment="AntiVirus package is installed">
<linux:object object_ref="oval:ssg:obj:349"/>
</linux:rpminfo_test>
<ind:textfilecontent54_test check="all" comment="check the configuration of /etc/security/pwquality.conf" id="oval:ssg:tst:191" version="1">
<ind:object object_ref="oval:ssg:obj:350"/>
<ind:state state_ref="oval:ssg:ste:351"/>
</ind:textfilecontent54_test>
<unix:file_test check="all" check_existence="all_exist" comment="Testing file permissions" id="oval:ssg:tst:193" version="1">
<unix:object object_ref="oval:ssg:obj:352"/>
<unix:state state_ref="oval:ssg:ste:353"/>
</unix:file_test>
<unix:file_test check="all" check_existence="all_exist" comment="/boot/efi/EFI/redhat/grub.cfg owned by root" id="oval:ssg:tst:194" version="1">
<unix:object object_ref="oval:ssg:obj:354"/>
<unix:state state_ref="oval:ssg:ste:353"/>
</unix:file_test>
<ind:textfilecontent54_test check="all" check_existence="none_exist" comment="check for existence of gpgcheck=0 in /etc/yum.repos.d/ files" id="oval:ssg:tst:196" version="1">
<ind:object object_ref="oval:ssg:obj:355"/>
</ind:textfilecontent54_test>
<ind:textfilecontent54_test check="all" check_existence="all_exist" comment="GUI banner cannot be changed by user" id="oval:ssg:tst:198" version="1">
<ind:object object_ref="oval:ssg:obj:356"/>
</ind:textfilecontent54_test>
<ind:textfilecontent54_test check="all" check_existence="all_exist" comment="login banner text is correctly set" id="oval:ssg:tst:199" version="1">
<ind:object object_ref="oval:ssg:obj:357"/>
<ind:state state_ref="oval:ssg:ste:358"/>
</ind:textfilecontent54_test>
<unix:file_test check="all" check_existence="at_least_one_exists" comment="look for .netrc in /home" id="oval:ssg:tst:201" version="1">
<unix:object object_ref="oval:ssg:obj:359"/>
</unix:file_test>
<unix:uname_test check="all" comment="32 bit architecture" id="oval:ssg:tst:202" version="1">
<unix:object object_ref="oval:ssg:obj:360"/>
<unix:state state_ref="oval:ssg:ste:361"/>
</unix:uname_test>
<ind:textfilecontent54_test check="all" check_existence="at_least_one_exists" comment="Ensure at least one NTP server is set" id="oval:ssg:tst:204" version="1">
<ind:object object_ref="oval:ssg:obj:362"/>
</ind:textfilecontent54_test>
<ind:textfilecontent54_test check="all" check_existence="all_exist" comment="Tests the value of the ClientAliveCountMax setting in the /etc/ssh/sshd_config file" id="oval:ssg:tst:206" version="1">
<ind:object object_ref="oval:ssg:obj:363"/>
<ind:state state_ref="oval:ssg:ste:364"/>
</ind:textfilecontent54_test>
<ind:textfilecontent54_test check="all" check_existence="none_exist" comment="tests for the presence of login shells (not /sbin/nologin) for system accounts in /etc/passwd file" id="oval:ssg:tst:208" version="1">
<ind:object object_ref="oval:ssg:obj:365"/>
</ind:textfilecontent54_test>
<linux:rpminfo_test check="all" check_existence="all_exist" id="oval:ssg:tst:209" version="1" comment="package vsftpd is installed">
<linux:object object_ref="oval:ssg:obj:366"/>
</linux:rpminfo_test>
<ind:textfilecontent54_test check="all" check_existence="none_exist" comment="Tests the value of the insecure locks in /etc/exports" id="oval:ssg:tst:211" version="1">
<ind:object object_ref="oval:ssg:obj:367"/>
</ind:textfilecontent54_test>
<ind:textfilecontent54_test check="all" check_existence="none_exist" comment="Check snmpd configuration" id="oval:ssg:tst:213" version="1">
<ind:object object_ref="oval:ssg:obj:368"/>
</ind:textfilecontent54_test>
<ind:textfilecontent54_test check="all" comment="check the configuration of /etc/security/pwquality.conf" id="oval:ssg:tst:215" version="1">
<ind:object object_ref="oval:ssg:obj:369"/>
<ind:state state_ref="oval:ssg:ste:370"/>
</ind:textfilecontent54_test>
<ind:textfilecontent54_test check="all" comment="check the configuration of /etc/pam.d/system-auth" id="oval:ssg:tst:216" version="1">
<ind:object object_ref="oval:ssg:obj:371"/>
</ind:textfilecontent54_test>
<ind:textfilecontent54_test check="all" check_existence="all_exist" comment="Disable automount in GNOME3" id="oval:ssg:tst:218" version="1">
<ind:object object_ref="oval:ssg:obj:372"/>
</ind:textfilecontent54_test>
<ind:textfilecontent54_test check="all" check_existence="all_exist" comment="Prevent user from changing automount setting" id="oval:ssg:tst:221" version="1">
<ind:object object_ref="oval:ssg:obj:373"/>
</ind:textfilecontent54_test>
<ind:textfilecontent54_test check="all" check_existence="all_exist" comment="Disable automount-open in GNOME" id="oval:ssg:tst:219" version="1">
<ind:object object_ref="oval:ssg:obj:374"/>
</ind:textfilecontent54_test>
<ind:textfilecontent54_test check="all" check_existence="all_exist" comment="Prevent user from changing automount-open setting" id="oval:ssg:tst:222" version="1">
<ind:object object_ref="oval:ssg:obj:375"/>
</ind:textfilecontent54_test>
<ind:textfilecontent54_test check="all" check_existence="all_exist" comment="Disable autorun in GNOME" id="oval:ssg:tst:220" version="1">
<ind:object object_ref="oval:ssg:obj:376"/>
</ind:textfilecontent54_test>
<ind:textfilecontent54_test check="all" check_existence="all_exist" comment="Prevent user from changing autorun setting" id="oval:ssg:tst:223" version="1">
<ind:object object_ref="oval:ssg:obj:377"/>
</ind:textfilecontent54_test>
<unix:file_test check="all" check_existence="none_exist" comment="look for sshd.service in /etc/systemd/system/multi-user.target.wants" id="oval:ssg:tst:224" version="1">
<unix:object object_ref="oval:ssg:obj:378"/>
</unix:file_test>
<ind:textfilecontent54_test check="all" check_existence="all_exist" comment="remember is set in /etc/pam.d/system-auth" id="oval:ssg:tst:226" version="1">
<ind:object object_ref="oval:ssg:obj:379"/>
<ind:state state_ref="oval:ssg:ste:380"/>
</ind:textfilecontent54_test>
<ind:textfilecontent54_test check="all" check_existence="none_exist" comment="Tests the value of the PermitEmptyPasswords[\s]*(<:nocomment:>*) setting in the /etc/ssh/sshd_config file" id="oval:ssg:tst:228" version="1">
<ind:object object_ref="oval:ssg:obj:381"/>
</ind:textfilecontent54_test>
<linux:rpminfo_test check="all" check_existence="at_least_one_exists" comment="redhat-release-workstation is version 6" id="oval:ssg:tst:105" version="1">
<linux:object object_ref="oval:ssg:obj:115"/>
<linux:state state_ref="oval:ssg:ste:116"/>
</linux:rpminfo_test>
<linux:rpminfo_test check="all" check_existence="at_least_one_exists" comment="redhat-release-server is version 6" id="oval:ssg:tst:106" version="1">
<linux:object object_ref="oval:ssg:obj:117"/>
<linux:state state_ref="oval:ssg:ste:118"/>
</linux:rpminfo_test>
<ind:textfilecontent54_test check="all" comment="check the configuration of /etc/security/pwquality.conf" id="oval:ssg:tst:230" version="1">
<ind:object object_ref="oval:ssg:obj:382"/>
<ind:state state_ref="oval:ssg:ste:383"/>
</ind:textfilecontent54_test>
<ind:variable_test id="oval:ssg:tst:232" check="all" comment="The value of PASS_WARN_AGE should be set appropriately in /etc/login.defs" version="1">
<ind:object object_ref="oval:ssg:obj:384"/>
<ind:state state_ref="oval:ssg:ste:385"/>
</ind:variable_test>
<unix:file_test check="all" check_existence="none_exist" comment="binary files go-w" id="oval:ssg:tst:234" version="1">
<unix:object object_ref="oval:ssg:obj:386"/>
</unix:file_test>
<ind:textfilecontent54_test check="all" comment="check the configuration of /etc/security/pwquality.conf" id="oval:ssg:tst:236" version="1">
<ind:object object_ref="oval:ssg:obj:387"/>
<ind:state state_ref="oval:ssg:ste:388"/>
</ind:textfilecontent54_test>
<unix:file_test check="all" check_existence="all_exist" comment="/boot/grub2/grub.cfg owned by root" id="oval:ssg:tst:238" version="1">
<unix:object object_ref="oval:ssg:obj:389"/>
<unix:state state_ref="oval:ssg:ste:390"/>
</unix:file_test>
<unix:file_test check="all" check_existence="all_exist" comment="/boot/efi/EFI/redhat/grub.cfg owned by root" id="oval:ssg:tst:239" version="1">
<unix:object object_ref="oval:ssg:obj:391"/>
<unix:state state_ref="oval:ssg:ste:390"/>
</unix:file_test>
<unix:file_test check="all" check_existence="none_exist" comment="library directories go-w" id="oval:ssg:tst:241" version="1">
<unix:object object_ref="oval:ssg:obj:392"/>
</unix:file_test>
<unix:file_test check="all" check_existence="none_exist" comment="library files go-w" id="oval:ssg:tst:242" version="1">
<unix:object object_ref="oval:ssg:obj:393"/>
</unix:file_test>
<ind:textfilecontent54_test check="all" check_existence="none_exist" comment="Tests the value of the PermitRootLogin[\s]*(<:nocomment:>*) setting in the /etc/ssh/sshd_config file" id="oval:ssg:tst:244" version="1">
<ind:object object_ref="oval:ssg:obj:394"/>
</ind:textfilecontent54_test>
<ind:textfilecontent54_test check="all" check_existence="all_exist" comment="serial ports /etc/securetty" id="oval:ssg:tst:246" version="1">
<ind:object object_ref="oval:ssg:obj:395"/>
</ind:textfilecontent54_test>
<ind:textfilecontent54_test check="all" comment="check the configuration of /etc/security/pwquality.conf" id="oval:ssg:tst:248" version="1">
<ind:object object_ref="oval:ssg:obj:396"/>
<ind:state state_ref="oval:ssg:ste:397"/>
</ind:textfilecontent54_test>
<ind:textfilecontent54_test check="all" check_existence="all_exist" comment="check value of gpgcheck in /etc/yum.conf" id="oval:ssg:tst:250" version="1">
<ind:object object_ref="oval:ssg:obj:398"/>
</ind:textfilecontent54_test>
<ind:variable_test id="oval:ssg:tst:252" check="all" comment="The value of PASS_MIN_LEN should be set appropriately in /etc/login.defs" version="1">
<ind:object object_ref="oval:ssg:obj:399"/>
<ind:state state_ref="oval:ssg:ste:400"/>
</ind:variable_test>
<ind:textfilecontent54_test check="all" check_existence="all_exist" comment="correct banner in /etc/issue" id="oval:ssg:tst:254" version="1">
<ind:object object_ref="oval:ssg:obj:401"/>
</ind:textfilecontent54_test>
<ind:textfilecontent54_test check="all" check_existence="all_exist" comment="Disable thumbnailers in GNOME3" id="oval:ssg:tst:256" version="1">
<ind:object object_ref="oval:ssg:obj:402"/>
</ind:textfilecontent54_test>
<ind:textfilecontent54_test check="all" check_existence="all_exist" comment="user cannot enable thumbnailers " id="oval:ssg:tst:257" version="1">
<ind:object object_ref="oval:ssg:obj:403"/>
</ind:textfilecontent54_test>
<ind:textfilecontent54_test check="all" check_existence="all_exist" comment="dconf user profile exists" id="oval:ssg:tst:258" version="1">
<ind:object object_ref="oval:ssg:obj:404"/>
</ind:textfilecontent54_test>
<unix:sysctl_test check="all" check_existence="all_exist" comment="Disable IPv6 runtime check" id="oval:ssg:tst:260" version="1">
<unix:object object_ref="oval:ssg:obj:405"/>
<unix:state state_ref="oval:ssg:ste:406"/>
</unix:sysctl_test>
<ind:textfilecontent54_test check="all" check_existence="all_exist" comment="Disable IPv6 in sysctl.d conf file" id="oval:ssg:tst:261" version="1">
<ind:object object_ref="oval:ssg:obj:407"/>
</ind:textfilecontent54_test>
<ind:textfilecontent54_test check="all" comment="check the configuration of /etc/security/pwquality.conf" id="oval:ssg:tst:263" version="1">
<ind:object object_ref="oval:ssg:obj:408"/>
<ind:state state_ref="oval:ssg:ste:409"/>
</ind:textfilecontent54_test>
<ind:textfilecontent54_test check="all" check_existence="all_exist" comment="superuser is defined in /etc/grub2.cfg files. Superuser is not root, admin, or administrator" id="oval:ssg:tst:266" version="1">
<ind:object object_ref="oval:ssg:obj:410"/>
</ind:textfilecontent54_test>
<ind:textfilecontent54_test check="all" check_existence="all_exist" comment="make sure a password is defined in /etc/grub2.cfg" id="oval:ssg:tst:265" version="1">
<ind:object object_ref="oval:ssg:obj:411"/>
</ind:textfilecontent54_test>
<unix:password_test check="all" comment="password hashes are shadowed" id="oval:ssg:tst:268" version="1">
<unix:object object_ref="oval:ssg:obj:412"/>
<unix:state state_ref="oval:ssg:ste:413"/>
</unix:password_test>
<ind:textfilecontent54_test check="all" check_existence="all_exist" comment="idle delay is configured" id="oval:ssg:tst:270" version="1">
<ind:object object_ref="oval:ssg:obj:414"/>
</ind:textfilecontent54_test>
<ind:textfilecontent54_test check="all" check_existence="all_exist" comment="user cannot change idle_activation_enabled" id="oval:ssg:tst:271" version="1">
<ind:object object_ref="oval:ssg:obj:415"/>
</ind:textfilecontent54_test>
<unix:file_test check="all" check_existence="at_least_one_exists" comment="look for ntpd.service in /etc/systemd/system/multi-user.target.wants" id="oval:ssg:tst:273" version="1">
<unix:object object_ref="oval:ssg:obj:416"/>
</unix:file_test>
<unix:file_test check="all" check_existence="none_exist" comment="Check if there aren't directories in root's path having write permission set for group or other" id="oval:ssg:tst:275" version="1">
<unix:object object_ref="oval:ssg:obj:417"/>
</unix:file_test>
<ind:family_test check="all" check_existence="at_least_one_exists" comment="installed OS part of unix family" id="oval:ssg:tst:108" version="1">
<ind:object object_ref="oval:ssg:obj:119"/>
<ind:state state_ref="oval:ssg:ste:120"/>
</ind:family_test>
<linux:rpminfo_test check="all" check_existence="at_least_one_exists" comment="redhat-release-workstation is version 7" id="oval:ssg:tst:109" version="1">
<linux:object object_ref="oval:ssg:obj:121"/>
<linux:state state_ref="oval:ssg:ste:122"/>
</linux:rpminfo_test>
<linux:rpminfo_test check="all" check_existence="at_least_one_exists" comment="redhat-release-server is version 7" id="oval:ssg:tst:110" version="1">
<linux:object object_ref="oval:ssg:obj:123"/>
<linux:state state_ref="oval:ssg:ste:124"/>
</linux:rpminfo_test>
<ind:textfilecontent54_test check="all" check_existence="none_exist" comment="test that there are no accounts with UID 0 except root in the /etc/passwd file" id="oval:ssg:tst:277" version="1">
<ind:object object_ref="oval:ssg:obj:418"/>
</ind:textfilecontent54_test>
<unix:file_test check="all" check_existence="all_exist" comment="/boot/grub2/grub.cfg owned by root" id="oval:ssg:tst:279" version="1">
<unix:object object_ref="oval:ssg:obj:419"/>
<unix:state state_ref="oval:ssg:ste:420"/>
</unix:file_test>
<unix:file_test check="all" check_existence="all_exist" comment="/boot/efi/EFI/redhat/grub.cfg owned by root" id="oval:ssg:tst:280" version="1">
<unix:object object_ref="oval:ssg:obj:421"/>
<unix:state state_ref="oval:ssg:ste:420"/>
</unix:file_test>
<ind:textfilecontent54_test check="all" check_existence="none_exist" comment="virtual consoles /etc/securetty" id="oval:ssg:tst:282" version="1">
<ind:object object_ref="oval:ssg:obj:422"/>
</ind:textfilecontent54_test>
<ind:variable_test id="oval:ssg:tst:284" check="all" comment="The value of PASS_MIN_DAYS should be set appropriately in /etc/login.defs" version="1">
<ind:object object_ref="oval:ssg:obj:423"/>
<ind:state state_ref="oval:ssg:ste:424"/>
</ind:variable_test>
<ind:textfilecontent54_test check="all" comment="check the configuration of /etc/security/pwquality.conf" id="oval:ssg:tst:286" version="1">
<ind:object object_ref="oval:ssg:obj:425"/>
<ind:state state_ref="oval:ssg:ste:426"/>
</ind:textfilecontent54_test>
<ind:textfilecontent54_test check="all" check_existence="all_exist" comment="screensaver lock is enabled" id="oval:ssg:tst:288" version="1">
<ind:object object_ref="oval:ssg:obj:427"/>
</ind:textfilecontent54_test>
<ind:textfilecontent54_test check="all" check_existence="all_exist" comment="screensaver lock cannot be changed by user" id="oval:ssg:tst:289" version="1">
<ind:object object_ref="oval:ssg:obj:428"/>
</ind:textfilecontent54_test>
<ind:textfilecontent54_test check="all" check_existence="all_exist" comment="screensaver lock is set correctly" id="oval:ssg:tst:290" version="1">
<ind:object object_ref="oval:ssg:obj:429"/>
</ind:textfilecontent54_test>
<ind:textfilecontent54_test check="all" check_existence="all_exist" comment="screensaver lock delay cannot be changed by user" id="oval:ssg:tst:291" version="1">
<ind:object object_ref="oval:ssg:obj:430"/>
</ind:textfilecontent54_test>
<ind:textfilecontent54_test check="all" check_existence="all_exist" comment="Banner for FTP Users" id="oval:ssg:tst:293" version="1">
<ind:object object_ref="oval:ssg:obj:431"/>
</ind:textfilecontent54_test>
<ind:textfilecontent54_test check="all" check_existence="all_exist" comment="screensaver idle delay is configured" id="oval:ssg:tst:295" version="1">
<ind:object object_ref="oval:ssg:obj:432"/>
</ind:textfilecontent54_test>
<ind:textfilecontent54_test check="all" check_existence="all_exist" comment="user cannot change screensaver idle delay" id="oval:ssg:tst:296" version="1">
<ind:object object_ref="oval:ssg:obj:433"/>
</ind:textfilecontent54_test>
<ind:textfilecontent54_test check="all" check_existence="all_exist" comment="screensaver idle delay setting is correct" id="oval:ssg:tst:297" version="1">
<ind:object object_ref="oval:ssg:obj:434"/>
<ind:state state_ref="oval:ssg:ste:435"/>
</ind:textfilecontent54_test>
<ind:textfilecontent54_test check="all" check_existence="all_exist" comment="Tests that /sbin/sulogin was not removed from the default systemd rescue.service to ensure that a password must be entered to access single user mode" id="oval:ssg:tst:299" version="1">
<ind:object object_ref="oval:ssg:obj:436"/>
</ind:textfilecontent54_test>
<ind:textfilecontent54_test check="all" check_existence="all_exist" comment="Tests that the systemd rescue.service is in the runlevel1.target" id="oval:ssg:tst:300" version="1">
<ind:object object_ref="oval:ssg:obj:437"/>
</ind:textfilecontent54_test>
<unix:file_test check="all" check_existence="at_least_one_exists" comment="look for rescue.service in /etc/systemd/system" id="oval:ssg:tst:302" version="1">
<unix:object object_ref="oval:ssg:obj:438"/>
</unix:file_test>
<unix:file_test check="all" check_existence="at_least_one_exists" comment="look for runlevel1.target in /etc/systemd/system" id="oval:ssg:tst:301" version="1">
<unix:object object_ref="oval:ssg:obj:439"/>
</unix:file_test>
</tests>
<objects>
<ind:textfilecontent54_object comment="Ensure more than one NTP server is set" id="oval:ssg:obj:303" version="1">
<ind:filepath>/etc/ntp.conf</ind:filepath>
<ind:pattern operation="pattern match">^([\s]*server[\s]+.+$){2,}$</ind:pattern>
<ind:instance datatype="int">1</ind:instance>
</ind:textfilecontent54_object>
<ind:textfilecontent54_object id="oval:ssg:obj:304" version="1">
<ind:filepath>/etc/pam.d/system-auth</ind:filepath>
<ind:pattern operation="pattern match">\s*nullok\s*</ind:pattern>
<ind:instance datatype="int">1</ind:instance>
</ind:textfilecontent54_object>
<ind:textfilecontent54_object id="oval:ssg:obj:305" version="1">
<ind:filepath>/etc/security/pwquality.conf</ind:filepath>
<ind:pattern operation="pattern match">^minclass[\s]*=[\s]*(-?\d+)(?:[\s]|$)</ind:pattern>
<ind:instance datatype="int" operation="less than or equal">1</ind:instance>
</ind:textfilecontent54_object>
<ind:family_object id="oval:ssg:obj:111" version="1"/>
<linux:rpminfo_object id="oval:ssg:obj:113" version="1">
<linux:name>fedora-release</linux:name>
</linux:rpminfo_object>
<linux:rpminfo_object id="oval:ssg:obj:307" version="1">
<linux:name>openssh-server</linux:name>
</linux:rpminfo_object>
<linux:rpminfo_object id="oval:ssg:obj:308" version="1">
<linux:name>dconf</linux:name>
</linux:rpminfo_object>
<ind:textfilecontent54_object id="oval:ssg:obj:440" version="1">
<!-- Read whole /etc/login.defs as single line so we can retrieve last PASS_MAX_DAYS directive occurrence -->
<ind:behaviors singleline="true"/>
<ind:filepath>/etc/login.defs</ind:filepath>
<!-- Retrieve last (uncommented) occurrence of PASS_MAX_DAYS directive -->
<ind:pattern operation="pattern match">.*\n[^#]*(PASS_MAX_DAYS\s+\d+)\s*\n</ind:pattern>
<ind:instance datatype="int" operation="greater than or equal">1</ind:instance>
</ind:textfilecontent54_object>
<ind:variable_object id="oval:ssg:obj:309" version="1">
<ind:var_ref>oval:ssg:var:441</ind:var_ref>
</ind:variable_object>
<unix:file_object comment="binary directories" id="oval:ssg:obj:311" version="1">
<!-- Check that /bin, /sbin, /usr/sbin, /usr/sbin, /usr/local/bin, and
/usr/local/sbin directories belong to user with uid 0 (root) -->
<unix:path operation="pattern match">^\/(|s)bin|^\/usr\/(|local\/)(|s)bin</unix:path>
<unix:filename xsi:nil="true"/>
<filter action="include">oval:ssg:ste:442</filter>
</unix:file_object>
<unix:file_object comment="binary files" id="oval:ssg:obj:312" version="1">
<!-- Check that files within /bin, /sbin, /usr/bin, /usr/sbin, /usr/local/bin, and
/usr/local/sbin directories belong to user with uid 0 (root) -->
<unix:path operation="pattern match">^\/(|s)bin|^\/usr\/(|local\/)(|s)bin</unix:path>
<unix:filename operation="pattern match">^.*$</unix:filename>
<filter action="include">oval:ssg:ste:442</filter>
</unix:file_object>
<ind:textfilecontent54_object id="oval:ssg:obj:313" version="2">
<ind:filepath>/etc/ssh/sshd_config</ind:filepath>
<ind:pattern operation="pattern match">^[\s]*(?i)ClientAliveInterval[\s]+(\d+)[\s]*(?:|(?:#.*))?$</ind:pattern>
<ind:instance datatype="int">1</ind:instance>
</ind:textfilecontent54_object>
<ind:textfilecontent54_object id="oval:ssg:obj:316" version="1">
<ind:path>/etc/dconf/db/gdm.d/</ind:path>
<ind:filename operation="pattern match">^.*$</ind:filename>
<ind:pattern operation="pattern match">^\[org/gnome/login-screen]([^\n]*\n+)+?banner-message-enable=true$</ind:pattern>
<ind:instance datatype="int">1</ind:instance>
</ind:textfilecontent54_object>
<ind:textfilecontent54_object id="oval:ssg:obj:317" version="1">
<ind:path>/etc/dconf/db/gdm.d/locks/</ind:path>
<ind:filename operation="pattern match">^.*$</ind:filename>
<ind:pattern operation="pattern match">^/org/gnome/login-screen/banner-message-enable$</ind:pattern>
<ind:instance datatype="int">1</ind:instance>
</ind:textfilecontent54_object>
<unix:file_object comment="library directories" id="oval:ssg:obj:318" version="1">
<!-- Check that /lib, /lib64, /usr/lib, and /usr/lib64 directories belong to user with uid 0 (root) -->
<unix:path operation="pattern match">^\/lib(|64)\/|^\/usr\/lib(|64)\/</unix:path>
<unix:filename xsi:nil="true"/>
<filter action="include">oval:ssg:ste:443</filter>
</unix:file_object>
<unix:file_object comment="library files" id="oval:ssg:obj:319" version="1">
<!-- Check that files within /lib, /lib64, /usr/lib, and /usr/lib64 directories belong to user with uid 0 (root) -->
<unix:path operation="pattern match">^\/lib(|64)\/|^\/usr\/lib(|64)\/</unix:path>
<unix:filename operation="pattern match">^.*$</unix:filename>
<filter action="include">oval:ssg:ste:443</filter>
</unix:file_object>
<ind:textfilecontent54_object id="oval:ssg:obj:320" version="2">
<ind:filepath>/etc/sysconfig/prelink</ind:filepath>
<ind:pattern operation="pattern match">^[\s]*PRELINKING=no[\s]*</ind:pattern>
<ind:instance datatype="int">1</ind:instance>
</ind:textfilecontent54_object>
<ind:textfilecontent54_object id="oval:ssg:obj:444" version="1">
<!-- Read whole /etc/login.defs as single line so we can retrieve last ENCRYPT_METHOD directive occurrence -->
<ind:behaviors singleline="true"/>
<ind:filepath>/etc/login.defs</ind:filepath>
<!-- Retrieve last (uncommented) occurrence of ENCRYPT_METHOD directive -->
<ind:pattern operation="pattern match">.*\n[^#]*(ENCRYPT_METHOD\s+\w+)\s*\n</ind:pattern>
<ind:instance datatype="int" operation="greater than or equal">1</ind:instance>
</ind:textfilecontent54_object>
<ind:variable_object id="oval:ssg:obj:321" version="1">
<ind:var_ref>oval:ssg:var:445</ind:var_ref>
</ind:variable_object>
<unix:file_object comment="home directories" id="oval:ssg:obj:323" version="2">
<unix:behaviors recurse="directories" recurse_direction="down" max_depth="1" recurse_file_system="all"/>
<unix:path operation="equals">/home</unix:path>
<unix:filename xsi:nil="true"/>
<filter action="exclude">oval:ssg:ste:446</filter>
<filter action="include">oval:ssg:ste:324</filter>
</unix:file_object>
<ind:textfilecontent54_object id="oval:ssg:obj:325" version="1">
<!-- Read whole /etc/pam.d/system-auth content as single line so we can verify existing order of PAM modules -->
<ind:behaviors singleline="true"/>
<ind:filepath>/etc/pam.d/system-auth</ind:filepath>
<!-- Since order of PAM modules matters ensure pam_faillock.so preauth silent in auth section is listed before
pam_unix.so module in auth section -->
<ind:pattern operation="pattern match">[\n][\s]*auth[\s]+required[\s]+pam_faillock\.so[\s]+preauth[\s]+silent[\s]+deny=([0-9]+)[\s]*[\n][\s]*auth[\s]+sufficient[\s]+pam_unix\.so[^\n]*[\n]</ind:pattern>
<!-- Check only the first instance -->
<ind:instance datatype="int" operation="equals">1</ind:instance>
</ind:textfilecontent54_object>
<ind:textfilecontent54_object id="oval:ssg:obj:327" version="1">
<!-- Read whole /etc/pam.d/system-auth content as single line so we can verify existing order of PAM modules -->
<ind:behaviors singleline="true"/>
<ind:filepath>/etc/pam.d/system-auth</ind:filepath>
<!-- Since order of PAM modules matters ensure pam_faillock.so in auth section is listed right after pam_unix.so auth row -->
<ind:pattern operation="pattern match">[\n][\s]*auth[\s]+sufficient[\s]+pam_unix\.so[^\n]+[\n][\s]*auth[\s]+\[default=die\][\s]+pam_faillock\.so[\s]+authfail[\s]+deny=([0-9]+)[^\n]*[\n]</ind:pattern>
<!-- Check only the first instance -->
<ind:instance datatype="int" operation="equals">1</ind:instance>
</ind:textfilecontent54_object>
<ind:textfilecontent54_object id="oval:ssg:obj:328" version="1">
<!-- Read whole /etc/pam.d/system-auth content as single line so we can verify existing order of PAM modules -->
<ind:behaviors singleline="true"/>
<ind:filepath>/etc/pam.d/system-auth</ind:filepath>
<!-- Since order of PAM modules matters ensure pam_faillock.so in account section is listed right before pam_unix.so account row -->
<ind:pattern operation="pattern match">[\n][\s]*account[\s]+required[\s]+pam_faillock\.so[^\n]*[\n][\s]*account[\s]+required[\s]+pam_unix\.so[^\n]*[\n]</ind:pattern>
<!-- Check only the first instance -->
<ind:instance datatype="int" operation="equals">1</ind:instance>
</ind:textfilecontent54_object>
<ind:textfilecontent54_object id="oval:ssg:obj:329" version="1">
<!-- Read whole /etc/pam.d/password-auth content as single line so we can verify existing order of PAM modules -->
<ind:behaviors singleline="true"/>
<ind:filepath>/etc/pam.d/password-auth</ind:filepath>
<!-- Since order of PAM modules matters ensure pam_faillock.so preauth silent in auth section is listed before
pam_unix.so module in auth section -->
<ind:pattern operation="pattern match">[\n][\s]*auth[\s]+required[\s]+pam_faillock\.so[\s]+preauth[\s]+silent[\s]+deny=([0-9]+)[\s]*[\n][\s]*auth[\s]+sufficient[\s]+pam_unix\.so[^\n]*[\n]</ind:pattern>
<!-- Check only the first instance -->
<ind:instance datatype="int" operation="equals">1</ind:instance>
</ind:textfilecontent54_object>
<ind:textfilecontent54_object id="oval:ssg:obj:330" version="1">
<!-- Read whole /etc/pam.d/system-auth content as single line so we can verify existing order of PAM modules -->
<ind:behaviors singleline="true"/>
<ind:filepath>/etc/pam.d/password-auth</ind:filepath>
<!-- Since order of PAM modules matters ensure pam_faillock.so in auth section is listed right after pam_unix.so auth row -->
<ind:pattern operation="pattern match">[\n][\s]*auth[\s]+sufficient[\s]+pam_unix\.so[^\n]+[\n][\s]*auth[\s]+\[default=die\][\s]+pam_faillock\.so[\s]+authfail[\s]+deny=([0-9]+)[^\n]*[\n]</ind:pattern>
<!-- Check only the first instance -->
<ind:instance datatype="int" operation="equals">1</ind:instance>
</ind:textfilecontent54_object>
<ind:textfilecontent54_object id="oval:ssg:obj:331" version="1">
<!-- Read whole /etc/pam.d/system-auth content as single line so we can verify existing order of PAM modules -->
<ind:behaviors singleline="true"/>
<ind:filepath>/etc/pam.d/password-auth</ind:filepath>
<!-- Since order of PAM modules matters ensure pam_faillock.so in account section is listed right before pam_unix.so account row -->
<ind:pattern operation="pattern match">[\n][\s]*account[\s]+required[\s]+pam_faillock\.so[^\n]*[\n][\s]*account[\s]+required[\s]+pam_unix\.so[^\n]*[\n]</ind:pattern>
<!-- Check only the first instance -->
<ind:instance datatype="int" operation="equals">1</ind:instance>
</ind:textfilecontent54_object>
<ind:textfilecontent54_object id="oval:ssg:obj:332" version="1">
<ind:filepath>/etc/snmp/snmpd.conf</ind:filepath>
<ind:pattern operation="pattern match">^[\s]*(com2se|rocommunity|rwcommunity)</ind:pattern>
<ind:instance datatype="int">1</ind:instance>
</ind:textfilecontent54_object>
<ind:textfilecontent54_object comment="log ftp transactions" id="oval:ssg:obj:333" version="1">
<ind:filepath>/etc/vsftpd/vsftpd.conf</ind:filepath>
<ind:pattern operation="pattern match">^[\s]*xferlog_enable[\s]*=[\s]*YES$</ind:pattern>
<ind:instance datatype="int" operation="greater than or equal">1</ind:instance>
</ind:textfilecontent54_object>
<ind:textfilecontent54_object comment="log ftp transactions" id="oval:ssg:obj:334" version="1">
<ind:filepath>/etc/vsftpd/vsftpd.conf</ind:filepath>
<ind:pattern operation="pattern match">^[\s]*xferlog_std_format[\s]*=[\s]*NO$</ind:pattern>
<ind:instance datatype="int" operation="greater than or equal">1</ind:instance>
</ind:textfilecontent54_object>
<ind:textfilecontent54_object comment="log ftp transactions" id="oval:ssg:obj:335" version="1">
<ind:filepath>/etc/vsftpd/vsftpd.conf</ind:filepath>
<ind:pattern operation="pattern match">^[\s]*log_ftp_protocol[\s]*=[\s]*YES$</ind:pattern>
<ind:instance datatype="int" operation="greater than or equal">1</ind:instance>
</ind:textfilecontent54_object>
<ind:textfilecontent54_object id="oval:ssg:obj:336" version="1">
<ind:path>/etc/dconf/db/local.d/</ind:path>
<ind:filename operation="pattern match">^.*$</ind:filename>
<ind:pattern operation="pattern match">^\[org/gnome/desktop/screensaver]([^\n]*\n+)+?picture-uri=\'\'$</ind:pattern>
<ind:instance datatype="int">1</ind:instance>
</ind:textfilecontent54_object>
<ind:textfilecontent54_object id="oval:ssg:obj:337" version="1">
<ind:path>/etc/dconf/db/local.d/locks/</ind:path>
<ind:filename operation="pattern match">^.*$</ind:filename>
<ind:pattern operation="pattern match">^/org/gnome/desktop/screensaver/picture-uri$</ind:pattern>
<ind:instance datatype="int">1</ind:instance>
</ind:textfilecontent54_object>
<ind:textfilecontent54_object id="oval:ssg:obj:340" version="1">
<ind:filepath>/etc/sysctl.conf</ind:filepath>
<ind:pattern operation="pattern match">^[\s]*kernel.exec-shield[\s]*=[\s]*1[\s]*$</ind:pattern>
<ind:instance datatype="int">1</ind:instance>
</ind:textfilecontent54_object>
<unix:sysctl_object id="oval:ssg:obj:338" version="1">
<unix:name>kernel.exec-shield</unix:name>
</unix:sysctl_object>
<ind:textfilecontent54_object id="oval:ssg:obj:341" version="1">
<ind:filepath>/boot/grub2/grub.cfg</ind:filepath>
<ind:pattern operation="pattern match">[\s]*noexec[\s]*=[\s]*off</ind:pattern>
<ind:instance datatype="int">1</ind:instance>
</ind:textfilecontent54_object>
<linux:rpminfo_object id="oval:ssg:obj:342" version="1">
<linux:name>ntp</linux:name>
</linux:rpminfo_object>
<linux:rpminfo_object id="oval:ssg:obj:343" version="1">
<linux:name>net-snmp</linux:name>
</linux:rpminfo_object>
<unix:uname_object comment="64 bit architecture" id="oval:ssg:obj:344" version="1"/>
<ind:textfilecontent54_object id="oval:ssg:obj:346" version="1">
<ind:filepath>/etc/pam.d/system-auth</ind:filepath>
<ind:pattern operation="pattern match">^\s*password\s+(?:(?:required)|(?:requisite))\s+pam_cracklib\.so.*retry=([0-9]*).*$</ind:pattern>
<ind:instance datatype="int">1</ind:instance>
</ind:textfilecontent54_object>
<ind:textfilecontent54_object id="oval:ssg:obj:348" version="1">
<ind:filepath>/etc/pam.d/system-auth</ind:filepath>
<ind:pattern operation="pattern match">^\s*password\s+(?:(?:required)|(?:requisite))\s+pam_pwquality\.so.*retry=([0-9]*).*$</ind:pattern>
<ind:instance datatype="int">1</ind:instance>
</ind:textfilecontent54_object>
<linux:rpminfo_object id="oval:ssg:obj:349" version="1">
<linux:name>McAfeeVSEForLinux</linux:name>
</linux:rpminfo_object>
<ind:textfilecontent54_object id="oval:ssg:obj:350" version="1">
<ind:filepath>/etc/security/pwquality.conf</ind:filepath>
<ind:pattern operation="pattern match">^minlen[\s]*=[\s]*(-?\d+)(?:[\s]|$)</ind:pattern>
<ind:instance datatype="int" operation="greater than or equal">1</ind:instance>
</ind:textfilecontent54_object>
<unix:file_object comment="/boot/grub2/grub.cfg" id="oval:ssg:obj:352" version="1">
<unix:filepath>/boot/grub2/grub.cfg</unix:filepath>
</unix:file_object>
<unix:file_object comment="/boot/efi/EFI/redhat/grub.cfg" id="oval:ssg:obj:354" version="1">
<unix:filepath>/boot/efi/EFI/redhat/grub.cfg</unix:filepath>
</unix:file_object>
<ind:textfilecontent54_object id="oval:ssg:obj:355" version="1">
<ind:path>/etc/yum.repos.d</ind:path>
<ind:filename operation="pattern match">.*</ind:filename>
<ind:pattern operation="pattern match">^\s*gpgcheck\s*=\s*0\s*$</ind:pattern>
<ind:instance datatype="int">1</ind:instance>
</ind:textfilecontent54_object>
<ind:textfilecontent54_object id="oval:ssg:obj:356" version="1">
<ind:path>/etc/dconf/db/gdm.d/locks/</ind:path>
<ind:filename operation="pattern match">^.*$</ind:filename>
<ind:pattern operation="pattern match">^/org/gnome/login-screen/banner-message-text$</ind:pattern>
<ind:instance datatype="int">1</ind:instance>
</ind:textfilecontent54_object>
<ind:textfilecontent54_object id="oval:ssg:obj:357" version="1">
<ind:path>/etc/dconf/db/gdm.d/</ind:path>
<ind:filename operation="pattern match">^.*$</ind:filename>
<ind:pattern operation="pattern match">^banner-message-text=[\s']*([^']*)</ind:pattern>
<ind:instance datatype="int">1</ind:instance>
</ind:textfilecontent54_object>
<unix:file_object comment="look for .netrc in /home" id="oval:ssg:obj:359" version="1">
<unix:behaviors recurse="directories" recurse_direction="down" max_depth="1" recurse_file_system="all"/>
<unix:path operation="equals">/home</unix:path>
<unix:filename operation="pattern match">^\.netrc$</unix:filename>
</unix:file_object>
<unix:uname_object comment="32 bit architecture" id="oval:ssg:obj:360" version="1"/>
<ind:textfilecontent54_object comment="Ensure at least one NTP server is set" id="oval:ssg:obj:362" version="1">
<ind:filepath>/etc/ntp.conf</ind:filepath>
<ind:pattern operation="pattern match">^[\s]*server[\s]+.+$</ind:pattern>
<ind:instance datatype="int">1</ind:instance>
</ind:textfilecontent54_object>
<ind:textfilecontent54_object id="oval:ssg:obj:363" version="2">
<ind:filepath>/etc/ssh/sshd_config</ind:filepath>
<ind:pattern operation="pattern match">^[\s]*(?i)ClientAliveCountMax[\s]+([\d]+)[\s]*(?:|(?:#.*))?$</ind:pattern>
<ind:instance datatype="int">1</ind:instance>
</ind:textfilecontent54_object>
<ind:textfilecontent54_object id="oval:ssg:obj:365" version="1">
<ind:filepath>/etc/passwd</ind:filepath>
<ind:pattern operation="pattern match">^(?!root).*:x:0*([0-9]{1,2}|[1-4][0-9]{2}):[\d]*:[^:]*:[^:]*:(?!\/sbin\/nologin|\/bin\/sync|\/sbin\/shutdown|\/sbin\/halt).*$</ind:pattern>
<ind:instance datatype="int">1</ind:instance>
</ind:textfilecontent54_object>
<linux:rpminfo_object id="oval:ssg:obj:366" version="1">
<linux:name>vsftpd</linux:name>
</linux:rpminfo_object>
<ind:textfilecontent54_object id="oval:ssg:obj:367" version="2">
<ind:filepath>/etc/exports</ind:filepath>
<ind:pattern operation="pattern match">^(.*?(\binsecure_locks\b)[^$]*)$</ind:pattern>
<ind:instance datatype="int">1</ind:instance>
</ind:textfilecontent54_object>
<ind:textfilecontent54_object id="oval:ssg:obj:368" version="1">
<ind:filepath>/etc/snmp/snmpd.conf</ind:filepath>
<ind:pattern operation="pattern match">^[\s]*(com2se|rocommunity|rwcommunity|createUser).*(public|private)</ind:pattern>
<ind:instance datatype="int">1</ind:instance>
</ind:textfilecontent54_object>
<ind:textfilecontent54_object id="oval:ssg:obj:369" version="1">
<ind:filepath>/etc/security/pwquality.conf</ind:filepath>
<ind:pattern operation="pattern match">^ucredit[s\]*=[\s]*(-?\d+)(?:[\s]|$)</ind:pattern>
<ind:instance datatype="int" operation="less than or equal">1</ind:instance>
</ind:textfilecontent54_object>
<ind:textfilecontent54_object id="oval:ssg:obj:371" version="1">
<ind:filepath>/etc/pam.d/system-auth</ind:filepath>
<ind:pattern operation="pattern match">^\s*password\s+(?:(?:required)|(?:requisite))\s+pam_pwquality\.so.*$</ind:pattern>
<ind:instance datatype="int">1</ind:instance>
</ind:textfilecontent54_object>
<ind:textfilecontent54_object id="oval:ssg:obj:372" version="1">
<ind:path>/etc/dconf/db/local.d/</ind:path>
<ind:filename operation="pattern match">^.*$</ind:filename>
<ind:pattern operation="pattern match">^\[org/gnome/desktop/media-handling]([^\n]*\n+)+?automount=false$</ind:pattern>
<ind:instance datatype="int">1</ind:instance>
</ind:textfilecontent54_object>
<ind:textfilecontent54_object id="oval:ssg:obj:373" version="1">
<ind:path>/etc/dconf/db/local.d/locks/</ind:path>
<ind:filename operation="pattern match">^.*$</ind:filename>
<ind:pattern operation="pattern match">^/org/gnome/desktop/media-handling/automount$</ind:pattern>
<ind:instance datatype="int">1</ind:instance>
</ind:textfilecontent54_object>
<ind:textfilecontent54_object id="oval:ssg:obj:374" version="1">
<ind:path>/etc/dconf/db/local.d/</ind:path>
<ind:filename operation="pattern match">^.*$</ind:filename>
<ind:pattern operation="pattern match">^\[org/gnome/desktop/media-handling]([^\n]*\n+)+?automount-open=false$</ind:pattern>
<ind:instance datatype="int">1</ind:instance>
</ind:textfilecontent54_object>
<ind:textfilecontent54_object id="oval:ssg:obj:375" version="1">
<ind:path>/etc/dconf/db/local.d/locks/</ind:path>
<ind:filename operation="pattern match">^.*$</ind:filename>
<ind:pattern operation="pattern match">^/org/gnome/desktop/media-handling/automount-open$</ind:pattern>
<ind:instance datatype="int">1</ind:instance>
</ind:textfilecontent54_object>
<ind:textfilecontent54_object id="oval:ssg:obj:376" version="1">
<ind:path>/etc/dconf/db/local.d/</ind:path>
<ind:filename operation="pattern match">^.*$</ind:filename>
<ind:pattern operation="pattern match">^\[org/gnome/desktop/media-handling]([^\n]*\n+)+?autorun-never=true$</ind:pattern>
<ind:instance datatype="int">1</ind:instance>
</ind:textfilecontent54_object>
<ind:textfilecontent54_object id="oval:ssg:obj:377" version="1">
<ind:path>/etc/dconf/db/local.d/locks/</ind:path>
<ind:filename operation="pattern match">^.*$</ind:filename>
<ind:pattern operation="pattern match">^/org/gnome/desktop/media-handling/autorun-never$</ind:pattern>
<ind:instance datatype="int">1</ind:instance>
</ind:textfilecontent54_object>
<unix:file_object comment="look for sshd.service in /etc/systemd/system/multi-user.target.wants" id="oval:ssg:obj:378" version="1">
<unix:filepath>/etc/systemd/system/multi-user.target.wants/sshd.service</unix:filepath>
<filter action="include">oval:ssg:ste:447</filter>
</unix:file_object>
<ind:textfilecontent54_object id="oval:ssg:obj:379" version="1">
<ind:filepath>/etc/pam.d/system-auth</ind:filepath>
<ind:pattern operation="pattern match">^\s*password\s+(?:(?:sufficient)|(?:required))\s+pam_unix\.so.*remember=([0-9]*).*$</ind:pattern>
<ind:instance datatype="int">1</ind:instance>
</ind:textfilecontent54_object>
<ind:textfilecontent54_object id="oval:ssg:obj:381" version="2">
<ind:filepath>/etc/ssh/sshd_config</ind:filepath>
<ind:pattern operation="pattern match">^[\s]*(?i)PermitEmptyPasswords(?-i)[\s]+no[\s]*(?:|(?:#.*))?$</ind:pattern>
<ind:instance datatype="int">1</ind:instance>
</ind:textfilecontent54_object>
<linux:rpminfo_object id="oval:ssg:obj:115" version="1">
<linux:name>redhat-release-workstation</linux:name>
</linux:rpminfo_object>
<linux:rpminfo_object id="oval:ssg:obj:117" version="1">
<linux:name>redhat-release-server</linux:name>
</linux:rpminfo_object>
<ind:textfilecontent54_object id="oval:ssg:obj:382" version="1">
<ind:filepath>/etc/security/pwquality.conf</ind:filepath>
<ind:pattern operation="pattern match">^ocredit[\s]*=[\s]*(-?\d+)(?:[\s]|$)</ind:pattern>
<ind:instance datatype="int" operation="less than or equal">1</ind:instance>
</ind:textfilecontent54_object>
<ind:textfilecontent54_object id="oval:ssg:obj:448" version="1">
<!-- Read whole /etc/login.defs as single line so we can retrieve last PASS_WARN_AGE directive occurrence -->
<ind:behaviors singleline="true"/>
<ind:filepath>/etc/login.defs</ind:filepath>
<!-- Retrieve last (uncommented) occurrence of PASS_WARN_AGE directive -->
<ind:pattern operation="pattern match">.*\n[^#]*(PASS_WARN_AGE\s+\d+)\s*\n</ind:pattern>
<ind:instance datatype="int" operation="greater than or equal">1</ind:instance>
</ind:textfilecontent54_object>
<ind:variable_object id="oval:ssg:obj:384" version="1">
<ind:var_ref>oval:ssg:var:449</ind:var_ref>
</ind:variable_object>
<unix:file_object comment="binary files" id="oval:ssg:obj:386" version="1">
<!-- Check that binary files under /bin, /sbin, /usr/bin, /usr/sbin, /usr/local/bin,
and /usr/local/sbin directories have safe permissions (go-w) -->
<unix:path operation="pattern match">^\/(|s)bin|^\/usr\/(|local\/)(|s)bin</unix:path>
<unix:filename operation="pattern match">^.*$</unix:filename>
<filter action="include">oval:ssg:ste:450</filter>
<filter action="exclude">oval:ssg:ste:451</filter>
</unix:file_object>
<ind:textfilecontent54_object id="oval:ssg:obj:387" version="1">
<ind:filepath>/etc/security/pwquality.conf</ind:filepath>
<ind:pattern operation="pattern match">^maxrepeat[\s]*=[\s]*(-?\d+)(?:[\s]|$)</ind:pattern>
<ind:instance datatype="int" operation="less than or equal">1</ind:instance>
</ind:textfilecontent54_object>
<unix:file_object comment="/boot/grub2/grub.cfg" id="oval:ssg:obj:389" version="1">
<unix:filepath>/boot/grub2/grub.cfg</unix:filepath>
</unix:file_object>
<unix:file_object comment="/boot/efi/EFI/redhat/grub.cfg" id="oval:ssg:obj:391" version="1">
<unix:filepath>/boot/efi/EFI/redhat/grub.cfg</unix:filepath>
</unix:file_object>
<unix:file_object comment="library directories" id="oval:ssg:obj:392" version="1">
<!-- Check that /lib, /lib64, /usr/lib, /usr/lib64 directories have safe permissions (go-w) -->
<unix:path operation="pattern match">^\/lib(|64)|^\/usr\/lib(|64)</unix:path>
<unix:filename xsi:nil="true"/>
<filter action="include">oval:ssg:ste:452</filter>
<filter action="exclude">oval:ssg:ste:453</filter>
</unix:file_object>
<unix:file_object comment="library files" id="oval:ssg:obj:393" version="1">
<!-- Check the files within /lib, /lib64, /usr/lib, /usr/lib64 directories have safe permissions (go-w) -->
<unix:path operation="pattern match">^\/lib(|64)|^\/usr\/lib(|64)</unix:path>
<unix:filename operation="pattern match">^.*$</unix:filename>
<filter action="include">oval:ssg:ste:452</filter>
<filter action="exclude">oval:ssg:ste:453</filter>
</unix:file_object>
<ind:textfilecontent54_object id="oval:ssg:obj:394" version="2">
<ind:filepath>/etc/ssh/sshd_config</ind:filepath>
<ind:pattern operation="pattern match">^[\s]*(?i)PermitRootLogin(?-i)[\s]+no[\s]*(?:|(?:#.*))?$</ind:pattern>
<ind:instance datatype="int">1</ind:instance>
</ind:textfilecontent54_object>
<ind:textfilecontent54_object comment="serial ports /etc/securetty" id="oval:ssg:obj:395" version="1">
<ind:filepath>/etc/securetty</ind:filepath>
<ind:pattern operation="pattern match">^ttyS[0-9]+$</ind:pattern>
<ind:instance datatype="int" operation="greater than or equal">1</ind:instance>
</ind:textfilecontent54_object>
<ind:textfilecontent54_object id="oval:ssg:obj:396" version="1">
<ind:filepath>/etc/security/pwquality.conf</ind:filepath>
<ind:pattern operation="pattern match">^difok[\s]*=[\s]*(\d+)(?:[\s]|$)</ind:pattern>
<ind:instance datatype="int" operation="greater than or equal">1</ind:instance>
</ind:textfilecontent54_object>
<ind:textfilecontent54_object id="oval:ssg:obj:398" comment="gpgcheck set in /etc/yum.conf" version="1">
<ind:filepath>/etc/yum.conf</ind:filepath>
<ind:pattern operation="pattern match">^\s*gpgcheck\s*=\s*1\s*$</ind:pattern>
<ind:instance datatype="int" operation="equals">1</ind:instance>
</ind:textfilecontent54_object>
<ind:textfilecontent54_object id="oval:ssg:obj:454" version="1">
<!-- Read whole /etc/login.defs as single line so we can retrieve last PASS_MIN_LEN directive occurrence -->
<ind:behaviors singleline="true"/>
<ind:filepath>/etc/login.defs</ind:filepath>
<!-- Retrieve last (uncommented) occurrence of PASS_MIN_LEN directive -->
<ind:pattern operation="pattern match">.*\n[^#]*(PASS_MIN_LEN\s+\d+)\s*\n</ind:pattern>
<ind:instance datatype="int" operation="greater than or equal">1</ind:instance>
</ind:textfilecontent54_object>
<ind:variable_object id="oval:ssg:obj:399" version="1">
<ind:var_ref>oval:ssg:var:455</ind:var_ref>
</ind:variable_object>
<ind:textfilecontent54_object id="oval:ssg:obj:401" version="1">
<ind:filepath>/etc/issue</ind:filepath>
<ind:pattern var_ref="oval:ssg:var:456" operation="pattern match"/>
<ind:instance datatype="int" operation="greater than or equal">1</ind:instance>
</ind:textfilecontent54_object>
<ind:textfilecontent54_object id="oval:ssg:obj:402" version="1">
<ind:path>/etc/dconf/db/local.d/</ind:path>
<ind:filename operation="pattern match">^.*$</ind:filename>
<ind:pattern operation="pattern match">^\[org/gnome/desktop/thumbnailers]([^\n]*\n+)+?disable-all=true$</ind:pattern>
<ind:instance datatype="int">1</ind:instance>
</ind:textfilecontent54_object>
<ind:textfilecontent54_object id="oval:ssg:obj:403" version="1">
<ind:path>/etc/dconf/db/local.d/locks/</ind:path>
<ind:filename operation="pattern match">^.*$</ind:filename>
<ind:pattern operation="pattern match">^/org/gnome/desktop/thumbnailers/disable-all$</ind:pattern>
<ind:instance datatype="int">1</ind:instance>
</ind:textfilecontent54_object>
<ind:textfilecontent54_object id="oval:ssg:obj:404" version="2">
<ind:filepath>/etc/dconf/profile/user</ind:filepath>
<ind:pattern operation="pattern match">^user-db:user\nsystem-db:local$</ind:pattern>
<ind:instance datatype="int">1</ind:instance>
</ind:textfilecontent54_object>
<ind:textfilecontent54_object id="oval:ssg:obj:407" version="1">
<ind:filepath>/etc/sysctl.d/ipv6.conf</ind:filepath>
<ind:pattern operation="pattern match">^[\s]*net.ipv6.conf.all.disable_ipv6[\s]*=[\s]*1[\s]*$</ind:pattern>
<ind:instance datatype="int">1</ind:instance>
</ind:textfilecontent54_object>
<unix:sysctl_object id="oval:ssg:obj:405" version="1">
<unix:name>net.ipv6.conf.all.disable_ipv6</unix:name>
</unix:sysctl_object>
<ind:textfilecontent54_object id="oval:ssg:obj:408" version="1">
<ind:filepath>/etc/security/pwquality.conf</ind:filepath>
<ind:pattern operation="pattern match">^lcredit[\s]*=[\s]*(-?\d+)(?:[\s]|$)</ind:pattern>
<ind:instance datatype="int" operation="less than or equal">1</ind:instance>
</ind:textfilecontent54_object>
<ind:textfilecontent54_object id="oval:ssg:obj:410" version="1">
<ind:filepath>/etc/grub2.cfg</ind:filepath>
<ind:pattern operation="pattern match">^[\s]*set[\s]+superusers=\"(?i)(?!root|admin|administrator)(?-i).*\"$</ind:pattern>
<ind:instance datatype="int">1</ind:instance>
</ind:textfilecontent54_object>
<ind:textfilecontent54_object id="oval:ssg:obj:411" version="1">
<ind:filepath>/etc/grub2.cfg</ind:filepath>
<ind:pattern operation="pattern match">^[\s]*password_pbkdf2[\s]+.*[\s]+grub\.pbkdf2\.sha512.*$</ind:pattern>
<ind:instance datatype="int">1</ind:instance>
</ind:textfilecontent54_object>
<unix:password_object id="oval:ssg:obj:412" version="1">
<unix:username operation="pattern match">.*</unix:username>
</unix:password_object>
<ind:textfilecontent54_object id="oval:ssg:obj:414" version="1">
<ind:path>/etc/dconf/db/local.d/</ind:path>
<ind:filename operation="pattern match">^.*$</ind:filename>
<ind:pattern operation="pattern match">^\[org/gnome/desktop/screensaver]([^\n]*\n+)+?idle-activation-enabled=true$</ind:pattern>
<ind:instance datatype="int">1</ind:instance>
</ind:textfilecontent54_object>
<ind:textfilecontent54_object id="oval:ssg:obj:415" version="1">
<ind:path>/etc/dconf/db/local.d/locks/</ind:path>
<ind:filename operation="pattern match">^.*$</ind:filename>
<ind:pattern operation="pattern match">^/org/gnome/desktop/screensaver/idle-activation-enabled$</ind:pattern>
<ind:instance datatype="int">1</ind:instance>
</ind:textfilecontent54_object>
<unix:file_object comment="look for ntpd.service in /etc/systemd/system/multi-user.target.wants" id="oval:ssg:obj:416" version="1">
<unix:filepath>/etc/systemd/system/multi-user.target.wants/ntpd.service</unix:filepath>
<filter action="include">oval:ssg:ste:447</filter>
</unix:file_object>
<ind:environmentvariable58_object id="oval:ssg:obj:457" version="1">
<ind:pid xsi:nil="true" datatype="int"/>
<ind:name>PATH</ind:name>
</ind:environmentvariable58_object>
<unix:file_object comment="root's path directories with wrong group / other write permissions" id="oval:ssg:obj:417" version="1">
<unix:path var_ref="oval:ssg:var:458" var_check="at least one"/>
<unix:filename xsi:nil="true"/>
<filter action="include">oval:ssg:ste:459</filter>
<filter action="exclude">oval:ssg:ste:460</filter>
</unix:file_object>
<ind:family_object id="oval:ssg:obj:119" version="1"/>
<linux:rpminfo_object id="oval:ssg:obj:121" version="1">
<linux:name>redhat-release-workstation</linux:name>
</linux:rpminfo_object>
<linux:rpminfo_object id="oval:ssg:obj:123" version="1">
<linux:name>redhat-release-server</linux:name>
</linux:rpminfo_object>
<ind:textfilecontent54_object id="oval:ssg:obj:418" version="1">
<ind:filepath>/etc/passwd</ind:filepath>
<ind:pattern operation="pattern match">^(?!root:)[^:]*:[^:]*:0</ind:pattern>
<ind:instance datatype="int">1</ind:instance>
</ind:textfilecontent54_object>
<unix:file_object comment="/boot/grub2/grub.cfg" id="oval:ssg:obj:419" version="1">
<unix:filepath>/boot/grub2/grub.cfg</unix:filepath>
</unix:file_object>
<unix:file_object comment="/boot/efi/EFI/redhat/grub.cfg" id="oval:ssg:obj:421" version="1">
<unix:filepath>/boot/efi/EFI/redhat/grub.cfg</unix:filepath>
</unix:file_object>
<ind:textfilecontent54_object comment="virtual consoles /etc/securetty" id="oval:ssg:obj:422" version="1">
<ind:filepath>/etc/securetty</ind:filepath>
<ind:pattern operation="pattern match">^vc/[0-9]+$</ind:pattern>
<ind:instance datatype="int" operation="greater than or equal">1</ind:instance>
</ind:textfilecontent54_object>
<ind:textfilecontent54_object id="oval:ssg:obj:461" version="1">
<!-- Read whole /etc/login.defs as single line so we can retrieve last PASS_MIN_DAYS directive occurrence -->
<ind:behaviors singleline="true"/>
<ind:filepath>/etc/login.defs</ind:filepath>
<!-- Retrieve last (uncommented) occurrence of PASS_MIN_DAYS directive -->
<ind:pattern operation="pattern match">.*\n[^#]*(PASS_MIN_DAYS\s+\d+)\s*\n</ind:pattern>
<ind:instance datatype="int" operation="greater than or equal">1</ind:instance>
</ind:textfilecontent54_object>
<ind:variable_object id="oval:ssg:obj:423" version="1">
<ind:var_ref>oval:ssg:var:462</ind:var_ref>
</ind:variable_object>
<ind:textfilecontent54_object id="oval:ssg:obj:425" version="1">
<ind:filepath>/etc/security/pwquality.conf</ind:filepath>
<ind:pattern operation="pattern match">^dcredit[\s]*=[\s]*(-?\d+)(?:[\s]|$)</ind:pattern>
<ind:instance datatype="int" operation="less than or equal">1</ind:instance>
</ind:textfilecontent54_object>
<ind:textfilecontent54_object id="oval:ssg:obj:427" version="1">
<ind:path>/etc/dconf/db/local.d/</ind:path>
<ind:filename operation="pattern match">^.*$</ind:filename>
<ind:pattern operation="pattern match">^\[org/gnome/desktop/screensaver]([^\n]*\n+)+?lock-enabled=true$</ind:pattern>
<ind:instance datatype="int">1</ind:instance>
</ind:textfilecontent54_object>
<ind:textfilecontent54_object id="oval:ssg:obj:428" version="1">
<ind:path>/etc/dconf/db/local.d/locks/</ind:path>
<ind:filename operation="pattern match">^.*$</ind:filename>
<ind:pattern operation="pattern match">^/org/gnome/desktop/screensaver/lock-enabled$</ind:pattern>
<ind:instance datatype="int">1</ind:instance>
</ind:textfilecontent54_object>
<ind:textfilecontent54_object id="oval:ssg:obj:429" version="1">
<ind:path>/etc/dconf/db/local.d/</ind:path>
<ind:filename operation="pattern match">^.*$</ind:filename>
<ind:pattern operation="pattern match">^\[org/gnome/desktop/screensaver]([^\n]*\n+)+?lock-delay=0$</ind:pattern>
<ind:instance datatype="int">1</ind:instance>
</ind:textfilecontent54_object>
<ind:textfilecontent54_object id="oval:ssg:obj:430" version="1">
<ind:path>/etc/dconf/db/local.d/locks/</ind:path>
<ind:filename operation="pattern match">^.*$</ind:filename>
<ind:pattern operation="pattern match">^/org/gnome/desktop/screensaver/lock-delay$</ind:pattern>
<ind:instance datatype="int">1</ind:instance>
</ind:textfilecontent54_object>
<ind:textfilecontent54_object comment="Banner for FTP Users" id="oval:ssg:obj:431" version="1">
<ind:filepath>/etc/vsftpd/vsftpd.conf</ind:filepath>
<ind:pattern operation="pattern match">^[\s]*banner_file[\s]*=[\s]*/etc/issue*$</ind:pattern>
<ind:instance datatype="int" operation="greater than or equal">1</ind:instance>
</ind:textfilecontent54_object>
<ind:textfilecontent54_object id="oval:ssg:obj:432" version="1">
<ind:path>/etc/dconf/db/local.d/</ind:path>
<ind:filename operation="pattern match">^.*$</ind:filename>
<ind:pattern operation="pattern match">^\[org/gnome/desktop/session]([^\n]*\n+)+?idle-delay=[0-9]*$</ind:pattern>
<ind:instance datatype="int">1</ind:instance>
</ind:textfilecontent54_object>
<ind:textfilecontent54_object id="oval:ssg:obj:433" version="1">
<ind:path>/etc/dconf/db/local.d/locks/</ind:path>
<ind:filename operation="pattern match">^.*$</ind:filename>
<ind:pattern operation="pattern match">^/org/gnome/desktop/session/idle-delay$</ind:pattern>
<ind:instance datatype="int">1</ind:instance>
</ind:textfilecontent54_object>
<ind:textfilecontent54_object id="oval:ssg:obj:434" version="1">
<ind:path>/etc/dconf/db/local.d/</ind:path>
<ind:filename operation="pattern match">^.*$</ind:filename>
<ind:pattern operation="pattern match">^idle-delay[\s=]*([^=\s]*)</ind:pattern>
<ind:instance datatype="int">1</ind:instance>
</ind:textfilecontent54_object>
<ind:textfilecontent54_object id="oval:ssg:obj:436" version="1">
<ind:filepath>/usr/lib/systemd/system/rescue.service</ind:filepath>
<ind:pattern operation="pattern match">^ExecStart=\-.*/sbin/sulogin</ind:pattern>
<ind:instance datatype="int">1</ind:instance>
</ind:textfilecontent54_object>
<ind:textfilecontent54_object id="oval:ssg:obj:437" version="1">
<ind:filepath>/usr/lib/systemd/system/runlevel1.target</ind:filepath>
<ind:pattern operation="pattern match">^Requires=.*rescue.service</ind:pattern>
<ind:instance datatype="int">1</ind:instance>
</ind:textfilecontent54_object>
<unix:file_object comment="look for rescue.service in /etc/systemd/system" id="oval:ssg:obj:438" version="1">
<unix:behaviors recurse="directories" recurse_direction="down" recurse_file_system="all"/>
<unix:path operation="equals">/etc/systemd/system</unix:path>
<unix:filename operation="pattern match">^rescue.service$</unix:filename>
</unix:file_object>
<unix:file_object comment="look for runlevel1.target in /etc/systemd/system" id="oval:ssg:obj:439" version="1">
<unix:behaviors recurse="directories" recurse_direction="down" recurse_file_system="all"/>
<unix:path operation="equals">/etc/systemd/system</unix:path>
<unix:filename operation="pattern match">^runlevel1.target$</unix:filename>
</unix:file_object>
</objects>
<states>
<ind:textfilecontent54_state id="oval:ssg:ste:306" version="1">
<ind:instance datatype="int">1</ind:instance>
<ind:subexpression datatype="int" operation="greater than or equal" var_ref="oval:ssg:var:463"/>
</ind:textfilecontent54_state>
<ind:family_state id="oval:ssg:ste:112" version="1">
<ind:family>unix</ind:family>
</ind:family_state>
<linux:rpminfo_state id="oval:ssg:ste:114" version="1">
<linux:version operation="pattern match">^19$</linux:version>
</linux:rpminfo_state>
<ind:variable_state id="oval:ssg:ste:310" version="1">
<ind:value operation="less than or equal" var_ref="oval:ssg:var:464" datatype="int" var_check="at least one"/>
</ind:variable_state>
<unix:file_state id="oval:ssg:ste:442" version="1" operator="OR">
<unix:user_id datatype="int" operation="not equal">0</unix:user_id>
</unix:file_state>
<ind:textfilecontent54_state comment="upper bound of ClientAliveInterval in seconds" id="oval:ssg:ste:314" version="1">
<ind:subexpression datatype="int" operation="less than or equal" var_check="all" var_ref="oval:ssg:var:465"/>
</ind:textfilecontent54_state>
<ind:textfilecontent54_state comment="lower bound of ClientAliveInterval in seconds" id="oval:ssg:ste:315" version="1">
<ind:subexpression datatype="int" operation="greater than">0</ind:subexpression>
</ind:textfilecontent54_state>
<unix:file_state id="oval:ssg:ste:443" version="1">
<unix:user_id datatype="int" operation="not equal">0</unix:user_id>
</unix:file_state>
<ind:variable_state id="oval:ssg:ste:322" version="1">
<ind:value operation="equals" datatype="string">SHA512</ind:value>
</ind:variable_state>
<unix:file_state id="oval:ssg:ste:446" version="1">
<!-- Exclude /home directory itself from the check. Check /home/* directories only. -->
<unix:path operation="equals">/home</unix:path>
</unix:file_state>
<unix:file_state id="oval:ssg:ste:324" version="1" operator="OR">
<unix:suid datatype="boolean">true</unix:suid>
<unix:sgid datatype="boolean">true</unix:sgid>
<unix:sticky datatype="boolean">true</unix:sticky>
<unix:gwrite datatype="boolean">true</unix:gwrite>
<unix:oread datatype="boolean">true</unix:oread>
<unix:owrite datatype="boolean">true</unix:owrite>
<unix:oexec datatype="boolean">true</unix:oexec>
</unix:file_state>
<ind:textfilecontent54_state id="oval:ssg:ste:326" version="1">
<ind:subexpression datatype="int" operation="less than or equal" var_ref="oval:ssg:var:466"/>
</ind:textfilecontent54_state>
<unix:sysctl_state id="oval:ssg:ste:339" version="1">
<unix:value datatype="int" operation="equals">1</unix:value>
</unix:sysctl_state>
<unix:uname_state comment="64 bit architecture" id="oval:ssg:ste:345" version="1">
<unix:processor_type operation="equals">x86_64</unix:processor_type>
</unix:uname_state>
<ind:textfilecontent54_state id="oval:ssg:ste:347" version="1">
<ind:subexpression datatype="int" operation="less than or equal" var_ref="oval:ssg:var:467"/>
</ind:textfilecontent54_state>
<ind:textfilecontent54_state id="oval:ssg:ste:351" version="1">
<ind:instance datatype="int">1</ind:instance>
<ind:subexpression datatype="int" operation="greater than or equal" var_ref="oval:ssg:var:468"/>
</ind:textfilecontent54_state>
<unix:file_state id="oval:ssg:ste:353" version="1">
<unix:uexec datatype="boolean">false</unix:uexec>
<unix:gread datatype="boolean">false</unix:gread>
<unix:gwrite datatype="boolean">false</unix:gwrite>
<unix:gexec datatype="boolean">false</unix:gexec>
<unix:oread datatype="boolean">false</unix:oread>
<unix:owrite datatype="boolean">false</unix:owrite>
<unix:oexec datatype="boolean">false</unix:oexec>
</unix:file_state>
<ind:textfilecontent54_state id="oval:ssg:ste:358" version="1">
<ind:subexpression datatype="string" operation="pattern match" var_ref="oval:ssg:var:456"/>
</ind:textfilecontent54_state>
<unix:uname_state comment="32 bit architecture" id="oval:ssg:ste:361" version="1">
<unix:processor_type operation="equals">i686</unix:processor_type>
</unix:uname_state>
<ind:textfilecontent54_state id="oval:ssg:ste:364" version="1">
<ind:subexpression datatype="int" operation="equals">0</ind:subexpression>
</ind:textfilecontent54_state>
<ind:textfilecontent54_state id="oval:ssg:ste:370" version="1">
<ind:instance datatype="int">1</ind:instance>
<ind:subexpression datatype="int" operation="less than or equal" var_ref="oval:ssg:var:469"/>
</ind:textfilecontent54_state>
<unix:file_state id="oval:ssg:ste:447" version="1">
<unix:type operation="equals">symbolic link</unix:type>
</unix:file_state>
<ind:textfilecontent54_state id="oval:ssg:ste:380" version="1">
<ind:subexpression datatype="int" operation="greater than or equal" var_ref="oval:ssg:var:470"/>
</ind:textfilecontent54_state>
<linux:rpminfo_state id="oval:ssg:ste:116" version="1">
<linux:version operation="pattern match">^6.*$</linux:version>
</linux:rpminfo_state>
<linux:rpminfo_state id="oval:ssg:ste:118" version="1">
<linux:version operation="pattern match">^6.*$</linux:version>
</linux:rpminfo_state>
<ind:textfilecontent54_state id="oval:ssg:ste:383" version="1">
<ind:instance datatype="int">1</ind:instance>
<ind:subexpression datatype="int" operation="less than or equal" var_ref="oval:ssg:var:471"/>
</ind:textfilecontent54_state>
<ind:variable_state id="oval:ssg:ste:385" version="1">
<ind:value operation="greater than or equal" var_ref="oval:ssg:var:472" datatype="int" var_check="at least one"/>
</ind:variable_state>
<unix:file_state id="oval:ssg:ste:450" version="1" operator="OR">
<unix:gwrite datatype="boolean">true</unix:gwrite>
<unix:owrite datatype="boolean">true</unix:owrite>
</unix:file_state>
<unix:file_state id="oval:ssg:ste:451" version="1">
<unix:type operation="equals">symbolic link</unix:type>
</unix:file_state>
<ind:textfilecontent54_state id="oval:ssg:ste:388" version="1">
<ind:subexpression datatype="int" operation="less than or equal" var_ref="oval:ssg:var:473"/>
</ind:textfilecontent54_state>
<unix:file_state id="oval:ssg:ste:390" version="1">
<unix:user_id datatype="int">0</unix:user_id>
</unix:file_state>
<unix:file_state id="oval:ssg:ste:452" version="1" operator="OR">
<unix:gwrite datatype="boolean">true</unix:gwrite>
<unix:owrite datatype="boolean">true</unix:owrite>
</unix:file_state>
<unix:file_state id="oval:ssg:ste:453" version="1">
<unix:type operation="equals">symbolic link</unix:type>
</unix:file_state>
<ind:textfilecontent54_state id="oval:ssg:ste:397" version="1">
<ind:instance datatype="int">1</ind:instance>
<ind:subexpression datatype="int" operation="greater than or equal" var_ref="oval:ssg:var:474"/>
</ind:textfilecontent54_state>
<ind:variable_state id="oval:ssg:ste:400" version="1">
<ind:value operation="greater than or equal" var_ref="oval:ssg:var:475" datatype="int" var_check="at least one"/>
</ind:variable_state>
<unix:sysctl_state id="oval:ssg:ste:406" version="1">
<unix:value datatype="int" operation="equals">1</unix:value>
</unix:sysctl_state>
<ind:textfilecontent54_state id="oval:ssg:ste:409" version="1">
<ind:instance datatype="int">1</ind:instance>
<ind:subexpression datatype="int" operation="less than or equal" var_ref="oval:ssg:var:476"/>
</ind:textfilecontent54_state>
<unix:password_state id="oval:ssg:ste:413" version="1">
<unix:password>x</unix:password>
</unix:password_state>
<unix:file_state comment="group or other has write privilege" id="oval:ssg:ste:459" version="1" operator="OR">
<unix:gwrite datatype="boolean">true</unix:gwrite>
<unix:owrite datatype="boolean">true</unix:owrite>
</unix:file_state>
<unix:file_state comment="symbolic link" id="oval:ssg:ste:460" version="1">
<unix:type operation="equals">symbolic link</unix:type>
</unix:file_state>
<ind:family_state id="oval:ssg:ste:120" version="1">
<ind:family>unix</ind:family>
</ind:family_state>
<linux:rpminfo_state id="oval:ssg:ste:122" version="1">
<linux:version operation="pattern match">^7.*$</linux:version>
</linux:rpminfo_state>
<linux:rpminfo_state id="oval:ssg:ste:124" version="1">
<linux:version operation="pattern match">^7.*$</linux:version>
</linux:rpminfo_state>
<unix:file_state id="oval:ssg:ste:420" version="1">
<unix:group_id datatype="int">0</unix:group_id>
</unix:file_state>
<ind:variable_state id="oval:ssg:ste:424" version="1">
<ind:value operation="greater than or equal" var_ref="oval:ssg:var:477" datatype="int" var_check="at least one"/>
</ind:variable_state>
<ind:textfilecontent54_state id="oval:ssg:ste:426" version="1">
<ind:instance datatype="int">1</ind:instance>
<ind:subexpression datatype="int" operation="less than or equal" var_ref="oval:ssg:var:478"/>
</ind:textfilecontent54_state>
<ind:textfilecontent54_state id="oval:ssg:ste:435" version="1">
<ind:subexpression operation="equals" var_check="all" var_ref="oval:ssg:var:479"/>
</ind:textfilecontent54_state>
</states>
<variables>
<external_variable comment="External variable for pam_cracklib minclass" datatype="int" id="oval:ssg:var:463" version="1"/>
<local_variable id="oval:ssg:var:441" datatype="int" comment="The value of last PASS_MAX_DAYS directive in /etc/login.defs" version="1">
<regex_capture pattern="PASS_MAX_DAYS\s+(\d+)">
<object_component item_field="subexpression" object_ref="oval:ssg:obj:440"/>
</regex_capture>
</local_variable>
<external_variable comment="Maximum password age" datatype="int" id="oval:ssg:var:464" version="1"/>
<external_variable comment="timeout value" datatype="int" id="oval:ssg:var:465" version="1"/>
<local_variable id="oval:ssg:var:445" datatype="string" comment="The value of last ENCRYPT_METHOD directive in /etc/login.defs" version="1">
<regex_capture pattern="ENCRYPT_METHOD\s+(\w+)">
<object_component item_field="subexpression" object_ref="oval:ssg:obj:444"/>
</regex_capture>
</local_variable>
<external_variable id="oval:ssg:var:466" datatype="int" comment="number of failed login attempts allowed" version="1"/>
<external_variable comment="External variable for pam_cracklib retry" datatype="int" id="oval:ssg:var:467" version="1"/>
<external_variable comment="External variable for pam_cracklib minlen" datatype="int" id="oval:ssg:var:468" version="1"/>
<external_variable comment="external variable for GDM login banner text" datatype="string" id="oval:ssg:var:456" version="1"/>
<external_variable comment="External variable for pam_cracklib ucredit" datatype="int" id="oval:ssg:var:469" version="1"/>
<external_variable comment="number of passwords that should be remembered" datatype="int" id="oval:ssg:var:470" version="1"/>
<external_variable comment="External variable for pam_cracklib ocredit" datatype="int" id="oval:ssg:var:471" version="1"/>
<local_variable id="oval:ssg:var:449" datatype="int" comment="The value of last PASS_WARN_AGE directive in /etc/login.defs" version="1">
<regex_capture pattern="PASS_WARN_AGE\s+(\d+)">
<object_component item_field="subexpression" object_ref="oval:ssg:obj:448"/>
</regex_capture>
</local_variable>
<external_variable comment="password expiration warning age in days" datatype="int" id="oval:ssg:var:472" version="1"/>
<external_variable comment="External variable for pam_cracklib maxrepeat" datatype="int" id="oval:ssg:var:473" version="1"/>
<external_variable comment="External variable for pam_cracklib difok" datatype="int" id="oval:ssg:var:474" version="1"/>
<local_variable id="oval:ssg:var:455" datatype="int" comment="The value of last PASS_MIN_LEN directive in /etc/login.defs" version="1">
<regex_capture pattern="PASS_MIN_LEN\s+(\d+)">
<object_component item_field="subexpression" object_ref="oval:ssg:obj:454"/>
</regex_capture>
</local_variable>
<external_variable comment="Password minimum length" datatype="int" id="oval:ssg:var:475" version="1"/>
<external_variable comment="External variable for pam_cracklib lcredit" datatype="int" id="oval:ssg:var:476" version="1"/>
<local_variable comment="Split the PATH on the : delimiter" datatype="string" id="oval:ssg:var:458" version="1">
<split delimiter=":">
<object_component item_field="value" object_ref="oval:ssg:obj:457"/>
</split>
</local_variable>
<local_variable id="oval:ssg:var:462" datatype="int" comment="The value of last PASS_MIN_DAYS directive in /etc/login.defs" version="1">
<regex_capture pattern="PASS_MIN_DAYS\s+(\d+)">
<object_component item_field="subexpression" object_ref="oval:ssg:obj:461"/>
</regex_capture>
</local_variable>
<external_variable comment="Minimum password age in days" datatype="int" id="oval:ssg:var:477" version="1"/>
<external_variable comment="External variable for pam_cracklib dcredit" datatype="int" id="oval:ssg:var:478" version="1"/>
<external_variable comment="inactivity timeout variable" datatype="string" id="oval:ssg:var:479" version="1"/>
</variables>
</oval_definitions>
</ds:component>
<ds:component id="scap_org.open-scap_comp_ssg-fedora-xccdf-1.2.xml" timestamp="2015-03-17T12:23:35">
<Benchmark xmlns="http://checklists.nist.gov/xccdf/1.2" id="xccdf_org.ssgproject.content_benchmark_FEDORA" resolved="1" xml:lang="en-US">
<status date="2015-03-17">draft</status>
<title xml:lang="en-US">Guide to the Secure Configuration of Fedora</title>
<description xml:lang="en-US">This guide presents a catalog of security-relevant configuration
settings for Fedora operating system formatted in the eXtensible Configuration
Checklist Description Format (XCCDF).
<br xmlns="http://www.w3.org/1999/xhtml"/>
<br xmlns="http://www.w3.org/1999/xhtml"/>
Providing system administrators with such guidance informs them how to securely
configure systems under their control in a variety of network roles. Policy
makers and baseline creators can use this catalog of settings, with its
associated references to higher-level security control catalogs, in order to
assist them in security baseline creation. This guide is a <i xmlns="http://www.w3.org/1999/xhtml">catalog, not a
checklist,</i> and satisfaction of every item is not likely to be possible or
sensible in many operational scenarios. However, the XCCDF format enables
granular selection and adjustment of settings, and their association with OVAL
and OCIL content provides an automated checking capability. Transformations of
this document, and its associated automated checking content, are capable of
providing baselines that meet a diverse set of policy objectives. Some example
XCCDF <i xmlns="http://www.w3.org/1999/xhtml">Profiles</i>, which are selections of items that form checklists and
can be used as baselines, are available with this guide. They can be
processed, in an automated fashion, with tools that support the Security
Content Automation Protocol (SCAP).
</description>
<notice xml:lang="en-US" id="terms_of_use">Do not attempt to implement any of the settings in
this guide without first testing them in a non-operational environment. The
creators of this guidance assume no responsibility whatsoever for its use by
other parties, and makes no guarantees, expressed or implied, about its
quality, reliability, or any other characteristic.</notice>
<front-matter xml:lang="en-US">
<p xmlns="http://www.w3.org/1999/xhtml">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" id="Layer_1" xml:space="preserve" height="140px" viewBox="30 100 330 150" width="350px" version="1.1" y="0px" x="0px" enable-background="new 30 100 330 150">
<g fill="#3A3B3B">
<path d="m197.1 150.3s-10.1-1.2-14.4-1.2c-7.2 0-11.0 2.6-11.0 8.3 0 6.6 3.5 7.7 12.3 9.6 10.1 2.3 14.5 4.7 14.5 13.6 0 11.2-6.1 15.6-16.1 15.6-6.0 0-16.0-1.6-16.0-1.6l0.6-4.7s9.9 1.3 15.1 1.3c7.2 0 10.8-3.1 10.8-10.2 0-5.7-3.0-7.3-11.2-8.9-10.4-2.3-15.7-4.7-15.7-14.4 0-9.8 6.4-13.6 16.3-13.6 6.0 0 15.3 1.5 15.3 1.5l-0.5 4.8z"/>
<path d="m238.7 194.6c-3.6 0.7-9.1 1.5-13.9 1.5-15.1 0-18.5-9.2-18.5-25.9 0-17.1 3.3-26.1 18.5-26.1 5.2 0 10.7 1.0 13.9 1.6l-0.2 4.7c-3.3-0.6-9.2-1.3-13.1-1.3-11.2 0-13.2 6.7-13.2 21.1 0 14.1 1.8 20.8 13.4 20.8 4.1 0 9.5-0.7 13.0-1.3l0.2 4.8z"/>
<path d="m257.5 144.9h12.3l13.9 50.5h-5.6l-3.7-13.0h-21.6l-3.7 13.0h-5.5l13.9-50.5zm-3.4 32.5h19.1l-7.7-27.7h-3.8l-7.7 27.7z"/>
<path d="m297.2 178.4v17.0h-5.6v-50.5h18.5c11.0 0 16.1 5.3 16.1 16.3 0 11.0-5.1 17.2-16.1 17.2h-12.9zm12.8-5.0c7.4 0 10.4-4.5 10.4-12.3 0-7.7-3.1-11.3-10.4-11.3h-12.8v23.6h12.8z"/>
</g>
<g fill="#676767">
<path d="m176.8 211.2s-2.8-0.3-4.0-0.3c-1.5 0-2.2 0.5-2.2 1.4 0 0.9 0.5 1.2 2.8 1.9 2.9 0.9 3.8 1.8 3.8 4.0 0 3.0-2.0 4.3-4.7 4.3-1.9 0-4.5-0.6-4.5-0.6l0.3-2.1s2.7 0.4 4.1 0.4c1.5 0 2.1-0.7 2.1-1.8 0-0.8-0.5-1.2-2.4-1.8-3.1-0.9-4.2-1.9-4.2-4.1 0-2.8 1.9-4.0 4.6-4.0 1.8 0 4.5 0.5 4.5 0.5l-0.2 2.2z"/>
<path d="m180.6 208.7h8.8v2.4h-6.0v3.2h4.8v2.4h-4.9v3.3h6.0v2.4h-8.8v-13.6z"/>
<path d="m201.2 222.1c-0.9 0.2-2.7 0.5-4.0 0.5-4.2 0-5.2-2.3-5.2-7.0 0-5.2 1.2-7.0 5.2-7.0 1.4 0 3.1 0.3 4.0 0.5l-0.1 2.2c-0.9-0.1-2.6-0.3-3.5-0.3-2.1 0-2.8 0.7-2.8 4.6 0 3.7 0.5 4.6 2.8 4.6 0.9 0 2.6-0.2 3.4-0.3l0.1 2.3z"/>
<path d="m209.5 220.2c1.6 0 2.4-0.8 2.4-2.4v-9.1h2.8v9.0c0 3.4-1.8 4.8-5.2 4.8-3.4 0-5.2-1.4-5.2-4.8v-9.0h2.8v9.1c0 1.6 0.8 2.4 2.4 2.4z"/>
<path d="m221.3 217.8v4.6h-2.8v-13.6h5.3c3.1 0 4.8 1.4 4.8 4.5 0 1.9-0.8 3.1-2.0 3.9l1.9 5.2h-3.0l-1.6-4.6h-2.7zm2.5-6.7h-2.5v4.3h2.6c1.4 0 1.9-1.0 1.9-2.2 0-1.3-0.7-2.2-2.0-2.2z"/>
<path d="m231.9 208.7h2.8v13.6h-2.8v-13.6z"/>
<path d="m237.4 208.7h10.0v2.4h-3.6v11.2h-2.8v-11.2h-3.6v-2.4z"/>
<path d="m255.7 222.3h-2.8v-5.5l-4.2-8.1h3.1l2.5 5.4 2.5-5.4h3.1l-4.2 8.1v5.5z"/>
<path d="m273.4 215.1h4.0v7.1s-2.9 0.5-4.6 0.5c-4.4 0-5.6-2.5-5.6-7.0 0-5.0 1.4-7.0 5.5-7.0 2.1 0 4.7 0.6 4.7 0.6l-0.1 2.1s-2.4-0.3-4.2-0.3c-2.4 0-3.1 0.8-3.1 4.6 0 3.6 0.5 4.6 3.0 4.6 0.8 0 1.7-0.1 1.7-0.1v-2.6h-1.2v-2.4z"/>
<path d="m286 220.2c1.6 0 2.4-0.8 2.4-2.4v-9.1h2.8v9.0c0 3.4-1.8 4.8-5.2 4.8s-5.2-1.4-5.2-4.8v-9.0h2.8v9.1c0 1.6 0.8 2.4 2.4 2.4z"/>
<path d="m295.0 208.7h2.8v13.6h-2.8v-13.6z"/>
<path d="m301.8 222.3v-13.6h4.6c4.7 0 5.8 2.0 5.6 6.5 0 4.6-0.9 7.1-5.8 7.1h-4.6zm4.6-11.2h-1.8v8.8h1.8c2.7 0 2.9-1.6 2.9-4.7 0-3.0-0.3-4.1-3.0-4.1z"/>
<path d="m315.5 208.7h8.8v2.4h-6.0v3.2h4.8v2.4h-4.8v3.3h6.0v2.4h-8.8v-13.6z"/>
</g>
<path d="m116.0 204.9h-2.8c-1.5 0-2.8 1.2-2.8 2.7v19.2c0 1.5 1.3 2.7 2.8 2.7h27.9c1.5 0 2.8-1.2 2.8-2.7v-19.2c0-1.5-1.3-2.7-2.8-2.7h-2.8v-8.2c0-6.1-5.0-11.0-11.2-11.0-6.2 0-11.2 4.9-11.2 11.0v8.2zm5.6-8.2c0-3.0 2.5-5.5 5.6-5.4 3.1 0 5.6 2.4 5.6 5.5v8.2h-11.2v-8.2z" fill="#6D0B2B"/>
<g fill="#AD1D3F">
<path d="m106.4 214.7c-16.4 11.4-37.5 7.8-50.0-3.4l11.9-11.7c2.3-1.9 3.4-5.4 1.2-8.8-0.1-0.1-6.7-11.0 2.3-19.8 7.3-7.2 17.8-5.8 23.3-0.3 3.2 3.1 4.9 7.1 4.9 11.4v0.1c0 4.3-1.8 8.5-5.1 11.7-4.0 3.9-9.6 5.4-15.4 4.1-2.1-0.5-4.3 0.8-4.8 2.9-0.5 2.1 0.8 4.2 2.9 4.7 8.4 2.0 16.9-0.3 22.8-6.1 4.9-4.8 7.5-10.9 7.4-17.4-0.0-6.3-2.6-12.3-7.3-16.8-8.2-8.1-23.8-10.3-34.5 0.3-10.7 10.5-6.6 23.8-3.7 28.8l-12.8 12.6c-2.9 2.9-2.3 6.6-0.2 8.7 15.4 15.2 38.7 17.9 56.9 8.2l-0.0-9.1z"/>
<path d="m43.9 188.4c-1.1-7.5-1.1-21.8 11.2-33.9 8.0-7.9 18.5-12.0 29.5-11.7 10.2 0.3 20.1 4.5 27.1 11.4 7.6 7.4 11.8 17.3 11.9 27.8v0.1c1.16-0.3 2.4-0.4 3.6-0.4 1.5 0 2.9 0.2 4.3 0.6 0-0.1 0.0-0.2 0.0-0.3-0.1-12.5-5.2-24.3-14.2-33.2-8.4-8.3-20.2-13.3-32.4-13.7-13.2-0.5-25.8 4.5-35.4 14.0-9.1 8.9-14.0 20.8-14.0 33.3 0 2.4 0.2 4.8 0.5 7.2 0.6 4.0 1.8 8.1 3.7 12.2 0.9 2.0 3.2 2.8 5.2 1.9 2.0-0.9 2.9-3.1 2.0-5.1-1.5-3.3-2.6-6.8-3.1-10.1z"/>
</g>
<circle cy="218.49" cx="127.26" r="3.233" fill="#fff"/>
</svg>
</p>
</front-matter>
<rear-matter xml:lang="en-US">Red Hat and Fedora are either registered
trademarks or trademarks of Red Hat, Inc. in the United States and other
countries. All other names are registered trademarks or trademarks of their
respective companies.</rear-matter>
<platform idref="cpe:/o:fedoraproject:fedora:21"/>
<platform idref="cpe:/o:fedoraproject:fedora:20"/>
<platform idref="cpe:/o:fedoraproject:fedora:19"/>
<version>0.0.4</version>
<model system="urn:xccdf:scoring:default"/>
<Profile id="xccdf_org.ssgproject.content_profile_common">
<title xml:lang="en-US">Common Profile for General-Purpose Fedora Systems</title>
<description xml:lang="en-US">This profile contains items common to general-purpose Fedora installations.</description>
<select idref="xccdf_org.ssgproject.content_rule_disable_prelink" selected="true"/>
<select idref="xccdf_org.ssgproject.content_rule_ensure_gpgcheck_globally_activated" selected="true"/>
<select idref="xccdf_org.ssgproject.content_rule_ensure_gpgcheck_never_disabled" selected="true"/>
<select idref="xccdf_org.ssgproject.content_rule_file_permissions_library_dirs" selected="true"/>
<select idref="xccdf_org.ssgproject.content_rule_file_ownership_library_dirs" selected="true"/>
<select idref="xccdf_org.ssgproject.content_rule_file_permissions_binary_dirs" selected="true"/>
<select idref="xccdf_org.ssgproject.content_rule_file_ownership_binary_dirs" selected="true"/>
<select idref="xccdf_org.ssgproject.content_rule_no_direct_root_logins" selected="true"/>
<select idref="xccdf_org.ssgproject.content_rule_securetty_root_login_console_only" selected="true"/>
<select idref="xccdf_org.ssgproject.content_rule_restrict_serial_port_logins" selected="true"/>
<select idref="xccdf_org.ssgproject.content_rule_no_uidzero_except_root" selected="true"/>
<select idref="xccdf_org.ssgproject.content_rule_no_empty_passwords" selected="true"/>
<select idref="xccdf_org.ssgproject.content_rule_no_hashes_outside_shadow" selected="true"/>
<select idref="xccdf_org.ssgproject.content_rule_no_netrc_files" selected="true"/>
<select idref="xccdf_org.ssgproject.content_rule_accounts_password_minlen_login_defs" selected="true"/>
<select idref="xccdf_org.ssgproject.content_rule_accounts_minimum_age_login_defs" selected="true"/>
<select idref="xccdf_org.ssgproject.content_rule_accounts_maximum_age_login_defs" selected="true"/>
<select idref="xccdf_org.ssgproject.content_rule_accounts_password_warn_age_login_defs" selected="true"/>
<select idref="xccdf_org.ssgproject.content_rule_root_path_no_groupother_writable" selected="true"/>
<select idref="xccdf_org.ssgproject.content_rule_service_ntpd_enabled" selected="true"/>
<select idref="xccdf_org.ssgproject.content_rule_ntpd_specify_remote_server" selected="true"/>
<select idref="xccdf_org.ssgproject.content_rule_sshd_disable_root_login" selected="true"/>
<select idref="xccdf_org.ssgproject.content_rule_sshd_disable_empty_passwords" selected="true"/>
<select idref="xccdf_org.ssgproject.content_rule_sshd_set_idle_timeout" selected="true"/>
<select idref="xccdf_org.ssgproject.content_rule_sshd_set_keepalive" selected="true"/>
<refine-value idref="xccdf_org.ssgproject.content_value_var_accounts_password_minlen_login_defs" selector="12"/>
<refine-value idref="xccdf_org.ssgproject.content_value_var_accounts_minimum_age_login_defs" selector="7"/>
<refine-value idref="xccdf_org.ssgproject.content_value_var_accounts_maximum_age_login_defs" selector="90"/>
<refine-value idref="xccdf_org.ssgproject.content_value_var_accounts_password_warn_age_login_defs" selector="7"/>
<refine-value idref="xccdf_org.ssgproject.content_value_sshd_idle_timeout_value" selector="5_minutes"/>
</Profile>
<Value id="xccdf_org.ssgproject.content_value_conditional_clause" operator="equals" type="string">
<title xml:lang="en-US">A conditional clause for check statements.</title>
<description xml:lang="en-US">A conditional clause for check statements.</description>
<value>This is a placeholder.</value>
</Value>
<Group id="xccdf_org.ssgproject.content_group_intro">
<title xml:lang="en-US">Introduction</title>
<description xml:lang="en-US"><!-- purpose and scope of guidance -->
The purpose of this guidance is to provide security configuration
recommendations and baselines for the Fedora operating system.
Recommended settings for the basic operating system are provided,
as well as for many network services that the system can provide
to other systems.
<!-- audience -->The guide is intended for system administrators. Readers are assumed to
possess basic system administration skills for Unix-like systems, as well
as some familiarity with Fedora's documentation and administration
conventions. Some instructions within this guide are complex.
All directions should be followed completely and with understanding of
their effects in order to avoid serious adverse effects on the system
and its security.
</description>
<Group id="xccdf_org.ssgproject.content_group_general-principles">
<title xml:lang="en-US">General Principles</title>
<description xml:lang="en-US">
The following general principles motivate much of the advice in this
guide and should also influence any configuration decisions that are
not explicitly covered.
</description>
<Group id="xccdf_org.ssgproject.content_group_principle-encrypt-transmitted-data">
<title xml:lang="en-US">Encrypt Transmitted Data Whenever Possible</title>
<description xml:lang="en-US">
Data transmitted over a network, whether wired or wireless, is susceptible
to passive monitoring. Whenever practical solutions for encrypting
such data exist, they should be applied. Even if data is expected to
be transmitted only over a local network, it should still be encrypted.
Encrypting authentication data, such as passwords, is particularly
important. Networks of Fedora machines can and should be configured
so that no unencrypted authentication data is ever transmitted between
machines.
</description>
</Group>
<Group id="xccdf_org.ssgproject.content_group_principle-minimize-software">
<title xml:lang="en-US">Minimize Software to Minimize Vulnerability</title>
<description xml:lang="en-US">
The simplest way to avoid vulnerabilities in software is to avoid
installing that software. On Fedora, the RPM Package Manager (originally
Red Hat Package Manager, abbreviated RPM) allows for careful management of
the set of software packages installed on a system. Installed software
contributes to system vulnerability in several ways. Packages that
include setuid programs may provide local attackers a potential path to
privilege escalation. Packages that include network services may give
this opportunity to network-based attackers. Packages that include
programs which are predictably executed by local users (e.g. after
graphical login) may provide opportunities for trojan horses or other
attack code to be run undetected. The number of software packages
installed on a system can almost always be significantly pruned to include
only the software for which there is an environmental or operational need.
</description>
</Group>
<Group id="xccdf_org.ssgproject.content_group_principle-separate-servers">
<title xml:lang="en-US">Run Different Network Services on Separate Systems</title>
<description xml:lang="en-US">
Whenever possible, a server should be dedicated to serving exactly one
network service. This limits the number of other services that can
be compromised in the event that an attacker is able to successfully
exploit a software flaw in one network service.
</description>
</Group>
<Group id="xccdf_org.ssgproject.content_group_principle-use-security-tools">
<title xml:lang="en-US">Configure Security Tools to Improve System Robustness</title>
<description xml:lang="en-US">
Several tools exist which can be effectively used to improve a system's
resistance to and detection of unknown attacks. These tools can improve
robustness against attack at the cost of relatively little configuration
effort. In particular, this guide recommends and discusses the use of
Iptables for host-based firewalling, SELinux for protection against
vulnerable services, and a logging and auditing infrastructure for
detection of problems.
</description>
</Group>
<Group id="xccdf_org.ssgproject.content_group_principle-least-privilege">
<title xml:lang="en-US">Least Privilege</title>
<description xml:lang="en-US">
Grant the least privilege necessary for user accounts and software to perform tasks.
For example, <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">sudo</xhtml:code> can be implemented to limit authorization to super user
accounts on the system only to designated personnel. Another example is to limit
logins on server systems to only those administrators who need to log into them in
order to perform administration tasks. Using SELinux also follows the principle of
least privilege: SELinux policy can confine software to perform only actions on the
system that are specifically allowed. This can be far more restrictive than the
actions permissible by the traditional Unix permissions model.
</description>
</Group>
</Group>
<Group id="xccdf_org.ssgproject.content_group_how-to-use">
<title xml:lang="en-US">How to Use This Guide</title>
<description xml:lang="en-US">
Readers should heed the following points when using the guide.
</description>
<Group id="xccdf_org.ssgproject.content_group_intro-read-sections-completely">
<title xml:lang="en-US">Read Sections Completely and in Order</title>
<description xml:lang="en-US">
Each section may build on information and recommendations discussed in
prior sections. Each section should be read and understood completely;
instructions should never be blindly applied. Relevant discussion may
occur after instructions for an action.
</description>
</Group>
<Group id="xccdf_org.ssgproject.content_group_intro-test-non-production">
<title xml:lang="en-US">Test in Non-Production Environment</title>
<description xml:lang="en-US">
This guidance should always be tested in a non-production environment
before deployment. This test environment should simulate the setup in
which the system will be deployed as closely as possible.
</description>
</Group>
<Group id="xccdf_org.ssgproject.content_group_intro-root-shell-assumed">
<title xml:lang="en-US">Root Shell Environment Assumed</title>
<description xml:lang="en-US">
Most of the actions listed in this document are written with the
assumption that they will be executed by the root user running the
<xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/bin/bash</xhtml:code> shell. Commands preceded with a hash mark (#)
assume that the administrator will execute the commands as root, i.e.
apply the command via <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">sudo</xhtml:code> whenever possible, or use
<xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">su</xhtml:code> to gain root privileges if <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">sudo</xhtml:code> cannot be
used. Commands which can be executed as a non-root user are are preceded
by a dollar sign ($) prompt.
</description>
</Group>
<Group id="xccdf_org.ssgproject.content_group_intro-formatting-conventions">
<title xml:lang="en-US">Formatting Conventions</title>
<description xml:lang="en-US">
Commands intended for shell execution, as well as configuration file text,
are featured in a <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">monospace font</xhtml:code>. <i xmlns="http://www.w3.org/1999/xhtml">Italics</i> are used
to indicate instances where the system administrator must substitute
the appropriate information into a command or configuration file.
</description>
</Group>
<Group id="xccdf_org.ssgproject.content_group_intro-reboot-required">
<title xml:lang="en-US">Reboot Required</title>
<description xml:lang="en-US">
A system reboot is implicitly required after some actions in order to
complete the reconfiguration of the system. In many cases, the changes
will not take effect until a reboot is performed. In order to ensure
that changes are applied properly and to test functionality, always
reboot the system after applying a set of recommendations from this guide.
</description>
</Group>
</Group>
</Group>
<Group id="xccdf_org.ssgproject.content_group_system">
<title xml:lang="en-US">System Settings</title>
<Group id="xccdf_org.ssgproject.content_group_software">
<title xml:lang="en-US">Installing and Maintaining Software</title>
<description xml:lang="en-US">The following sections contain information on
security-relevant choices during the initial operating system
installation process and the setup of software
updates.</description>
<Group id="xccdf_org.ssgproject.content_group_updating">
<title xml:lang="en-US">Updating Software</title>
<description xml:lang="en-US">The <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">yum</xhtml:code> command line tool is used to install and
update software packages. The system also provides a graphical
software update tool in the <b xmlns="http://www.w3.org/1999/xhtml">System</b> menu, in the <b xmlns="http://www.w3.org/1999/xhtml">Administration</b> submenu,
called <b xmlns="http://www.w3.org/1999/xhtml">Software Update</b>.
<br xmlns="http://www.w3.org/1999/xhtml"/><br xmlns="http://www.w3.org/1999/xhtml"/>
Fedora systems contain an installed software catalog called
the RPM database, which records metadata of installed packages. Tools such as
<xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">yum</xhtml:code> or the graphical <b xmlns="http://www.w3.org/1999/xhtml">Software Update</b> ensure usage of RPM
packages for software installation. This allows for insight into the current
inventory of installed software on the system, and is highly recommended.
</description>
<Rule id="xccdf_org.ssgproject.content_rule_ensure_gpgcheck_globally_activated" selected="false" severity="high">
<title xml:lang="en-US">gpgcheck Enabled In Main Yum Configuration</title>
<description xml:lang="en-US">The <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">gpgcheck</xhtml:code> option should be used to ensure
checking of an RPM package's signature always occurs prior to its
installation. To configure yum to check package signatures before installing
them, ensure the following line appears in <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/yum.conf</xhtml:code> in
the <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">[main]</xhtml:code> section:
<pre xmlns="http://www.w3.org/1999/xhtml">gpgcheck=1</pre>
</description>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">SI-7</reference>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">MA-1(b)</reference>
<reference href="http://iase.disa.mil/stigs/cci/Pages/index.aspx">352</reference>
<reference href="http://iase.disa.mil/stigs/cci/Pages/index.aspx">663</reference>
<rationale xml:lang="en-US">
Ensuring the validity of packages' cryptographic signatures prior to
installation ensures the provenance of the software and
protects against malicious tampering.
</rationale>
<check system="http://oval.mitre.org/XMLSchema/oval-definitions-5">
<check-content-ref name="oval:ssg:def:249" href="ssg-fedora-oval.xml"/>
</check>
<check system="ocil-transitional">
<check-export export-name="GPG checking is not enabled" value-id="xccdf_org.ssgproject.content_value_conditional_clause"/>
<check-content>
To determine whether <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">yum</xhtml:code> is configured to use <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">gpgcheck</xhtml:code>,
inspect <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/yum.conf</xhtml:code> and ensure the following appears in the
<xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">[main]</xhtml:code> section:
<pre xmlns="http://www.w3.org/1999/xhtml">gpgcheck=1</pre>
A value of <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">1</xhtml:code> indicates that <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">gpgcheck</xhtml:code> is enabled. Absence of a
<xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">gpgcheck</xhtml:code> line or a setting of <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">0</xhtml:code> indicates that it is
disabled.
</check-content>
</check>
</Rule>
<Rule id="xccdf_org.ssgproject.content_rule_ensure_gpgcheck_never_disabled" selected="false" severity="high">
<title xml:lang="en-US">gpgcheck Enabled For All Yum Package Repositories</title>
<description xml:lang="en-US">To ensure signature checking is not disabled for
any repos, remove any lines from files in <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/yum.repos.d</xhtml:code> of the form:
<pre xmlns="http://www.w3.org/1999/xhtml">gpgcheck=0</pre>
</description>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">SI-7</reference>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">MA-1(b)</reference>
<reference href="http://iase.disa.mil/stigs/cci/Pages/index.aspx">352</reference>
<reference href="http://iase.disa.mil/stigs/cci/Pages/index.aspx">663</reference>
<rationale xml:lang="en-US">
Ensuring all packages' cryptographic signatures are valid prior to
installation ensures the provenance of the software and
protects against malicious tampering.
</rationale>
<check system="http://oval.mitre.org/XMLSchema/oval-definitions-5">
<check-content-ref name="oval:ssg:def:195" href="ssg-fedora-oval.xml"/>
</check>
<check system="ocil-transitional">
<check-export export-name="GPG checking is disabled" value-id="xccdf_org.ssgproject.content_value_conditional_clause"/>
<check-content>
To determine whether <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">yum</xhtml:code> has been configured to disable
<xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">gpgcheck</xhtml:code> for any repos, inspect all files in
<xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/yum.repos.d</xhtml:code> and ensure the following does not appear in any
sections:
<pre xmlns="http://www.w3.org/1999/xhtml">gpgcheck=0</pre>
A value of <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">0</xhtml:code> indicates that <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">gpgcheck</xhtml:code> has been disabled for that repo.
</check-content>
</check>
</Rule>
</Group>
<Group id="xccdf_org.ssgproject.content_group_integrity">
<title xml:lang="en-US">Software Integrity Checking</title>
<description xml:lang="en-US">
Both the AIDE (Advanced Intrusion Detection Environment)
software and the RPM package management system provide
mechanisms for verifying the integrity of installed software.
AIDE uses snapshots of file metadata (such as hashes) and compares these
to current system files in order to detect changes.
The RPM package management system can conduct integrity
checks by comparing information in its metadata database with
files installed on the system.
<br xmlns="http://www.w3.org/1999/xhtml"/><br xmlns="http://www.w3.org/1999/xhtml"/>
Integrity checking cannot <i xmlns="http://www.w3.org/1999/xhtml">prevent</i> intrusions,
but can detect that they have occurred. Requirements
for software integrity checking may be highly dependent on
the environment in which the system will be used. Snapshot-based
approaches such as AIDE may induce considerable overhead
in the presence of frequent software updates.
</description>
<Group id="xccdf_org.ssgproject.content_group_aide">
<title xml:lang="en-US">Verify Integrity with AIDE</title>
<description xml:lang="en-US">AIDE conducts integrity checks by comparing information about
files with previously-gathered information. Ideally, the AIDE database is
created immediately after initial system configuration, and then again after any
software update. AIDE is highly configurable, with further configuration
information located in <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/usr/share/doc/aide-<i xmlns="http://www.w3.org/1999/xhtml">VERSION</i></xhtml:code>.
</description>
<Rule id="xccdf_org.ssgproject.content_rule_package_aide_installed" selected="false" severity="medium">
<title xml:lang="en-US">Install AIDE</title>
<description xml:lang="en-US">
Install the AIDE package with the command:
<pre xmlns="http://www.w3.org/1999/xhtml">$ sudo yum install aide</pre>
</description>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">CM-3(d)</reference>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">CM-3(e)</reference>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">CM-6(d)</reference>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">CM-6(3)</reference>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">SC-28</reference>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">SI-7</reference>
<reference href="http://iase.disa.mil/stigs/cci/Pages/index.aspx">1069</reference>
<reference href="test_attestation">
<dc:contributor xmlns:dc="http://purl.org/dc/elements/1.1/">DS</dc:contributor>
<dc:date xmlns:dc="http://purl.org/dc/elements/1.1/">20121024</dc:date>
</reference>
<rationale xml:lang="en-US">
The AIDE package must be installed if it is to be available for integrity checking.
</rationale>
<check system="ocil-transitional">
<check-export export-name="the package is not installed" value-id="xccdf_org.ssgproject.content_value_conditional_clause"/>
<check-content>
Run the following command to determine if the <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">aide</xhtml:code> package is installed:
<xhtml:pre xmlns:xhtml="http://www.w3.org/1999/xhtml"># rpm -q aide</xhtml:pre>
</check-content>
</check>
</Rule>
<Rule id="xccdf_org.ssgproject.content_rule_disable_prelink" selected="false" severity="low">
<title xml:lang="en-US">Disable Prelinking</title>
<description xml:lang="en-US">
The prelinking feature changes binaries in an attempt to decrease their startup
time. In order to disable it, change or add the following line inside the file
<xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/sysconfig/prelink</xhtml:code>:
<pre xmlns="http://www.w3.org/1999/xhtml">PRELINKING=no</pre>
Next, run the following command to return binaries to a normal, non-prelinked state:
<pre xmlns="http://www.w3.org/1999/xhtml">$ sudo /usr/sbin/prelink -ua</pre>
</description>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">CM-6(d)</reference>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">CM-6(3)</reference>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">SC-28</reference>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">SI-7</reference>
<rationale xml:lang="en-US">
The prelinking feature can interfere with the operation
of AIDE, because it changes binaries.
</rationale>
<fixtext reboot="1">asdasdasd</fixtext>
<fixtext>asdasdsdfasdfasd</fixtext>
<fixtext>asdfasdfsdasdasd</fixtext>
<fix system="urn:xccdf:fix:script:sh" reboot="true">#
# Disable prelinking altogether
#
if grep -q ^PRELINKING /etc/sysconfig/prelink
then
sed -i 's/PRELINKING.*/PRELINKING=no/g' /etc/sysconfig/prelink
else
echo -e "\n# Set PRELINKING=no per security requirements" >> /etc/sysconfig/prelink
echo "PRELINKING=no" >> /etc/sysconfig/prelink
fi
#
# Undo previous prelink changes to binaries
#
/usr/sbin/prelink -ua
</fix>
<fix system="urn:xccdf:fix:script:sh">#
# Disable presdfasdfasdflinking altogether
#
if grep -q ^PRELINKING /etc/sysconfig/prelink
then
sed -i 's/PRELINKING.*/PRELINKING=no/g' /etc/sysconfig/prelink
else
echo -e "\n# Set PRELINKING=no per security requirements" >> /etc/sysconfig/prelink
echo "PRELINKING=no" >> /etc/sysconfig/prelink
fi
#
# Undo previous prelink changes to binaries
#
/usr/sbin/prelink -ua
</fix>
<check system="http://oval.mitre.org/XMLSchema/oval-definitions-5">
<check-content-ref name="oval:ssg:def:151" href="ssg-fedora-oval.xml"/>
</check>
</Rule>
<Rule id="xccdf_org.ssgproject.content_rule_aide_build_database" selected="false" severity="medium">
<title xml:lang="en-US">Build and Test AIDE Database</title>
<description xml:lang="en-US">Run the following command to generate a new database:
<pre xmlns="http://www.w3.org/1999/xhtml"># /usr/sbin/aide --init</pre>
By default, the database will be written to the file <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/var/lib/aide/aide.db.new.gz</xhtml:code>.
Storing the database, the configuration file <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/aide.conf</xhtml:code>, and the binary
<xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/usr/sbin/aide</xhtml:code> (or hashes of these files), in a secure location (such as on read-only media) provides additional assurance about their integrity.
The newly-generated database can be installed as follows:
<pre xmlns="http://www.w3.org/1999/xhtml"># cp /var/lib/aide/aide.db.new.gz /var/lib/aide/aide.db.gz</pre>
To initiate a manual check, run the following command:
<pre xmlns="http://www.w3.org/1999/xhtml"># /usr/sbin/aide --check</pre>
If this check produces any unexpected output, investigate.
</description>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">CM-3(d)</reference>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">CM-3(e)</reference>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">CM-6(d)</reference>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">CM-6(3)</reference>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">SC-28</reference>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">SI-7</reference>
<rationale xml:lang="en-US">
For AIDE to be effective, an initial database of "known-good" information about files
must be captured and it should be able to be verified against the installed files.
</rationale>
</Rule>
<Rule id="xccdf_org.ssgproject.content_rule_aide_periodic_cron_checking" selected="false" severity="medium">
<title xml:lang="en-US">Configure Periodic Execution of AIDE</title>
<description xml:lang="en-US">
To implement a daily execution of AIDE at 4:05am using cron, add the following line to <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/crontab</xhtml:code>:
<pre xmlns="http://www.w3.org/1999/xhtml">05 4 * * * root /usr/sbin/aide --check</pre>
AIDE can be executed periodically through other means; this is merely one example.
</description>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">CM-3(d)</reference>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">CM-3(e)</reference>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">CM-6(d)</reference>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">CM-6(3)</reference>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">SC-28</reference>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">SI-7</reference>
<reference href="http://iase.disa.mil/stigs/cci/Pages/index.aspx">374</reference>
<reference href="http://iase.disa.mil/stigs/cci/Pages/index.aspx">416</reference>
<reference href="http://iase.disa.mil/stigs/cci/Pages/index.aspx">1069</reference>
<reference href="http://iase.disa.mil/stigs/cci/Pages/index.aspx">1263</reference>
<reference href="http://iase.disa.mil/stigs/cci/Pages/index.aspx">1297</reference>
<reference href="http://iase.disa.mil/stigs/cci/Pages/index.aspx">1589</reference>
<rationale xml:lang="en-US">
By default, AIDE does not install itself for periodic execution. Periodically
running AIDE is necessary to reveal unexpected changes in installed files.
</rationale>
<check system="ocil-transitional">
<check-export export-name="there is no output" value-id="xccdf_org.ssgproject.content_value_conditional_clause"/>
<check-content>
To determine that periodic AIDE execution has been scheduled, run the following command:
<pre xmlns="http://www.w3.org/1999/xhtml"># grep aide /etc/crontab</pre>
</check-content>
</check>
</Rule>
</Group>
<Group id="xccdf_org.ssgproject.content_group_rpm_verification">
<title xml:lang="en-US">Verify Integrity with RPM</title>
<description xml:lang="en-US">The RPM package management system includes the ability
to verify the integrity of installed packages by comparing the
installed files with information about the files taken from the
package metadata stored in the RPM database. Although an attacker
could corrupt the RPM database (analogous to attacking the AIDE
database as described above), this check can still reveal
modification of important files. To list which files on the system differ from what is expected by the RPM database:
<pre xmlns="http://www.w3.org/1999/xhtml"># rpm -qVa</pre>
See the man page for <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">rpm</xhtml:code> to see a complete explanation of each column.
</description>
<Rule id="xccdf_org.ssgproject.content_rule_rpm_verify_permissions" selected="false" severity="low">
<title xml:lang="en-US">Verify and Correct File Permissions with RPM</title>
<description xml:lang="en-US">
The RPM package management system can check file access
permissions of installed software packages, including many that are
important to system security.
After locating a file with incorrect permissions, run the following command to determine which package owns it:
<pre xmlns="http://www.w3.org/1999/xhtml"># rpm -qf <i>FILENAME</i></pre>
Next, run the following command to reset its permissions to
the correct values:
<pre xmlns="http://www.w3.org/1999/xhtml"># rpm --setperms <i>PACKAGENAME</i></pre>
</description>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">AC-6</reference>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">CM-6(d)</reference>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">CM-6(3)</reference>
<reference href="http://iase.disa.mil/stigs/cci/Pages/index.aspx">1493</reference>
<reference href="http://iase.disa.mil/stigs/cci/Pages/index.aspx">1494</reference>
<reference href="http://iase.disa.mil/stigs/cci/Pages/index.aspx">1495</reference>
<rationale xml:lang="en-US">
Permissions on system binaries and configuration files that are too generous
could allow an unauthorized user to gain privileges that they should not have.
The permissions set by the vendor should be maintained. Any deviations from
this baseline should be investigated.</rationale>
<check system="ocil-transitional">
<check-export export-name="there is output" value-id="xccdf_org.ssgproject.content_value_conditional_clause"/>
<check-content>
The following command will list which files on the system have permissions different from what
is expected by the RPM database:
<pre xmlns="http://www.w3.org/1999/xhtml"># rpm -Va | grep '^.M'</pre>
</check-content>
</check>
</Rule>
<Rule id="xccdf_org.ssgproject.content_rule_rpm_verify_hashes" selected="false" severity="low">
<title xml:lang="en-US">Verify File Hashes with RPM</title>
<description xml:lang="en-US">The RPM package management system can check the hashes of
installed software packages, including many that are important to system
security. Run the following command to list which files on the system
have hashes that differ from what is expected by the RPM database:
<pre xmlns="http://www.w3.org/1999/xhtml"># rpm -Va | grep '^..5'</pre>
A "c" in the second column indicates that a file is a configuration file, which
may appropriately be expected to change. If the file was not expected to
change, investigate the cause of the change using audit logs or other means.
The package can then be reinstalled to restore the file.
Run the following command to determine which package owns the file:
<pre xmlns="http://www.w3.org/1999/xhtml"># rpm -qf <i>FILENAME</i></pre>
The package can be reinstalled from a yum repository using the command:
<pre xmlns="http://www.w3.org/1999/xhtml">yum reinstall <i>PACKAGENAME</i></pre>
Alternatively, the package can be reinstalled from trusted media using the command:
<pre xmlns="http://www.w3.org/1999/xhtml">rpm -Uvh <i>PACKAGENAME</i></pre>
</description>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">CM-6(d)</reference>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">CM-6(3)</reference>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">SI-7</reference>
<reference href="http://iase.disa.mil/stigs/cci/Pages/index.aspx">1496</reference>
<rationale xml:lang="en-US">
The hashes of important files like system executables should match the
information given by the RPM database. Executables with erroneous hashes could
be a sign of nefarious activity on the system.</rationale>
<check system="ocil-transitional">
<check-export export-name="there is output" value-id="xccdf_org.ssgproject.content_value_conditional_clause"/>
<check-content> The following command will list which files on the system
have file hashes different from what is expected by the RPM database.
<pre xmlns="http://www.w3.org/1999/xhtml"># rpm -Va | awk '$1 ~ /..5/ && $2 != "c"'</pre>
</check-content>
</check>
</Rule>
</Group>
<Group id="xccdf_org.ssgproject.content_group_additional_security_software">
<title xml:lang="en-US">Additional Security Software</title>
<description xml:lang="en-US">
Additional security software that is not provided or supported
by Red Hat can be installed to provide complementary or duplicative
security capabilities to those provided by the base platform. Add-on
software may not be appropriate for some specialized systems.
</description>
<Rule id="xccdf_org.ssgproject.content_rule_install_hids" selected="false" severity="high">
<title xml:lang="en-US">Install Intrusion Detection Software</title>
<description xml:lang="en-US">
The Red Hat platform includes a sophisticated auditing system
and SELinux, which provide host-based intrusion detection capabilities.
</description>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">SC-7</reference>
<reference href="http://iase.disa.mil/stigs/cci/Pages/index.aspx">1263</reference>
<rationale xml:lang="en-US">
Host-based intrusion detection tools provide a system-level defense when an
intruder gains access to a system or network.
</rationale>
<check system="ocil-transitional">
<check-export export-name="no host-based intrusion detection tools are installed" value-id="xccdf_org.ssgproject.content_value_conditional_clause"/>
<check-content>
Inspect the system to determine if intrusion detection software has been installed.
Verify this intrusion detection software is active.
</check-content>
</check>
</Rule>
<Rule id="xccdf_org.ssgproject.content_rule_install_antivirus" selected="false" severity="low">
<title xml:lang="en-US">Install Virus Scanning Software</title>
<description xml:lang="en-US">
Install virus scanning software, which uses signatures to search for the
presence of viruses on the filesystem.
The McAfee VirusScan Enterprise for Linux virus scanning tool is provided for DoD systems.
Ensure virus definition files are no older than 7 days, or their last release.
<!-- need info here on where DoD admins can go to get this -->
Configure the virus scanning software to perform scans dynamically on all
accessed files. If this is not possible, configure the
system to scan all altered files on the system on a daily
basis. If the system processes inbound SMTP mail, configure the virus scanner
to scan all received mail.
<!-- what's the basis for the IAO language? would not failure of a check
imply a discussion, for every check in this document,
with the IAO (or SSO or ISSO or ISSM or whatever is the right acronym in your
particular neighborhood) should occur? -->
</description>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">SC-28</reference>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">SI-3</reference>
<reference href="http://iase.disa.mil/stigs/cci/Pages/index.aspx">1239</reference>
<reference href="http://iase.disa.mil/stigs/cci/Pages/index.aspx">1668</reference>
<rationale xml:lang="en-US">
Virus scanning software can be used to detect if a system has been compromised by
computer viruses, as well as to limit their spread to other systems.
</rationale>
<check system="http://oval.mitre.org/XMLSchema/oval-definitions-5">
<check-content-ref name="oval:ssg:def:188" href="ssg-fedora-oval.xml"/>
</check>
<check system="ocil-transitional">
<check-export export-name="virus scanning software does not run continuously, or at least daily, or has signatures that are out of date" value-id="xccdf_org.ssgproject.content_value_conditional_clause"/>
<check-content>
Inspect the system for a cron job or system service which executes
a virus scanning tool regularly.
<br xmlns="http://www.w3.org/1999/xhtml"/>
<!-- this should be handled as DoD-specific text in a future revision -->
To verify the McAfee VSEL system service is operational,
run the following command:
<pre xmlns="http://www.w3.org/1999/xhtml"># /etc/init.d/nails status</pre>
<br xmlns="http://www.w3.org/1999/xhtml"/>
To check on the age of uvscan virus definition files, run the following command:
<pre xmlns="http://www.w3.org/1999/xhtml"># cd /opt/NAI/LinuxShield/engine/dat
# ls -la avvscan.dat avvnames.dat avvclean.dat</pre>
</check-content>
</check>
</Rule>
</Group>
</Group>
</Group>
<Group id="xccdf_org.ssgproject.content_group_permissions">
<title xml:lang="en-US">File Permissions and Masks</title>
<description xml:lang="en-US">Traditional Unix security relies heavily on file and
directory permissions to prevent unauthorized users from reading or
modifying files to which they should not have access.
</description>
<Group id="xccdf_org.ssgproject.content_group_mounting">
<title xml:lang="en-US">Restrict Dynamic Mounting and Unmounting of
Filesystems</title>
<description xml:lang="en-US">Linux includes a number of facilities for the automated addition
and removal of filesystems on a running system. These facilities may be
necessary in many environments, but this capability also carries some risk -- whether direct
risk from allowing users to introduce arbitrary filesystems,
or risk that software flaws in the automated mount facility itself could
allow an attacker to compromise the system.
<br xmlns="http://www.w3.org/1999/xhtml"/><br xmlns="http://www.w3.org/1999/xhtml"/>
This command can be used to list the types of filesystems that are
available to the currently executing kernel:
<pre xmlns="http://www.w3.org/1999/xhtml">$ find /lib/modules/`uname -r`/kernel/fs -type f -name '*.ko'</pre>
If these filesystems are not required then they can be explicitly disabled
in a configuratio file in <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/modprobe.d</xhtml:code>.
</description>
<Rule id="xccdf_org.ssgproject.content_rule_kernel_module_usb-storage_disabled" selected="false" severity="low">
<title xml:lang="en-US">Disable Modprobe Loading of USB Storage Driver</title>
<description xml:lang="en-US">
To prevent USB storage devices from being used, configure the kernel module loading system
to prevent automatic loading of the USB storage driver.
To configure the system to prevent the <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">usb-storage</xhtml:code>
kernel module from being loaded, add the following line to a file in the directory <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/modprobe.d</xhtml:code>:
<xhtml:pre xmlns:xhtml="http://www.w3.org/1999/xhtml" xml:space="preserve">install usb-storage /bin/false</xhtml:pre>
This will prevent the <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">modprobe</xhtml:code> program from loading the <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">usb-storage</xhtml:code>
module, but will not prevent an administrator (or another program) from using the
<xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">insmod</xhtml:code> program to load the module manually.</description>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">AC-19(a)</reference>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">AC-19(d)</reference>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">AC-19(e)</reference>
<reference href="http://iase.disa.mil/stigs/cci/Pages/index.aspx">1250</reference>
<reference href="http://iase.disa.mil/stigs/cci/Pages/index.aspx">85</reference>
<rationale xml:lang="en-US">USB storage devices such as thumb drives can be used to introduce
malicious software.</rationale>
<check system="ocil-transitional">
<check-export export-name="no line is returned" value-id="xccdf_org.ssgproject.content_value_conditional_clause"/>
<check-content>
If the system is configured to prevent the loading of the
<xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">usb-storage</xhtml:code> kernel module,
it will contain lines inside any file in <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/modprobe.d</xhtml:code> or the deprecated<xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/modprobe.conf</xhtml:code>.
These lines instruct the module loading system to run another program (such as
<xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/bin/false</xhtml:code>) upon a module <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">install</xhtml:code> event.
Run the following command to search for such lines in all files in <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/modprobe.d</xhtml:code>
and the deprecated <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/modprobe.conf</xhtml:code>:
<xhtml:pre xmlns:xhtml="http://www.w3.org/1999/xhtml" xml:space="preserve">$ grep -r usb-storage /etc/modprobe.conf /etc/modprobe.d</xhtml:pre>
</check-content>
</check>
</Rule>
<Rule id="xccdf_org.ssgproject.content_rule_bootloader_nousb_argument" selected="false" severity="low">
<title xml:lang="en-US">Disable Kernel Support for USB via Bootloader Configuration</title>
<description xml:lang="en-US">
All USB support can be disabled by adding the <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">nousb</xhtml:code>
argument to the kernel's boot loader configuration. To do so,
append "nousb" to the kernel line in <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/grub.conf</xhtml:code> as shown:
<pre xmlns="http://www.w3.org/1999/xhtml">kernel /vmlinuz-<i>VERSION</i> ro vga=ext root=/dev/VolGroup00/LogVol00 rhgb quiet nousb</pre>
<i xmlns="http://www.w3.org/1999/xhtml"><b>WARNING:</b> Disabling all kernel support for USB will cause problems for
systems with USB-based keyboards, mice, or printers. This configuration is
infeasible for systems which require USB devices, which is common.</i></description>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">AC-19(a)</reference>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">AC-19(d)</reference>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">AC-19(e)</reference>
<reference href="http://iase.disa.mil/stigs/cci/Pages/index.aspx">1250</reference>
<rationale xml:lang="en-US">Disabling the USB subsystem within the Linux kernel at system boot will
protect against potentially malicious USB devices, although it is only practical
in specialized systems.
</rationale>
</Rule>
<Rule id="xccdf_org.ssgproject.content_rule_bios_disable_usb_boot" selected="false" severity="low">
<title xml:lang="en-US">Disable Booting from USB Devices in Boot Firmware</title>
<description xml:lang="en-US">Configure the system boot firmware (historically called BIOS on PC
systems) to disallow booting from USB drives.
</description>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">AC-19(a)</reference>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">AC-19(d)</reference>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">AC-19(e)</reference>
<reference href="http://iase.disa.mil/stigs/cci/Pages/index.aspx">1250</reference>
<rationale xml:lang="en-US">Booting a system from a USB device would allow an attacker to
circumvent any security measures provided by the operating system. Attackers
could mount partitions and modify the configuration of the OS.</rationale>
</Rule>
<Rule id="xccdf_org.ssgproject.content_rule_bios_assign_password" selected="false" severity="low">
<title xml:lang="en-US">Assign Password to Prevent Changes to Boot Firmware Configuration</title>
<description xml:lang="en-US">Assign a password to the system boot firmware (historically called BIOS on PC
systems) to require a password for any configuration changes.
</description>
<rationale xml:lang="en-US">Assigning a password to the system boot firmware prevents anyone
with physical access from configuring the system to boot
from local media and circumvent the operating system's access controls.
For systems in physically secure locations, such as
a data center or Sensitive Compartmented Information Facility (SCIF), this risk must be weighed
against the risk of administrative personnel being unable to conduct recovery operations in
a timely fashion.
</rationale>
</Rule>
<Rule id="xccdf_org.ssgproject.content_rule_service_autofs_disabled" selected="false" severity="low">
<title xml:lang="en-US">Disable the Automounter</title>
<description xml:lang="en-US">The <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">autofs</xhtml:code> daemon mounts and unmounts filesystems, such as user
home directories shared via NFS, on demand. In addition, autofs can be used to handle
removable media, and the default configuration provides the cdrom device as <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/misc/cd</xhtml:code>.
However, this method of providing access to removable media is not common, so autofs
can almost always be disabled if NFS is not in use. Even if NFS is required, it may be
possible to configure filesystem mounts statically by editing <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/fstab</xhtml:code>
rather than relying on the automounter.
<br xmlns="http://www.w3.org/1999/xhtml"/><br xmlns="http://www.w3.org/1999/xhtml"/>
The <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">autofs</xhtml:code> service can be disabled with the following command:
<xhtml:pre xmlns:xhtml="http://www.w3.org/1999/xhtml"># systemctl disable autofs.service</xhtml:pre>
</description>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">AC-19(a)</reference>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">AC-19(d)</reference>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">AC-19(e)</reference>
<reference href="http://iase.disa.mil/stigs/cci/Pages/index.aspx">1250</reference>
<reference href="http://iase.disa.mil/stigs/cci/Pages/index.aspx">85</reference>
<rationale xml:lang="en-US">Disabling the automounter permits the administrator to
statically control filesystem mounting through <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/fstab</xhtml:code>.
</rationale>
<check system="ocil-transitional">
<check-export export-name="the service is running" value-id="xccdf_org.ssgproject.content_value_conditional_clause"/>
<check-content>
To check that the <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">autofs</xhtml:code> service is disabled in system boot configuration, run the following command:
<xhtml:pre xmlns:xhtml="http://www.w3.org/1999/xhtml"># chkconfig <xhtml:code>autofs</xhtml:code> --list</xhtml:pre>
Output should indicate the <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">autofs</xhtml:code> service has either not been installed,
or has been disabled at all runlevels, as shown in the example below:
<xhtml:pre xmlns:xhtml="http://www.w3.org/1999/xhtml"># chkconfig <xhtml:code>autofs</xhtml:code> --list
<xhtml:code>autofs</xhtml:code> 0:off 1:off 2:off 3:off 4:off 5:off 6:off</xhtml:pre>
Run the following command to verify <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">autofs</xhtml:code> is disabled through current runtime configuration:
<xhtml:pre xmlns:xhtml="http://www.w3.org/1999/xhtml"># service autofs status</xhtml:pre>
If the service is disabled the command will return the following output:
<xhtml:pre xmlns:xhtml="http://www.w3.org/1999/xhtml">autofs is stopped</xhtml:pre>
</check-content>
</check>
</Rule>
<Rule id="xccdf_org.ssgproject.content_rule_dconf_gnome_disable_automount" selected="false" severity="low">
<title xml:lang="en-US">Disable GNOME3 Automounting</title>
<description xml:lang="en-US">The system's default desktop environment, GNOME3, will mount
devices and removable media (such as DVDs, CDs and USB flash drives) whenever
they are inserted into the system. To disable automount and autorun within GNOME3,
the <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">automount</xhtml:code>, <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">automount-open</xhtml:code>, and <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">autorun-never</xhtml:code> settings must be set
under an appropriate configuration file(s) in the <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/dconf/db/local.d</xhtml:code> directory
and locked in <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/dconf/db/local.d/locks</xhtml:code> directory to prevent user modification.
After the settings have been set, run <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">dconf update</xhtml:code>.
</description>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">AC-19(a)</reference>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">AC-19(d)</reference>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">AC-19(e)</reference>
<rationale xml:lang="en-US">Disabling automatic mounting in GNOME3 can prevent
the introduction of malware via removable media.
It will, however, also prevent desktop users from legitimate use
of removable media.
</rationale>
<check system="http://oval.mitre.org/XMLSchema/oval-definitions-5">
<check-content-ref name="oval:ssg:def:217" href="ssg-fedora-oval.xml"/>
</check>
<check system="ocil-transitional">
<check-export export-name="GNOME automounting is not disabled" value-id="xccdf_org.ssgproject.content_value_conditional_clause"/>
<check-content>
These settings can be verified by running the following:
<pre xmlns="http://www.w3.org/1999/xhtml">$ gsettings get org.gnome.desktop.media-handling automount
$ gsettings get org.gnome.desktop.media-handling automount-open
$ gsettings get org.gnome.desktop.media-handling autorun-never</pre>
If properly configured, the output for <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">automount</xhtml:code> should be <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">false</xhtml:code>.
If properly configured, the output for <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">automount-open</xhtml:code>should be <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">false</xhtml:code>.
If properly configured, the output for <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">autorun-never</xhtml:code> should be <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">true</xhtml:code>.
To ensure that users cannot enable automount and autorun in GNOME3, run the following:
<pre xmlns="http://www.w3.org/1999/xhtml">$ grep 'automount\|autorun' /etc/dconf/db/local.d/locks/*</pre>
If properly configured, the output for <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">automount</xhtml:code> should be <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/org/gnome/desktop/media-handling/automount</xhtml:code>
If properly configured, the output for <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">automount-open</xhtml:code> should be <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/org/gnome/desktop/media-handling/auto-open</xhtml:code>
If properly configured, the output for <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">autorun-never</xhtml:code> should be <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/org/gnome/desktop/media-handling/autorun-never</xhtml:code>
</check-content>
</check>
</Rule>
<Rule id="xccdf_org.ssgproject.content_rule_kernel_module_cramfs_disabled" selected="false" severity="low">
<title xml:lang="en-US">Disable Mounting of cramfs</title>
<description xml:lang="en-US">
To configure the system to prevent the <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">cramfs</xhtml:code>
kernel module from being loaded, add the following line to a file in the directory <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/modprobe.d</xhtml:code>:
<xhtml:pre xmlns:xhtml="http://www.w3.org/1999/xhtml" xml:space="preserve">install cramfs /bin/false</xhtml:pre>
This effectively prevents usage of this uncommon filesystem.
</description>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">CM-7</reference>
<rationale xml:lang="en-US">Linux kernel modules which implement filesystems that are not needed by the
local system should be disabled.</rationale>
</Rule>
<Rule id="xccdf_org.ssgproject.content_rule_kernel_module_freevxfs_disabled" selected="false" severity="low">
<title xml:lang="en-US">Disable Mounting of freevxfs</title>
<description xml:lang="en-US">
To configure the system to prevent the <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">freevxfs</xhtml:code>
kernel module from being loaded, add the following line to a file in the directory <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/modprobe.d</xhtml:code>:
<xhtml:pre xmlns:xhtml="http://www.w3.org/1999/xhtml" xml:space="preserve">install freevxfs /bin/false</xhtml:pre>
This effectively prevents usage of this uncommon filesystem.
</description>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">CM-7</reference>
<rationale xml:lang="en-US">Linux kernel modules which implement filesystems that are not needed by the
local system should be disabled.</rationale>
</Rule>
<Rule id="xccdf_org.ssgproject.content_rule_kernel_module_jffs2_disabled" selected="false" severity="low">
<title xml:lang="en-US">Disable Mounting of jffs2</title>
<description xml:lang="en-US">
To configure the system to prevent the <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">jffs2</xhtml:code>
kernel module from being loaded, add the following line to a file in the directory <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/modprobe.d</xhtml:code>:
<xhtml:pre xmlns:xhtml="http://www.w3.org/1999/xhtml" xml:space="preserve">install jffs2 /bin/false</xhtml:pre>
This effectively prevents usage of this uncommon filesystem.
</description>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">CM-7</reference>
<rationale xml:lang="en-US">Linux kernel modules which implement filesystems that are not needed by the
local system should be disabled.</rationale>
</Rule>
<Rule id="xccdf_org.ssgproject.content_rule_kernel_module_hfs_disabled" selected="false" severity="low">
<title xml:lang="en-US">Disable Mounting of hfs</title>
<description xml:lang="en-US">
To configure the system to prevent the <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">hfs</xhtml:code>
kernel module from being loaded, add the following line to a file in the directory <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/modprobe.d</xhtml:code>:
<xhtml:pre xmlns:xhtml="http://www.w3.org/1999/xhtml" xml:space="preserve">install hfs /bin/false</xhtml:pre>
This effectively prevents usage of this uncommon filesystem.
</description>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">CM-7</reference>
<rationale xml:lang="en-US">Linux kernel modules which implement filesystems that are not needed by the
local system should be disabled.</rationale>
</Rule>
<Rule id="xccdf_org.ssgproject.content_rule_kernel_module_hfsplus_disabled" selected="false" severity="low">
<title xml:lang="en-US">Disable Mounting of hfsplus</title>
<description xml:lang="en-US">
To configure the system to prevent the <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">hfsplus</xhtml:code>
kernel module from being loaded, add the following line to a file in the directory <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/modprobe.d</xhtml:code>:
<xhtml:pre xmlns:xhtml="http://www.w3.org/1999/xhtml" xml:space="preserve">install hfsplus /bin/false</xhtml:pre>
This effectively prevents usage of this uncommon filesystem.
</description>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">CM-7</reference>
<rationale xml:lang="en-US">Linux kernel modules which implement filesystems that are not needed by the
local system should be disabled.</rationale>
</Rule>
<Rule id="xccdf_org.ssgproject.content_rule_kernel_module_squashfs_disabled" selected="false" severity="low">
<title xml:lang="en-US">Disable Mounting of squashfs</title>
<description xml:lang="en-US">
To configure the system to prevent the <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">squashfs</xhtml:code>
kernel module from being loaded, add the following line to a file in the directory <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/modprobe.d</xhtml:code>:
<xhtml:pre xmlns:xhtml="http://www.w3.org/1999/xhtml" xml:space="preserve">install squashfs /bin/false</xhtml:pre>
This effectively prevents usage of this uncommon filesystem.
</description>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">CM-7</reference>
<rationale xml:lang="en-US">Linux kernel modules which implement filesystems that are not needed by the
local system should be disabled.</rationale>
</Rule>
<Rule id="xccdf_org.ssgproject.content_rule_kernel_module_udf_disabled" selected="false" severity="low">
<title xml:lang="en-US">Disable Mounting of udf</title>
<description xml:lang="en-US">
To configure the system to prevent the <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">udf</xhtml:code>
kernel module from being loaded, add the following line to a file in the directory <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/modprobe.d</xhtml:code>:
<xhtml:pre xmlns:xhtml="http://www.w3.org/1999/xhtml" xml:space="preserve">install udf /bin/false</xhtml:pre>
This effectively prevents usage of this uncommon filesystem.
</description>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">CM-7</reference>
<rationale xml:lang="en-US">Linux kernel modules which implement filesystems that are not needed by the
local system should be disabled.</rationale>
</Rule>
<Rule id="xccdf_org.ssgproject.content_rule_dconf_gnome_disable_thumbnailers" selected="false" severity="low">
<title xml:lang="en-US">Disable All GNOME3 Thumbnailers</title>
<description xml:lang="en-US">The system's default desktop environment, GNOME3, uses
a number of different thumbnailer programs to generate thumbnails
for any new or modified content in an opened folder. To disable the
execution of these thumbnail applications, the <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">disable-all</xhtml:code> setting must be set
under an appropriate configuration file(s) in the <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/dconf/db/local.d</xhtml:code> directory
and locked in <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/dconf/db/local.d/locks</xhtml:code> directory to prevent user modification.
After the settings have been set, run <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">dconf update</xhtml:code>.
This effectively prevents an attacker from gaining access to a
system through a flaw in GNOME3's Nautilus thumbnail creators.
</description>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">CM-7</reference>
<rationale xml:lang="en-US">An attacker with knowledge of a flaw in a GNOME3 thumbnailer application could craft a malicious
file to exploit this flaw. Assuming the attacker could place the malicious file on the local filesystem
(via a web upload for example) and assuming a user browses the same location using Nautilus, the
malicious file would exploit the thumbnailer with the potential for malicious code execution. It
is best to disable these thumbnailer applications unless they are explicitly required.</rationale>
<check system="http://oval.mitre.org/XMLSchema/oval-definitions-5">
<check-content-ref name="oval:ssg:def:255" href="ssg-fedora-oval.xml"/>
</check>
<check system="ocil-transitional">
<check-export export-name="GNOME automounting is not disabled" value-id="xccdf_org.ssgproject.content_value_conditional_clause"/>
<check-content>
These settings can be verified by running the following:
<pre xmlns="http://www.w3.org/1999/xhtml">$ gsettings get org.gnome.desktop.thumbnailers disable-all</pre>
If properly configured, the output should be <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">true</xhtml:code>.
To ensure that users cannot how long until the the screensaver locks, run the following:
<pre xmlns="http://www.w3.org/1999/xhtml">$ grep disable-all /etc/dconf/db/local.d/locks/*</pre>
If properly configured, the output should be <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/org/gnome/desktop/thumbnailers/disable-all</xhtml:code>
</check-content>
</check>
</Rule>
</Group>
<Group id="xccdf_org.ssgproject.content_group_permissions_within_important_dirs">
<title xml:lang="en-US">Verify File Permissions Within Some Important Directories</title>
<description xml:lang="en-US">Some directories contain files whose confidentiality or integrity
is notably important and may also be susceptible to misconfiguration over time,
particularly if unpackaged software is installed. As such, an argument exists
to verify that files' permissions within these directories remain configured
correctly and restrictively.
</description>
<Rule id="xccdf_org.ssgproject.content_rule_file_permissions_library_dirs" selected="false" severity="medium">
<title xml:lang="en-US">Shared Library Files Have Restrictive Permissions</title>
<description xml:lang="en-US">System-wide shared library files, which are linked to executables
during process load time or run time, are stored in the following directories
by default:
<pre xmlns="http://www.w3.org/1999/xhtml">/lib
/lib64
/usr/lib
/usr/lib64
</pre>
Kernel modules, which can be added to the kernel during runtime, are stored in
<xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/lib/modules</xhtml:code>. All files in these directories should not be
group-writable or world-writable. If any file in these directories is found to
be group-writable or world-writable, correct its permission with the following
command:
<pre xmlns="http://www.w3.org/1999/xhtml"># chmod go-w <i>FILE</i></pre>
</description>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">AC-6</reference>
<reference href="http://iase.disa.mil/stigs/cci/Pages/index.aspx">1499</reference>
<rationale xml:lang="en-US">Files from shared library directories are loaded into the address
space of processes (including privileged ones) or of the kernel itself at
runtime. Restrictive permissions are necessary to protect the integrity of the
system.
</rationale>
<check system="http://oval.mitre.org/XMLSchema/oval-definitions-5">
<check-content-ref name="oval:ssg:def:240" href="ssg-fedora-oval.xml"/>
</check>
</Rule>
<Rule id="xccdf_org.ssgproject.content_rule_file_ownership_library_dirs" selected="false" severity="medium">
<title xml:lang="en-US">Shared Library Files Have Root Ownership</title>
<description xml:lang="en-US">System-wide shared library files, which are linked to executables
during process load time or run time, are stored in the following directories
by default:
<pre xmlns="http://www.w3.org/1999/xhtml">/lib
/lib64
/usr/lib
/usr/lib64
</pre>
Kernel modules, which can be added to the kernel during runtime, are also
stored in <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/lib/modules</xhtml:code>. All files in these directories should be owned
by the <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">root</xhtml:code> user. If the directory, or any file in these directories,
is found to be owned by a user other than root correct its ownership with the
following command:
<pre xmlns="http://www.w3.org/1999/xhtml"># chown root <i>FILE</i></pre>
</description>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">AC-6</reference>
<reference href="http://iase.disa.mil/stigs/cci/Pages/index.aspx">1499</reference>
<rationale xml:lang="en-US">Files from shared library directories are loaded into the address
space of processes (including privileged ones) or of the kernel itself at
runtime. Proper ownership is necessary to protect the integrity of the system.
</rationale>
<check system="http://oval.mitre.org/XMLSchema/oval-definitions-5">
<check-content-ref name="oval:ssg:def:148" href="ssg-fedora-oval.xml"/>
</check>
</Rule>
<Rule id="xccdf_org.ssgproject.content_rule_file_permissions_binary_dirs" selected="false" severity="medium">
<title xml:lang="en-US">System Executables Have Restrictive Permissions</title>
<description xml:lang="en-US">
System executables are stored in the following directories by default:
<pre xmlns="http://www.w3.org/1999/xhtml">/bin
/usr/bin
/usr/local/bin
/sbin
/usr/sbin
/usr/local/sbin</pre>
All files in these directories should not be group-writable or world-writable.
If any file <i xmlns="http://www.w3.org/1999/xhtml">FILE</i> in these directories is found to be group-writable or
world-writable, correct its permission with the following command:
<pre xmlns="http://www.w3.org/1999/xhtml"># chmod go-w <i>FILE</i></pre>
</description>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">AC-6</reference>
<reference href="http://iase.disa.mil/stigs/cci/Pages/index.aspx">1499</reference>
<rationale xml:lang="en-US">System binaries are executed by privileged users, as well as system
services, and restrictive permissions are necessary to ensure execution of
these programs cannot be co-opted.
</rationale>
<check system="http://oval.mitre.org/XMLSchema/oval-definitions-5">
<check-content-ref name="oval:ssg:def:233" href="ssg-fedora-oval.xml"/>
</check>
</Rule>
<Rule id="xccdf_org.ssgproject.content_rule_file_ownership_binary_dirs" selected="false" severity="medium">
<title xml:lang="en-US">System Executables Have Root Ownership</title>
<description xml:lang="en-US">
System executables are stored in the following directories by default:
<pre xmlns="http://www.w3.org/1999/xhtml">/bin
/usr/bin
/usr/local/bin
/sbin
/usr/sbin
/usr/local/sbin</pre>
All files in these directories should be owned by the <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">root</xhtml:code> user. If
any file <i xmlns="http://www.w3.org/1999/xhtml">FILE</i> in these directories is found to be owned by a user other
than root, correct its ownership with the following command:
<pre xmlns="http://www.w3.org/1999/xhtml"># chown root <i>FILE</i></pre>
</description>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">AC-6</reference>
<reference href="http://iase.disa.mil/stigs/cci/Pages/index.aspx">1499</reference>
<rationale xml:lang="en-US">System binaries are executed by privileged users as well as system
services, and restrictive permissions are necessary to ensure that their
execution of these programs cannot be co-opted.
</rationale>
<check system="http://oval.mitre.org/XMLSchema/oval-definitions-5">
<check-content-ref name="oval:ssg:def:138" href="ssg-fedora-oval.xml"/>
</check>
</Rule>
</Group>
<Group id="xccdf_org.ssgproject.content_group_restrictions">
<title xml:lang="en-US">Restrict Programs from Dangerous Execution Patterns</title>
<description xml:lang="en-US">The recommendations in this section are designed to
ensure that the system's features to protect against potentially
dangerous program execution are activated.
These protections are applied at the system initialization or
kernel level, and defend against certain types of badly-configured
or compromised programs.</description>
<Group id="xccdf_org.ssgproject.content_group_daemon_umask">
<title xml:lang="en-US">Daemon Umask</title>
<description xml:lang="en-US">The umask is a per-process setting which limits
the default permissions for creation of new files and directories.
The system includes initialization scripts which set the default umask
for system daemons.
</description>
<Value id="xccdf_org.ssgproject.content_value_var_umask_for_daemons" operator="equals" type="string">
<title xml:lang="en-US">daemon umask</title>
<description xml:lang="en-US">Enter umask for daemons</description>
<value>022</value>
<value selector="022">022</value>
<value selector="027">027</value>
</Value>
<Rule id="xccdf_org.ssgproject.content_rule_umask_for_daemons" selected="false" severity="low">
<title xml:lang="en-US">Set Daemon Umask</title>
<description xml:lang="en-US">The file <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/init.d/functions</xhtml:code> includes initialization
parameters for most or all daemons started at boot time. The default umask of
022 prevents creation of group- or world-writable files. To set the default
umask for daemons, edit the following line, inserting 022 or 027 for
<i xmlns="http://www.w3.org/1999/xhtml">UMASK</i> appropriately:
<pre xmlns="http://www.w3.org/1999/xhtml">umask <i>UMASK</i></pre>
Setting the umask to too restrictive a setting can cause serious errors at
runtime. Many daemons on the system already individually restrict themselves to
a umask of 077 in their own init scripts.
</description>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">AC-6</reference>
<rationale xml:lang="en-US">The umask influences the permissions assigned to files created by a
process at run time. An unnecessarily permissive umask could result in files
being created with insecure permissions.</rationale>
<check system="ocil-transitional">
<check-export export-name="it does not" value-id="xccdf_org.ssgproject.content_value_conditional_clause"/>
<check-content>
To check the value of the <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">umask</xhtml:code>, run the following command:
<pre xmlns="http://www.w3.org/1999/xhtml">$ grep umask /etc/init.d/functions</pre>
The output should show either <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">022</xhtml:code> or <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">027</xhtml:code>.
</check-content>
</check>
</Rule>
</Group>
<Group id="xccdf_org.ssgproject.content_group_coredumps">
<title xml:lang="en-US">Disable Core Dumps</title>
<description xml:lang="en-US">A core dump file is the memory image of an executable
program when it was terminated by the operating system due to
errant behavior. In most cases, only software developers
legitimately need to access these files. The core dump files may
also contain sensitive information, or unnecessarily occupy large
amounts of disk space.
<br xmlns="http://www.w3.org/1999/xhtml"/><br xmlns="http://www.w3.org/1999/xhtml"/>
Once a hard limit is set in <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/security/limits.conf</xhtml:code>, a
user cannot increase that limit within his or her own session. If access
to core dumps is required, consider restricting them to only
certain users or groups. See the <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">limits.conf</xhtml:code> man page for more
information.
<br xmlns="http://www.w3.org/1999/xhtml"/><br xmlns="http://www.w3.org/1999/xhtml"/>
The core dumps of setuid programs are further protected. The
<xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">sysctl</xhtml:code> variable <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">fs.suid_dumpable</xhtml:code> controls whether
the kernel allows core dumps from these programs at all. The default
value of 0 is recommended.</description>
<Rule id="xccdf_org.ssgproject.content_rule_disable_users_coredumps" selected="false" severity="low">
<title xml:lang="en-US">Disable Core Dumps for All Users</title>
<description xml:lang="en-US">To disable core dumps for all users, add the following line to
<xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/security/limits.conf</xhtml:code>:
<pre xmlns="http://www.w3.org/1999/xhtml">* hard core 0</pre>
</description>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">SC-5</reference>
<rationale xml:lang="en-US">A core dump includes a memory image taken at the time the operating system
terminates an application. The memory image could contain sensitive data and is generally useful
only for developers trying to debug problems.</rationale>
<check system="ocil-transitional">
<check-export export-name="it is not" value-id="xccdf_org.ssgproject.content_value_conditional_clause"/>
<check-content>
To verify that core dumps are disabled for all users, run the following command:
<pre xmlns="http://www.w3.org/1999/xhtml">$ grep core /etc/security/limits.conf</pre>
The output should be:
<pre xmlns="http://www.w3.org/1999/xhtml">* hard core 0</pre>
</check-content>
</check>
</Rule>
<Rule id="xccdf_org.ssgproject.content_rule_sysctl_fs_suid_dumpable" selected="false" severity="low">
<title xml:lang="en-US">Disable Core Dumps for SUID programs</title>
<description xml:lang="en-US">
To set the runtime status of the <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">fs.suid_dumpable</xhtml:code> kernel parameter,
run the following command:
<xhtml:pre xmlns:xhtml="http://www.w3.org/1999/xhtml" xml:space="preserve"># sysctl -w fs.suid_dumpable=0</xhtml:pre>
If this is not the system's default value, add the following line to <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/sysctl.conf</xhtml:code>:
<xhtml:pre xmlns:xhtml="http://www.w3.org/1999/xhtml" xml:space="preserve">fs.suid_dumpable = 0</xhtml:pre>
</description>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">SI-11</reference>
<rationale xml:lang="en-US">The core dump of a setuid program is more likely to contain
sensitive data, as the program itself runs with greater privileges than the
user who initiated execution of the program. Disabling the ability for any
setuid program to write a core file decreases the risk of unauthorized access
of such data.</rationale>
<check system="ocil-transitional">
<check-export export-name="the correct value is not returned" value-id="xccdf_org.ssgproject.content_value_conditional_clause"/>
<check-content>
The status of the <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">fs.suid_dumpable</xhtml:code> kernel parameter can be queried
by running the following command:
<xhtml:pre xmlns:xhtml="http://www.w3.org/1999/xhtml" xml:space="preserve">$ sysctl fs.suid_dumpable</xhtml:pre>
The output of the command should indicate a value of <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">0</xhtml:code>.
If this value is not the default value, investigate how it could have been
adjusted at runtime, and verify it is not set improperly in
<xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/sysctl.conf</xhtml:code>.
</check-content>
</check>
</Rule>
</Group>
<Group id="xccdf_org.ssgproject.content_group_enable_execshield_settings">
<title xml:lang="en-US">Enable ExecShield</title>
<description xml:lang="en-US">ExecShield describes kernel features that provide
protection against exploitation of memory corruption errors such as buffer
overflows. These features include random placement of the stack and other
memory regions, prevention of execution in memory that should only hold data,
and special handling of text buffers. These protections are enabled by default
on 32-bit systems and controlled through <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">sysctl</xhtml:code> variables
<xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">kernel.exec-shield</xhtml:code> and <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">kernel.randomize_va_space</xhtml:code>. On the latest
64-bit systems, <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">kernel.exec-shield</xhtml:code> cannot be enabled or disabled with
<xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">sysctl</xhtml:code>.
</description>
<Rule id="xccdf_org.ssgproject.content_rule_sysctl_kernel_exec_shield" selected="false" severity="medium">
<title xml:lang="en-US">Enable ExecShield</title>
<description xml:lang="en-US">By default on Fedora 64-bit systems, ExecShield is enabled and can
only be disabled if the hardware does not support ExecShield or is disabled in
<xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/default/grub</xhtml:code>. For Fedora 32-bit systems, <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">sysctl</xhtml:code> can be
used to enable ExecShield.</description>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf"/>
<rationale xml:lang="en-US">ExecShield uses the segmentation feature on all x86 systems
to prevent execution in memory higher than a certain address. It
writes an address as a limit in the code segment descriptor, to
control where code can be executed, on a per-process basis. When
the kernel places a process's memory regions such as the stack and
heap higher than this address, the hardware prevents execution in that
address range. This is enabled by default on the latest Red Hat and Fedora
systems if supported by the hardware.</rationale>
<check system="http://oval.mitre.org/XMLSchema/oval-definitions-5">
<check-content-ref name="oval:ssg:def:175" href="ssg-fedora-oval.xml"/>
</check>
<check system="ocil-transitional">
<check-export export-name="ExecShield is not supported by the hardware, is not enabled, or has been disabled by the kernel configuration." value-id="xccdf_org.ssgproject.content_value_conditional_clause"/>
<check-content>
To verify ExecShield is enabled on 64-bit Fedora systems, run the following
command:
<pre xmlns="http://www.w3.org/1999/xhtml">$ dmesg | grep '[NX|DX]*protection'</pre>
The output should not contain <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">'disabled by kernel command line option'</xhtml:code>.
To verify that ExecShield has not been disabled in the kernel configuration,
run the following command:
<pre xmlns="http://www.w3.org/1999/xhtml">$ sudo grep noexec /boot/grub2/grub.cfg</pre>
The output should not return <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">noexec=off</xhtml:code>.
For 32-bit Fedora systems, run the following command:
<pre xmlns="http://www.w3.org/1999/xhtml">$ sysctl kernel.exec-shield</pre>
The output should be:
<pre xmlns="http://www.w3.org/1999/xhtml">
To set the runtime status of the <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">kernel.exec-shield</xhtml:code> kernel parameter,
run the following command:
<xhtml:pre xmlns:xhtml="http://www.w3.org/1999/xhtml" xml:space="preserve"># sysctl -w kernel.exec-shield=1</xhtml:pre>
If this is not the system's default value, add the following line to <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/sysctl.conf</xhtml:code>:
<xhtml:pre xmlns:xhtml="http://www.w3.org/1999/xhtml" xml:space="preserve">kernel.exec-shield = 1</xhtml:pre></pre>
</check-content>
</check>
</Rule>
<Rule id="xccdf_org.ssgproject.content_rule_sysctl_kernel_randomize_va_space" selected="false" severity="medium">
<title xml:lang="en-US">Enable Randomized Layout of Virtual Address Space</title>
<description xml:lang="en-US">
To set the runtime status of the <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">kernel.randomize_va_space</xhtml:code> kernel parameter,
run the following command:
<xhtml:pre xmlns:xhtml="http://www.w3.org/1999/xhtml" xml:space="preserve"># sysctl -w kernel.randomize_va_space=2</xhtml:pre>
If this is not the system's default value, add the following line to <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/sysctl.conf</xhtml:code>:
<xhtml:pre xmlns:xhtml="http://www.w3.org/1999/xhtml" xml:space="preserve">kernel.randomize_va_space = 2</xhtml:pre>
</description>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf"/>
<rationale xml:lang="en-US"> Address space layout randomization (ASLR) makes it more difficult
for an attacker to predict the location of attack code they have introduced
into a process's address space during an attempt at exploitation. Additionally, ASLR
makes it more difficult for an attacker to know the location of existing code
in order to re-purpose it using return oriented programming (ROP) techniques.
</rationale>
<check system="ocil-transitional">
<check-export export-name="the correct value is not returned" value-id="xccdf_org.ssgproject.content_value_conditional_clause"/>
<check-content>
The status of the <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">kernel.randomize_va_space</xhtml:code> kernel parameter can be queried
by running the following command:
<xhtml:pre xmlns:xhtml="http://www.w3.org/1999/xhtml" xml:space="preserve">$ sysctl kernel.randomize_va_space</xhtml:pre>
The output of the command should indicate a value of <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">2</xhtml:code>.
If this value is not the default value, investigate how it could have been
adjusted at runtime, and verify it is not set improperly in
<xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/sysctl.conf</xhtml:code>.
</check-content>
</check>
</Rule>
</Group>
<Group id="xccdf_org.ssgproject.content_group_enable_nx">
<title xml:lang="en-US">Enable Execute Disable (XD) or No Execute (NX) Support on
x86 Systems</title>
<description xml:lang="en-US">Recent processors in the x86 family support the
ability to prevent code execution on a per memory page basis.
Generically and on AMD processors, this ability is called No
Execute (NX), while on Intel processors it is called Execute
Disable (XD). This ability can help prevent exploitation of buffer
overflow vulnerabilities and should be activated whenever possible.
Extra steps must be taken to ensure that this protection is
enabled, particularly on 32-bit x86 systems. Other processors, such
as Itanium and POWER, have included such support since inception
and the standard kernel for those platforms supports the
feature. This is enabled by default on the latest Red Hat and
Fedora systems if supported by the hardware.</description>
<Rule id="xccdf_org.ssgproject.content_rule_install_PAE_kernel_on_x86-32" selected="false" severity="low">
<title xml:lang="en-US">Install PAE Kernel on Supported 32-bit x86 Systems</title>
<description xml:lang="en-US">Systems that are using the 64-bit x86 kernel package
do not need to install the kernel-PAE package because the 64-bit
x86 kernel already includes this support. However, if the system is
32-bit and also supports the PAE and NX features as
determined in the previous section, the kernel-PAE package should
be installed to enable XD or NX support:
<pre xmlns="http://www.w3.org/1999/xhtml">$ sudo yum install kernel-PAE</pre>
The installation process should also have configured the
bootloader to load the new kernel at boot. Verify this at reboot
and modify <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/default/grub</xhtml:code> if necessary.</description>
<warning xml:lang="en-US" override="false" category="hardware">The kernel-PAE package should not be
installed on older systems that do not support the XD or NX bit, as
this may prevent them from booting.</warning>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf"/>
<rationale xml:lang="en-US">On 32-bit systems that support the XD or NX bit, the vendor-supplied
PAE kernel is required to enable either Execute Disable (XD) or No Execute (NX) support.</rationale>
</Rule>
<Rule id="xccdf_org.ssgproject.content_rule_bios_enable_execution_restrictions" selected="false" severity="low">
<title xml:lang="en-US">Enable NX or XD Support in the BIOS</title>
<description xml:lang="en-US">Reboot the system and enter the BIOS or Setup configuration menu.
Navigate the BIOS configuration menu and make sure that the option is enabled. The setting may be located
under a Security section. Look for Execute Disable (XD) on Intel-based systems and No Execute (NX)
on AMD-based systems.</description>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf"/>
<rationale xml:lang="en-US">Computers with the ability to prevent this type of code execution frequently put an option in the BIOS that will
allow users to turn the feature on or off at will.</rationale>
</Rule>
</Group>
<Rule id="xccdf_org.ssgproject.content_rule_enable_dmesg_restriction" selected="false" severity="low">
<title xml:lang="en-US">Restrict Access to Kernel Message Buffer</title>
<description xml:lang="en-US">
To set the runtime status of the <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">kernel.dmesg_restrict</xhtml:code> kernel parameter,
run the following command:
<xhtml:pre xmlns:xhtml="http://www.w3.org/1999/xhtml" xml:space="preserve"># sysctl -w kernel.dmesg_restrict=1</xhtml:pre>
If this is not the system's default value, add the following line to <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/sysctl.conf</xhtml:code>:
<xhtml:pre xmlns:xhtml="http://www.w3.org/1999/xhtml" xml:space="preserve">kernel.dmesg_restrict = 1</xhtml:pre>
</description>
<rationale xml:lang="en-US">Unprivileged access to the kernel syslog can expose sensitive kernel
address information.</rationale>
<check system="ocil-transitional">
<check-export export-name="the correct value is not returned" value-id="xccdf_org.ssgproject.content_value_conditional_clause"/>
<check-content>
The status of the <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">kernel.dmesg_restrict</xhtml:code> kernel parameter can be queried
by running the following command:
<xhtml:pre xmlns:xhtml="http://www.w3.org/1999/xhtml" xml:space="preserve">$ sysctl kernel.dmesg_restrict</xhtml:pre>
The output of the command should indicate a value of <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">1</xhtml:code>.
If this value is not the default value, investigate how it could have been
adjusted at runtime, and verify it is not set improperly in
<xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/sysctl.conf</xhtml:code>.
</check-content>
</check>
</Rule>
</Group>
</Group>
<Group id="xccdf_org.ssgproject.content_group_accounts">
<title xml:lang="en-US">Account and Access Control</title>
<description xml:lang="en-US">In traditional Unix security, if an attacker gains
shell access to a certain login account, they can perform any action
or access any file to which that account has access. Therefore,
making it more difficult for unauthorized people to gain shell
access to accounts, particularly to privileged accounts, is a
necessary part of securing a system. This section introduces
mechanisms for restricting access to accounts under Fedora.
</description>
<Group id="xccdf_org.ssgproject.content_group_accounts-restrictions">
<title xml:lang="en-US">Protect Accounts by Restricting Password-Based Login</title>
<description xml:lang="en-US">Conventionally, Unix shell accounts are accessed by
providing a username and password to a login program, which tests
these values for correctness using the <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/passwd</xhtml:code> and
<xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/shadow</xhtml:code> files. Password-based login is vulnerable to
guessing of weak passwords, and to sniffing and man-in-the-middle
attacks against passwords entered over a network or at an insecure
console. Therefore, mechanisms for accessing accounts by entering
usernames and passwords should be restricted to those which are
operationally necessary.</description>
<Group id="xccdf_org.ssgproject.content_group_root_logins">
<title xml:lang="en-US">Restrict Root Logins</title>
<description xml:lang="en-US">
Direct root logins should be allowed only for emergency use.
In normal situations, the administrator should access the system
via a unique unprivileged account, and then use <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">su</xhtml:code> or <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">sudo</xhtml:code> to execute
privileged commands. Discouraging administrators from accessing the
root account directly ensures an audit trail in organizations with
multiple administrators. Locking down the channels through which
root can connect directly also reduces opportunities for
password-guessing against the root account. The <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">login</xhtml:code> program
uses the file <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/securetty</xhtml:code> to determine which interfaces
should allow root logins.
The virtual devices <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/dev/console</xhtml:code>
and <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/dev/tty*</xhtml:code> represent the system consoles (accessible via
the Ctrl-Alt-F1 through Ctrl-Alt-F6 keyboard sequences on a default
installation). The default securetty file also contains <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/dev/vc/*</xhtml:code>.
These are likely to be deprecated in most environments, but may be retained
for compatibility. Furthermore, <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/dev/hvc*</xhtml:code> represent virtio-serial
consoles, <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/dev/hvsi*</xhtml:code> IBM pSeries serial consoles, and finally
<xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/dev/xvc0</xhtml:code> Xen virtual console. Root should also be prohibited
from connecting via network protocols. Other sections of this document
include guidance describing how to prevent root from logging in via SSH.
</description>
<Rule id="xccdf_org.ssgproject.content_rule_no_direct_root_logins" selected="false" severity="medium">
<title xml:lang="en-US">Direct root Logins Not Allowed</title>
<description xml:lang="en-US">To further limit access to the <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">root</xhtml:code> account, administrators
can disable root logins at the console by editing the <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/securetty</xhtml:code> file.
This file lists all devices the root user is allowed to login to. If the file does
not exist at all, the root user can login through any communication device on the
system, whether via the console or via a raw network interface. This is dangerous
as user can login to his machine as root via Telnet, which sends the password in
plain text over the network. By default, Fedora's <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/securetty</xhtml:code> file
only allows the root user to login at the console physically attached to the
machine. To prevent root from logging in, remove the contents of this file.
To prevent direct root logins, remove the contents of this file by typing the
following command:
<pre xmlns="http://www.w3.org/1999/xhtml">
echo > /etc/securetty
</pre>
</description>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">IA-2(1)</reference>
<rationale xml:lang="en-US">
Disabling direct root logins ensures proper accountability and multifactor
authentication to privileged accounts. Users will first login, then escalate
to privileged (root) access via su / sudo. This scenario is nowadays required
by security standards.
</rationale>
<check system="ocil-transitional">
<check-export export-name="the /etc/securetty file is not empty" value-id="xccdf_org.ssgproject.content_value_conditional_clause"/>
<check-content>
To ensure root may not directly login to the system over physical consoles,
run the following command:
<pre xmlns="http://www.w3.org/1999/xhtml">cat /etc/securetty</pre>
If any output is returned, this is a finding.
</check-content>
</check>
</Rule>
<Rule id="xccdf_org.ssgproject.content_rule_securetty_root_login_console_only" selected="false" severity="medium">
<title xml:lang="en-US">Virtual Console Root Logins Restricted</title>
<description xml:lang="en-US">
To restrict root logins through the (deprecated) virtual console devices,
ensure lines of this form do not appear in <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/securetty</xhtml:code>:
<pre xmlns="http://www.w3.org/1999/xhtml">vc/1
vc/2
vc/3
vc/4</pre>
</description>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">AC-6(2)</reference>
<reference href="http://iase.disa.mil/stigs/cci/Pages/index.aspx">770</reference>
<rationale xml:lang="en-US">
Preventing direct root login to virtual console devices
helps ensure accountability for actions taken on the system
using the root account.
</rationale>
<check system="http://oval.mitre.org/XMLSchema/oval-definitions-5">
<check-content-ref name="oval:ssg:def:281" href="ssg-fedora-oval.xml"/>
</check>
<check system="ocil-transitional">
<check-export export-name="root login over virtual console devices is permitted" value-id="xccdf_org.ssgproject.content_value_conditional_clause"/>
<check-content>
To check for virtual console entries which permit root login, run the
following command:
<pre xmlns="http://www.w3.org/1999/xhtml"># grep ^vc/[0-9] /etc/securetty</pre>
If any output is returned, then root logins over virtual console devices is permitted.
</check-content>
</check>
</Rule>
<Rule id="xccdf_org.ssgproject.content_rule_restrict_serial_port_logins" selected="false" severity="low">
<title xml:lang="en-US">Serial Port Root Logins Restricted</title>
<description xml:lang="en-US">To restrict root logins on serial ports,
ensure lines of this form do not appear in <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/securetty</xhtml:code>:
<pre xmlns="http://www.w3.org/1999/xhtml">ttyS0
ttyS1</pre>
<!-- TODO: discussion/description of serial port -->
</description>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">AC-6(2)</reference>
<reference href="http://iase.disa.mil/stigs/cci/Pages/index.aspx">770</reference>
<rationale xml:lang="en-US">
Preventing direct root login to serial port interfaces
helps ensure accountability for actions taken on the systems
using the root account.
</rationale>
<check system="http://oval.mitre.org/XMLSchema/oval-definitions-5">
<check-content-ref name="oval:ssg:def:245" href="ssg-fedora-oval.xml"/>
</check>
<check system="ocil-transitional">
<check-export export-name="root login over serial ports is permitted" value-id="xccdf_org.ssgproject.content_value_conditional_clause"/>
<check-content>
To check for serial port entries which permit root login,
run the following command:
<pre xmlns="http://www.w3.org/1999/xhtml"># grep ^ttyS/[0-9] /etc/securetty</pre>
If any output is returned, then root login over serial ports is permitted.
</check-content>
</check>
</Rule>
<Rule id="xccdf_org.ssgproject.content_rule_no_root_webbrowsing" selected="false" severity="low">
<title xml:lang="en-US">Web Browser Use for Administrative Accounts Restricted</title>
<description xml:lang="en-US">
Enforce policy requiring administrative accounts use web browsers only for
local service administration.
</description>
<rationale xml:lang="en-US">
If a browser vulnerability is exploited while running with administrative privileges,
the entire system could be compromised. Specific exceptions for local service
administration should be documented in site-defined policy.
</rationale>
<check system="ocil-transitional">
<check-export export-name="this is not the case" value-id="xccdf_org.ssgproject.content_value_conditional_clause"/>
<check-content>
Check the <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">root</xhtml:code> home directory for a <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">.mozilla</xhtml:code> directory. If
one exists, ensure browsing is limited to local service administration.
</check-content>
</check>
</Rule>
<Rule id="xccdf_org.ssgproject.content_rule_no_shelllogin_for_systemaccounts" selected="false" severity="medium">
<title xml:lang="en-US">System Accounts Do Not Run a Shell Upon Login</title>
<description xml:lang="en-US">
Some accounts are not associated with a human
user of the system, and exist to perform some administrative
function. Should an attacker be able to log into these accounts,
they should not be granted access to a shell.
<br xmlns="http://www.w3.org/1999/xhtml"/><br xmlns="http://www.w3.org/1999/xhtml"/>
The login shell for each local account is stored in the last field of each line
in <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/passwd</xhtml:code>. System accounts are those user accounts with a user ID less than
500. The user ID is stored in the third field.
If any system account <i xmlns="http://www.w3.org/1999/xhtml">SYSACCT</i> (other than root) has a login shell,
disable it with the command:
<pre xmlns="http://www.w3.org/1999/xhtml"># usermod -s /sbin/nologin <i>SYSACCT</i></pre>
</description>
<warning xml:lang="en-US" override="false" category="functionality">
Do not perform the steps in this
section on the root account. Doing so might cause the system to
become inaccessible.
</warning>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf"/>
<reference href="http://iase.disa.mil/stigs/cci/Pages/index.aspx">178</reference>
<rationale xml:lang="en-US">
Ensuring shells are not given to system accounts upon login
makes it more difficult for attackers to make use of
system accounts.
</rationale>
<check system="http://oval.mitre.org/XMLSchema/oval-definitions-5">
<check-content-ref name="oval:ssg:def:207" href="ssg-fedora-oval.xml"/>
</check>
<check system="ocil-transitional">
<check-export export-name="any system account (other than root) has a login shell" value-id="xccdf_org.ssgproject.content_value_conditional_clause"/>
<check-content>
To obtain a listing of all users,
their UIDs, and their shells, run the command:
<pre xmlns="http://www.w3.org/1999/xhtml">$ awk -F: '{print $1 ":" $3 ":" $7}' /etc/passwd</pre>
Identify the system accounts from this listing. These will
primarily be the accounts with UID numbers less than 500, other
than root.
</check-content>
</check>
</Rule>
<Rule id="xccdf_org.ssgproject.content_rule_no_uidzero_except_root" selected="false" severity="medium">
<title xml:lang="en-US">Only Root Has UID 0</title>
<description xml:lang="en-US">
If any account other than root has a UID of 0,
this misconfiguration should be investigated and the
accounts other than root should be removed or have their UID changed.
</description>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">AC-6</reference>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">IA-2(1)</reference>
<reference href="http://iase.disa.mil/stigs/cci/Pages/index.aspx">366</reference>
<rationale xml:lang="en-US">
An account has root authority if it has a UID of 0. Multiple accounts
with a UID of 0 afford more opportunity for potential intruders to
guess a password for a privileged account. Proper configuration of
sudo is recommended to afford multiple system administrators
access to root privileges in an accountable manner.
</rationale>
<check system="http://oval.mitre.org/XMLSchema/oval-definitions-5">
<check-content-ref name="oval:ssg:def:276" href="ssg-fedora-oval.xml"/>
</check>
<check system="ocil-transitional">
<check-export export-name="any account other than root has a UID of 0" value-id="xccdf_org.ssgproject.content_value_conditional_clause"/>
<check-content>
To list all password file entries for accounts with UID 0, run the following command:
<pre xmlns="http://www.w3.org/1999/xhtml"># awk -F: '($3 == "0") {print}' /etc/passwd</pre>
This should print only one line, for the user root.
</check-content>
</check>
</Rule>
<Rule id="xccdf_org.ssgproject.content_rule_root_path_default" selected="false" severity="low">
<title xml:lang="en-US">Root Path Is Vendor Default</title>
<description xml:lang="en-US">
Assuming root shell is bash, edit the following files:
<pre xmlns="http://www.w3.org/1999/xhtml">~/.profile</pre>
<pre xmlns="http://www.w3.org/1999/xhtml">~/.bashrc</pre>
Change any <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">PATH</xhtml:code> variables to the vendor default for root and remove any
empty <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">PATH</xhtml:code> entries or references to relative paths.
</description>
<rationale xml:lang="en-US">
The root account's executable search path must be the vendor default, and must
contain only absolute paths.
</rationale>
<check system="ocil-transitional">
<check-export export-name="any of these conditions are not met" value-id="xccdf_org.ssgproject.content_value_conditional_clause"/>
<check-content>
To view the root user's <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">PATH</xhtml:code>, run the following command:
<pre xmlns="http://www.w3.org/1999/xhtml"># env | grep PATH</pre>
If correctly configured, the <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">PATH</xhtml:code> must: use vendor default settings,
have no empty entries, and have no entries beginning with a character
other than a slash (/).
</check-content>
</check>
</Rule>
</Group>
<Group id="xccdf_org.ssgproject.content_group_password_storage">
<title xml:lang="en-US">Proper Storage and Existence of Password Hashes</title>
<description xml:lang="en-US">
By default, password hashes for local accounts are stored
in the second field (colon-separated) in
<xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/shadow</xhtml:code>. This file should be readable only by
processes running with root credentials, preventing users from
casually accessing others' password hashes and attempting
to crack them.
However, it remains possible to misconfigure the system
and store password hashes
in world-readable files such as <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/passwd</xhtml:code>, or
to even store passwords themselves in plaintext on the system.
Using system-provided tools for password change/creation
should allow administrators to avoid such misconfiguration.
</description>
<Rule id="xccdf_org.ssgproject.content_rule_no_empty_passwords" selected="false" severity="high">
<title xml:lang="en-US">Log In to Accounts With Empty Password Impossible</title>
<description xml:lang="en-US">If an account is configured for password authentication
but does not have an assigned password, it may be possible to log
into the account without authentication. Remove any instances of the <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">nullok</xhtml:code>
option in <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/pam.d/system-auth</xhtml:code> to
prevent logins with empty passwords.
</description>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">IA-5(b)</reference>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">IA-5(c)</reference>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">IA-5(1)(a)</reference>
<rationale xml:lang="en-US">
If an account has an empty password, anyone could log in and
run commands with the privileges of that account. Accounts with
empty passwords should never be used in operational
environments.
</rationale>
<check system="http://oval.mitre.org/XMLSchema/oval-definitions-5">
<check-content-ref name="oval:ssg:def:127" href="ssg-fedora-oval.xml"/>
</check>
<check system="ocil-transitional">
<check-export export-name="NULL passwords can be used" value-id="xccdf_org.ssgproject.content_value_conditional_clause"/>
<check-content>
To verify that null passwords cannot be used, run the following command:
<pre xmlns="http://www.w3.org/1999/xhtml"># grep nullok /etc/pam.d/system-auth</pre>
If this produces any output, it may be possible to log into accounts
with empty passwords.
</check-content>
</check>
</Rule>
<Rule id="xccdf_org.ssgproject.content_rule_no_hashes_outside_shadow" selected="false" severity="medium">
<title xml:lang="en-US">Password Hashes For Each Account Shadowed</title>
<description xml:lang="en-US">
If any password hashes are stored in <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/passwd</xhtml:code> (in the second field,
instead of an <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">x</xhtml:code>), the cause of this misconfiguration should be
investigated. The account should have its password reset and the hash should be
properly stored, or the account should be deleted entirely.
</description>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">IA-5(h)</reference>
<reference href="http://iase.disa.mil/stigs/cci/Pages/index.aspx">201</reference>
<rationale xml:lang="en-US">
The hashes for all user account passwords should be stored in
the file <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/shadow</xhtml:code> and never in <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/passwd</xhtml:code>,
which is readable by all users.
</rationale>
<check system="http://oval.mitre.org/XMLSchema/oval-definitions-5">
<check-content-ref name="oval:ssg:def:267" href="ssg-fedora-oval.xml"/>
</check>
<check system="ocil-transitional">
<check-export export-name="any stored hashes are found in /etc/passwd" value-id="xccdf_org.ssgproject.content_value_conditional_clause"/>
<check-content>
To check that no password hashes are stored in
<xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/passwd</xhtml:code>, run the following command:
<pre xmlns="http://www.w3.org/1999/xhtml"># awk -F: '($2 != "x") {print}' /etc/passwd</pre>
If it produces any output, then a password hash is
stored in <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/passwd</xhtml:code>.
</check-content>
</check>
</Rule>
<Rule id="xccdf_org.ssgproject.content_rule_gid_passwd_group_same" selected="false" severity="low">
<title xml:lang="en-US">All GIDs referenced in /etc/passwd Defined in /etc/group</title>
<description xml:lang="en-US">
Add a group to the system for each GID referenced without a corresponding group.
</description>
<reference href="http://iase.disa.mil/stigs/cci/Pages/index.aspx">366</reference>
<rationale xml:lang="en-US">
Inconsistency in GIDs between <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/passwd</xhtml:code> and <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/group</xhtml:code> could lead to a user having unintended rights.
</rationale>
<check system="ocil-transitional">
<check-export export-name="there is output" value-id="xccdf_org.ssgproject.content_value_conditional_clause"/>
<check-content>
To ensure all GIDs referenced in <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/passwd</xhtml:code> are defined in <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/group</xhtml:code>,
run the following command:
<pre xmlns="http://www.w3.org/1999/xhtml"># pwck -qr</pre>
There should be no output.
</check-content>
</check>
</Rule>
<Rule id="xccdf_org.ssgproject.content_rule_no_netrc_files" selected="false" severity="medium">
<title xml:lang="en-US">netrc Files Do Not Exist</title>
<description xml:lang="en-US">The <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">.netrc</xhtml:code> files contain login information
used to auto-login into FTP servers and reside in the user's home
directory. These files may contain unencrypted passwords to
remote FTP servers making them susceptible to access by unauthorized
users and should not be used. Any <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">.netrc</xhtml:code> files should be removed.
</description>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">IA-5(h)</reference>
<reference href="http://iase.disa.mil/stigs/cci/Pages/index.aspx">196</reference>
<rationale xml:lang="en-US">
Unencrypted passwords for remote FTP servers may be stored in <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">.netrc</xhtml:code>
files. DoD policy requires passwords be encrypted in storage and not used
in access scripts.
</rationale>
<check system="http://oval.mitre.org/XMLSchema/oval-definitions-5">
<check-content-ref name="oval:ssg:def:200" href="ssg-fedora-oval.xml"/>
</check>
<check system="ocil-transitional">
<check-export export-name="any .netrc files exist" value-id="xccdf_org.ssgproject.content_value_conditional_clause"/>
<check-content>
To check the system for the existence of any <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">.netrc</xhtml:code> files,
run the following command:
<pre xmlns="http://www.w3.org/1999/xhtml"># find /home -xdev -name .netrc</pre>
<!-- needs fixup to limit search to home dirs -->
</check-content>
</check>
</Rule>
</Group>
<Group id="xccdf_org.ssgproject.content_group_password_expiration">
<title xml:lang="en-US">Set Password Expiration Parameters</title>
<description xml:lang="en-US">The file <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/login.defs</xhtml:code> controls several
password-related settings. Programs such as <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">passwd</xhtml:code>,
<xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">su</xhtml:code>, and <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">login</xhtml:code> consult <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/login.defs</xhtml:code> to determine
behavior with regard to password aging, expiration warnings,
and length. See the man page <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">login.defs(5)</xhtml:code> for more information.
<br xmlns="http://www.w3.org/1999/xhtml"/><br xmlns="http://www.w3.org/1999/xhtml"/>
Users should be forced to change their passwords, in order to
decrease the utility of compromised passwords. However, the need to
change passwords often should be balanced against the risk that
users will reuse or write down passwords if forced to change them
too often. Forcing password changes every 90-360 days, depending on
the environment, is recommended. Set the appropriate value as
<xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">PASS_MAX_DAYS</xhtml:code> and apply it to existing accounts with the
<xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">-M</xhtml:code> flag.
<br xmlns="http://www.w3.org/1999/xhtml"/><br xmlns="http://www.w3.org/1999/xhtml"/>
The <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">PASS_MIN_DAYS</xhtml:code> (<xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">-m</xhtml:code>) setting prevents password
changes for 7 days after the first change, to discourage password
cycling. If you use this setting, train users to contact an administrator
for an emergency password change in case a new password becomes
compromised. The <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">PASS_WARN_AGE</xhtml:code> (<xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">-W</xhtml:code>) setting gives
users 7 days of warnings at login time that their passwords are about to expire.
<br xmlns="http://www.w3.org/1999/xhtml"/><br xmlns="http://www.w3.org/1999/xhtml"/>
For example, for each existing human user <i xmlns="http://www.w3.org/1999/xhtml">USER</i>, expiration parameters
could be adjusted to a 180 day maximum password age, 7 day minimum password
age, and 7 day warning period with the following command:
<pre xmlns="http://www.w3.org/1999/xhtml"># chage -M 180 -m 7 -W 7 USER</pre>
</description>
<Value id="xccdf_org.ssgproject.content_value_var_accounts_password_minlen_login_defs" type="number">
<title xml:lang="en-US">minimum password length</title>
<description xml:lang="en-US">Minimum number of characters in password</description>
<warning xml:lang="en-US" override="false" category="general">This will only check new passwords</warning>
<value>12</value>
<value selector="6">6</value>
<value selector="8">8</value>
<value selector="10">10</value>
<value selector="12">12</value>
<value selector="14">14</value>
</Value>
<Value id="xccdf_org.ssgproject.content_value_var_accounts_maximum_age_login_defs" type="number">
<title xml:lang="en-US">maximum password age</title>
<description xml:lang="en-US">Maximum age of password in days</description>
<warning xml:lang="en-US" override="false" category="general">This will only apply to newly created accounts</warning>
<value>60</value>
<value selector="60">60</value>
<value selector="90">90</value>
<value selector="120">120</value>
<value selector="180">180</value>
</Value>
<Value id="xccdf_org.ssgproject.content_value_var_accounts_minimum_age_login_defs" type="number">
<title xml:lang="en-US">minimum password age</title>
<description xml:lang="en-US">Minimum age of password in days</description>
<warning xml:lang="en-US" override="false" category="general">This will only apply to newly created accounts</warning>
<value>7</value>
<value selector="7">7</value>
<value selector="5">5</value>
<value selector="1">1</value>
<value selector="2">2</value>
<value selector="0">0</value>
</Value>
<Value id="xccdf_org.ssgproject.content_value_var_accounts_password_warn_age_login_defs" type="number">
<title xml:lang="en-US">warning days before password expires</title>
<description xml:lang="en-US">The number of days' warning given before a password expires.</description>
<warning xml:lang="en-US" override="false" category="general">This will only apply to newly created accounts</warning>
<value>7</value>
<value selector="0">0</value>
<value selector="7">7</value>
<value selector="14">14</value>
</Value>
<Rule id="xccdf_org.ssgproject.content_rule_accounts_password_minlen_login_defs" selected="false" severity="medium">
<title xml:lang="en-US">Password Minimum Length</title>
<description xml:lang="en-US">To specify password length requirements for new accounts,
edit the file <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/login.defs</xhtml:code>, locate the following line:
<pre xmlns="http://www.w3.org/1999/xhtml">PASS_MIN_LEN <b>LENGTH</b></pre>
and correct it to have the form of:
<pre xmlns="http://www.w3.org/1999/xhtml">PASS_MIN_LEN <b><sub xmlns="http://checklists.nist.gov/xccdf/1.2" idref="xccdf_org.ssgproject.content_value_var_accounts_password_minlen_login_defs" use="legacy"/></b></pre>
<br xmlns="http://www.w3.org/1999/xhtml"/>
Nowadays recommended values, considered as secure by various organizations
focused on topic of computer security, range from <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">12 (FISMA)</xhtml:code> up to
<xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">14 (DoD)</xhtml:code> characters for password length requirements.
If a program consults <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/login.defs</xhtml:code> and also another PAM module
(such as <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">pam_cracklib</xhtml:code>) during a password change operation,
then the most restrictive must be satisfied. See PAM section
for more information about enforcing password quality requirements.
</description>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">IA-5(f)</reference>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">IA-5(1)(a)</reference>
<reference href="http://iase.disa.mil/stigs/cci/Pages/index.aspx">205</reference>
<rationale xml:lang="en-US">
Requiring a minimum password length makes password
cracking attacks more difficult by ensuring a larger
search space. However, any security benefit from an onerous requirement
must be carefully weighed against usability problems, support costs, or
counterproductive behavior that may result.
</rationale>
<fix system="urn:xccdf:fix:script:sh">var_accounts_password_minlen_login_defs="<sub idref="xccdf_org.ssgproject.content_value_var_accounts_password_minlen_login_defs" use="legacy"/>"
grep -q ^PASS_MIN_LEN /etc/login.defs && \
sed -i "s/PASS_MIN_LEN.*/PASS_MIN_LEN\t$var_accounts_password_minlen_login_defs/g" /etc/login.defs
if ! [ $? -eq 0 ]
then
echo -e "PASS_MIN_LEN\t$var_accounts_password_minlen_login_defs" >> /etc/login.defs
fi
</fix>
<check system="http://oval.mitre.org/XMLSchema/oval-definitions-5">
<check-export export-name="oval:ssg:var:475" value-id="xccdf_org.ssgproject.content_value_var_accounts_password_minlen_login_defs"/>
<check-content-ref name="oval:ssg:def:251" href="ssg-fedora-oval.xml"/>
</check>
<check system="ocil-transitional">
<check-export export-name="it is not set to the required value" value-id="xccdf_org.ssgproject.content_value_conditional_clause"/>
<check-content>
To check the minimum password length, run the command:
<pre xmlns="http://www.w3.org/1999/xhtml">$ grep PASS_MIN_LEN /etc/login.defs</pre>
Passwords of length <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">12</xhtml:code> characters and more are nowadays
considered to be a standard requirement.
</check-content>
</check>
</Rule>
<Rule id="xccdf_org.ssgproject.content_rule_accounts_minimum_age_login_defs" selected="false" severity="medium">
<title xml:lang="en-US">Password Minimum Age</title>
<description xml:lang="en-US">To specify password minimum age for new accounts,
edit the file <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/login.defs</xhtml:code>, locate the following line:
<pre xmlns="http://www.w3.org/1999/xhtml">PASS_MIN_DAYS <b>DAYS</b></pre>
and correct it to have the form of:
<pre xmlns="http://www.w3.org/1999/xhtml">PASS_MIN_DAYS <b><sub xmlns="http://checklists.nist.gov/xccdf/1.2" idref="xccdf_org.ssgproject.content_value_var_accounts_minimum_age_login_defs" use="legacy"/></b></pre>
<br xmlns="http://www.w3.org/1999/xhtml"/>
A value greater than 1 day is considered to be sufficient for many environments.
</description>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">IA-5(f)</reference>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">IA-5(1)(d)</reference>
<reference href="http://iase.disa.mil/stigs/cci/Pages/index.aspx">198</reference>
<rationale xml:lang="en-US">
Setting the minimum password age protects against users cycling
back to a favorite password after satisfying the password reuse
requirement.
</rationale>
<fix system="urn:xccdf:fix:script:sh">var_accounts_minimum_age_login_defs="<sub idref="xccdf_org.ssgproject.content_value_var_accounts_minimum_age_login_defs" use="legacy"/>"
grep -q ^PASS_MIN_DAYS /etc/login.defs && \
sed -i "s/PASS_MIN_DAYS.*/PASS_MIN_DAYS\t$var_accounts_minimum_age_login_defs/g" /etc/login.defs
if ! [ $? -eq 0 ]
then
echo -e "PASS_MIN_DAYS\t$var_accounts_minimum_age_login_defs" >> /etc/login.defs
fi
</fix>
<check system="http://oval.mitre.org/XMLSchema/oval-definitions-5">
<check-export export-name="oval:ssg:var:477" value-id="xccdf_org.ssgproject.content_value_var_accounts_minimum_age_login_defs"/>
<check-content-ref name="oval:ssg:def:283" href="ssg-fedora-oval.xml"/>
</check>
<check system="ocil-transitional">
<check-export export-name="it is not set to the required value" value-id="xccdf_org.ssgproject.content_value_conditional_clause"/>
<check-content>
To check the minimum password age, run the command:
<pre xmlns="http://www.w3.org/1999/xhtml">$ grep PASS_MIN_DAYS /etc/login.defs</pre>
A value greater than 1 day is considered to be sufficient for many environments.
</check-content>
</check>
</Rule>
<Rule id="xccdf_org.ssgproject.content_rule_accounts_maximum_age_login_defs" selected="false" severity="medium">
<title xml:lang="en-US">Password Maximum Age</title>
<description xml:lang="en-US">To specify password maximum age for new accounts,
edit the file <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/login.defs</xhtml:code>, locate the following line:
<pre xmlns="http://www.w3.org/1999/xhtml">PASS_MAX_DAYS <b>DAYS</b></pre>
and correct it to have the form of:
<pre xmlns="http://www.w3.org/1999/xhtml">PASS_MAX_DAYS <b><sub xmlns="http://checklists.nist.gov/xccdf/1.2" idref="xccdf_org.ssgproject.content_value_var_accounts_maximum_age_login_defs" use="legacy"/></b></pre>
<br xmlns="http://www.w3.org/1999/xhtml"/>
A value less than 180 days is sufficient for many environments.
</description>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">IA-5(f)</reference>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">IA-5(g)</reference>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">IA-5(1)(d)</reference>
<reference href="http://iase.disa.mil/stigs/cci/Pages/index.aspx">180</reference>
<reference href="http://iase.disa.mil/stigs/cci/Pages/index.aspx">199</reference>
<rationale xml:lang="en-US">
Setting the password maximum age ensures users are required to
periodically change their passwords. This could possibly decrease
the utility of a stolen password. Requiring shorter password lifetimes
increases the risk of users writing down the password in a convenient
location subject to physical compromise.</rationale>
<fix system="urn:xccdf:fix:script:sh">var_accounts_maximum_age_login_defs="<sub idref="xccdf_org.ssgproject.content_value_var_accounts_maximum_age_login_defs" use="legacy"/>"
grep -q ^PASS_MAX_DAYS /etc/login.defs && \
sed -i "s/PASS_MAX_DAYS.*/PASS_MAX_DAYS\t$var_accounts_maximum_age_login_defs/g" /etc/login.defs
if ! [ $? -eq 0 ]
then
echo -e "PASS_MAX_DAYS\t$var_accounts_maximum_age_login_defs" >> /etc/login.defs
fi
</fix>
<check system="http://oval.mitre.org/XMLSchema/oval-definitions-5">
<check-export export-name="oval:ssg:var:464" value-id="xccdf_org.ssgproject.content_value_var_accounts_maximum_age_login_defs"/>
<check-content-ref name="oval:ssg:def:136" href="ssg-fedora-oval.xml"/>
</check>
<check system="ocil-transitional">
<check-export export-name="it is not set to the required value" value-id="xccdf_org.ssgproject.content_value_conditional_clause"/>
<check-content>
To check the maximum password age, run the command:
<pre xmlns="http://www.w3.org/1999/xhtml">$ grep PASS_MAX_DAYS /etc/login.defs</pre>
A value less than 180 days is sufficient for many environments.
</check-content>
</check>
</Rule>
<Rule id="xccdf_org.ssgproject.content_rule_accounts_password_warn_age_login_defs" selected="false" severity="low">
<title xml:lang="en-US">Password Warning Age</title>
<description xml:lang="en-US">To specify how many days prior to password
expiration that a warning will be issued to users,
edit the file <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/login.defs</xhtml:code>, locate the following line:
<pre xmlns="http://www.w3.org/1999/xhtml">PASS_WARN_AGE <b>DAYS</b></pre>
and correct it to have the form of:
<pre xmlns="http://www.w3.org/1999/xhtml">PASS_WARN_AGE <b><sub xmlns="http://checklists.nist.gov/xccdf/1.2" idref="xccdf_org.ssgproject.content_value_var_accounts_password_warn_age_login_defs" use="legacy"/></b></pre>
<br xmlns="http://www.w3.org/1999/xhtml"/>
A value of 7 days would be nowadays considered to be a standard.
</description>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">IA-5(f)</reference>
<rationale xml:lang="en-US">
Setting the password warning age enables users to make the change
at a practical time.
</rationale>
<fix system="urn:xccdf:fix:script:sh">var_accounts_password_warn_age_login_defs="<sub idref="xccdf_org.ssgproject.content_value_var_accounts_password_warn_age_login_defs" use="legacy"/>"
grep -q ^PASS_WARN_AGE /etc/login.defs && \
sed -i "s/PASS_WARN_AGE.*/PASS_WARN_AGE\t$var_accounts_password_warn_age_login_defs/g" /etc/login.defs
if ! [ $? -eq 0 ]
then
echo -e "PASS_WARN_AGE\t$var_accounts_password_warn_age_login_defs" >> /etc/login.defs
fi
</fix>
<check system="http://oval.mitre.org/XMLSchema/oval-definitions-5">
<check-export export-name="oval:ssg:var:472" value-id="xccdf_org.ssgproject.content_value_var_accounts_password_warn_age_login_defs"/>
<check-content-ref name="oval:ssg:def:231" href="ssg-fedora-oval.xml"/>
</check>
<check system="ocil-transitional">
<check-export export-name="it is not set to the required value" value-id="xccdf_org.ssgproject.content_value_conditional_clause"/>
<check-content>
To check the password warning age, run the command:
<pre xmlns="http://www.w3.org/1999/xhtml">$ grep PASS_WARN_AGE /etc/login.defs</pre>
A value of 7 days would be nowadays considered to be a standard.
</check-content>
</check>
</Rule>
</Group>
</Group>
<Group id="xccdf_org.ssgproject.content_group_accounts-session">
<title xml:lang="en-US">Secure Session Configuration Files for Login Accounts</title>
<description xml:lang="en-US">When a user logs into a Unix account, the system
configures the user's session by reading a number of files. Many of
these files are located in the user's home directory, and may have
weak permissions as a result of user error or misconfiguration. If
an attacker can modify or even read certain types of account
configuration information, they can often gain full access to the
affected user's account. Therefore, it is important to test and
correct configuration file permissions for interactive accounts,
particularly those of privileged users such as root or system
administrators.</description>
<Value id="xccdf_org.ssgproject.content_value_var_accounts_max_concurrent_login_sessions" operator="equals" type="number">
<title xml:lang="en-US">Maximum concurrent login sessions</title>
<description xml:lang="en-US">Maximum number of concurrent sessions by a user</description>
<value>1</value>
<value selector="1">1</value>
<value selector="3">3</value>
<value selector="5">5</value>
<value selector="10">10</value>
<value selector="15">15</value>
<value selector="20">20</value>
</Value>
<Rule id="xccdf_org.ssgproject.content_rule_accounts_max_concurrent_login_sessions" selected="false" severity="low">
<title xml:lang="en-US">Limit the Number of Concurrent Login Sessions Allowed Per User</title>
<description xml:lang="en-US">
Limiting the number of allowed users and sessions per user can limit risks related to Denial of
Service attacks. This addresses concurrent sessions for a single account and does not address
concurrent sessions by a single user via multiple accounts. The DoD requirement is 10. To set the number of concurrent
sessions per user add the following line in <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/security/limits.conf</xhtml:code>:
<pre xmlns="http://www.w3.org/1999/xhtml">* hard maxlogins <sub xmlns="http://checklists.nist.gov/xccdf/1.2" idref="xccdf_org.ssgproject.content_value_var_accounts_max_concurrent_login_sessions" use="legacy"/></pre>
</description>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">AC-10</reference>
<reference href="http://iase.disa.mil/stigs/cci/Pages/index.aspx">54</reference>
<rationale xml:lang="en-US">Limiting simultaneous user logins can insulate the system from denial of service
problems caused by excessive logins. Automated login processes operating improperly or
maliciously may result in an exceptional number of simultaneous login sessions.
</rationale>
<check system="ocil-transitional">
<check-export export-name="it is not similar" value-id="xccdf_org.ssgproject.content_value_conditional_clause"/>
<check-content>
Run the following command to ensure the <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">maxlogins</xhtml:code> value is configured for all users
on the system:
<pre xmlns="http://www.w3.org/1999/xhtml">$ grep "maxlogins" /etc/security/limits.conf</pre>
You should receive output similar to the following:
<pre xmlns="http://www.w3.org/1999/xhtml">* hard maxlogins 10</pre>
</check-content>
</check>
</Rule>
<Group id="xccdf_org.ssgproject.content_group_root_paths">
<title xml:lang="en-US">Ensure that No Dangerous Directories Exist in Root's Path</title>
<description xml:lang="en-US">The active path of the root account can be obtained by
starting a new root shell and running:
<pre xmlns="http://www.w3.org/1999/xhtml">$ sudo echo $PATH</pre>
This will produce a colon-separated list of
directories in the path.
<br xmlns="http://www.w3.org/1999/xhtml"/><br xmlns="http://www.w3.org/1999/xhtml"/>
Certain path elements could be considered dangerous, as they could lead
to root executing unknown or
untrusted programs, which could contain malicious
code.
Since root may sometimes work inside
untrusted directories, the <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">.</xhtml:code> character, which represents the
current directory, should never be in the root path, nor should any
directory which can be written to by an unprivileged or
semi-privileged (system) user.
<br xmlns="http://www.w3.org/1999/xhtml"/><br xmlns="http://www.w3.org/1999/xhtml"/>
It is a good practice for administrators to always execute
privileged commands by typing the full path to the
command.</description>
<Rule id="xccdf_org.ssgproject.content_rule_root_path_no_dot" selected="false" severity="low">
<title xml:lang="en-US">Ensure that Root's Path Does Not Include Relative Paths or Null Directories</title>
<description xml:lang="en-US">
Ensure that none of the directories in root's path is equal to a single
<xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">.</xhtml:code> character, or
that it contains any instances that lead to relative path traversal, such as
<xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">..</xhtml:code> or beginning a path without the slash (<xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/</xhtml:code>) character.
Also ensure that there are no "empty" elements in the path, such as in these examples:
<pre xmlns="http://www.w3.org/1999/xhtml">PATH=:/bin
PATH=/bin:
PATH=/bin::/sbin</pre>
These empty elements have the same effect as a single <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">.</xhtml:code> character.
</description>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf"/>
<rationale xml:lang="en-US">
Including these entries increases the risk that root could
execute code from an untrusted location.
</rationale>
</Rule>
<Rule id="xccdf_org.ssgproject.content_rule_root_path_no_groupother_writable" selected="false" severity="low">
<title xml:lang="en-US">Ensure that Root's Path Does Not Include World or Group-Writable Directories</title>
<description xml:lang="en-US">
For each element in root's path, run:
<pre xmlns="http://www.w3.org/1999/xhtml">$ sudo ls -ld <i>DIR</i></pre>
and ensure that write permissions are disabled for group and
other.
</description>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf"/>
<rationale xml:lang="en-US">
Such entries increase the risk that root could
execute code provided by unprivileged users,
and potentially malicious code.
</rationale>
<check system="http://oval.mitre.org/XMLSchema/oval-definitions-5">
<check-content-ref name="oval:ssg:def:274" href="ssg-fedora-oval.xml"/>
</check>
<check system="ocil-transitional">
<check-export export-name="group or other write permissions exist" value-id="xccdf_org.ssgproject.content_value_conditional_clause"/>
<check-content>
To ensure write permissions are disabled for group and other
for each element in root's path, run the following command:
<pre xmlns="http://www.w3.org/1999/xhtml">$ sudo ls -ld <i>DIR</i></pre>
</check-content>
</check>
</Rule>
</Group>
<Rule id="xccdf_org.ssgproject.content_rule_homedir_perms_no_groupwrite_worldread" selected="false" severity="low">
<title xml:lang="en-US">Ensure that User Home Directories are not Group-Writable or World-Readable</title>
<description xml:lang="en-US">For each human user of the system, view the
permissions of the user's home directory:
<pre xmlns="http://www.w3.org/1999/xhtml">$ sudo ls -ld /home/<i>USER</i></pre>
Ensure that the directory is not group-writable and that it
is not world-readable. If necessary, repair the permissions:
<pre xmlns="http://www.w3.org/1999/xhtml">$ sudo chmod g-w /home/<i>USER</i>
$ sudo chmod o-rwx /home/<i>USER</i></pre>
</description>
<warning xml:lang="en-US" override="false" category="general">This action may involve
modifying user home directories. Notify your user community, and
solicit input if appropriate, before making this type of
change.</warning>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf"/>
<rationale xml:lang="en-US">
User home directories contain many configuration files which
affect the behavior of a user's account. No user should ever have
write permission to another user's home directory. Group shared
directories can be configured in sub-directories or elsewhere in the
filesystem if they are needed. Typically, user home directories
should not be world-readable, as it would disclose file names
to other users. If a subset of users need read access
to one another's home directories, this can be provided using
groups or ACLs.
</rationale>
<check system="http://oval.mitre.org/XMLSchema/oval-definitions-5">
<check-content-ref name="oval:ssg:def:155" href="ssg-fedora-oval.xml"/>
</check>
<check system="ocil-transitional">
<check-export export-name="the user home directory is group-writable or world-readable" value-id="xccdf_org.ssgproject.content_value_conditional_clause"/>
<check-content>
To ensure the user home directory is not group-writable or world-readable, run the following:
<pre xmlns="http://www.w3.org/1999/xhtml">$ sudo ls -ld /home/<i>USER</i></pre>
</check-content>
</check>
</Rule>
<Group id="xccdf_org.ssgproject.content_group_user_umask">
<title xml:lang="en-US">Ensure that Users Have Sensible Umask Values</title>
<description xml:lang="en-US">
The umask setting controls the default permissions
for the creation of new files.
With a default <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">umask</xhtml:code> setting of 077, files and directories
created by users will not be readable by any other user on the
system. Users who wish to make specific files group- or
world-readable can accomplish this by using the chmod command.
Additionally, users can make all their files readable to their
group by default by setting a <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">umask</xhtml:code> of 027 in their shell
configuration files. If default per-user groups exist (that is, if
every user has a default group whose name is the same as that
user's username and whose only member is the user), then it may
even be safe for users to select a <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">umask</xhtml:code> of 007, making it very
easy to intentionally share files with groups of which the user is
a member.
<br xmlns="http://www.w3.org/1999/xhtml"/><br xmlns="http://www.w3.org/1999/xhtml"/>
<!--In addition, it may be necessary to change root's <tt>umask</tt>
temporarily in order to install software or files which must be
readable by other users, or to change the default umasks of certain
service accounts such as the FTP user. However, setting a
restrictive default protects the files of users who have not taken
steps to make their files more available, and preventing files from
being inadvertently shared.-->
</description>
<Value id="xccdf_org.ssgproject.content_value_var_accounts_user_umask" operator="equals" type="string">
<title xml:lang="en-US">Sensible umask</title>
<description xml:lang="en-US">Enter default user umask</description>
<value>027</value>
<value selector="007">007</value>
<value selector="022">022</value>
<value selector="027">027</value>
<value selector="077">077</value>
</Value>
<Rule id="xccdf_org.ssgproject.content_rule_accounts_umask_bashrc" selected="false" severity="low">
<title xml:lang="en-US">Ensure the Default Bash Umask is Set Correctly</title>
<description xml:lang="en-US">
To ensure the default umask for users of the Bash shell is set properly,
add or correct the <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">umask</xhtml:code> setting in <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/bashrc</xhtml:code> to read
as follows:
<pre xmlns="http://www.w3.org/1999/xhtml">umask <sub xmlns="http://checklists.nist.gov/xccdf/1.2" idref="xccdf_org.ssgproject.content_value_var_accounts_user_umask" use="legacy"/></pre>
</description>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf"/>
<reference href="http://iase.disa.mil/stigs/cci/Pages/index.aspx">366</reference>
<rationale xml:lang="en-US">The umask value influences the permissions assigned to files when they are created.
A misconfigured umask value could result in files with excessive permissions that can be read or
written to by unauthorized users.</rationale>
<check system="ocil-transitional">
<check-export export-name="the above command returns no output, or if the umask is configured incorrectly" value-id="xccdf_org.ssgproject.content_value_conditional_clause"/>
<check-content>
Verify the <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">umask</xhtml:code> setting is configured correctly in the <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/bashrc</xhtml:code> file by
running the following command:
<pre xmlns="http://www.w3.org/1999/xhtml">$ grep "umask" /etc/bashrc</pre>
All output must show the value of <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">umask</xhtml:code> set to 077, as shown below:
<pre xmlns="http://www.w3.org/1999/xhtml">$ grep "umask" /etc/bashrc
umask 077
umask 077</pre>
</check-content>
</check>
</Rule>
<Rule id="xccdf_org.ssgproject.content_rule_accounts_umask_cshrc" selected="false" severity="low">
<title xml:lang="en-US">Ensure the Default C Shell Umask is Set Correctly</title>
<description xml:lang="en-US">
To ensure the default umask for users of the C shell is set properly,
add or correct the <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">umask</xhtml:code> setting in <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/csh.cshrc</xhtml:code> to read as follows:
<pre xmlns="http://www.w3.org/1999/xhtml">umask <sub xmlns="http://checklists.nist.gov/xccdf/1.2" idref="xccdf_org.ssgproject.content_value_var_accounts_user_umask" use="legacy"/></pre>
</description>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf"/>
<reference href="http://iase.disa.mil/stigs/cci/Pages/index.aspx">366</reference>
<rationale xml:lang="en-US">The umask value influences the permissions assigned to files when they are created.
A misconfigured umask value could result in files with excessive permissions that can be read or
written to by unauthorized users.</rationale>
<check system="ocil-transitional">
<check-export export-name="the above command returns no output, or if the umask is configured incorrectly" value-id="xccdf_org.ssgproject.content_value_conditional_clause"/>
<check-content>
Verify the <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">umask</xhtml:code> setting is configured correctly in the <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/csh.cshrc</xhtml:code> file by
running the following command:
<pre xmlns="http://www.w3.org/1999/xhtml">$ grep "umask" /etc/csh.cshrc</pre>
All output must show the value of <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">umask</xhtml:code> set to 077, as shown in the below:
<pre xmlns="http://www.w3.org/1999/xhtml">$ grep "umask" /etc/csh.cshrc
umask 077</pre>
</check-content>
</check>
</Rule>
<Rule id="xccdf_org.ssgproject.content_rule_accounts_umask_etc_profile" selected="false" severity="low">
<title xml:lang="en-US">Ensure the Default Umask is Set Correctly in /etc/profile</title>
<description xml:lang="en-US">
To ensure the default umask controlled by <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/profile</xhtml:code> is set properly,
add or correct the <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">umask</xhtml:code> setting in <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/profile</xhtml:code> to read as follows:
<pre xmlns="http://www.w3.org/1999/xhtml">umask <sub xmlns="http://checklists.nist.gov/xccdf/1.2" idref="xccdf_org.ssgproject.content_value_var_accounts_user_umask" use="legacy"/></pre>
</description>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf"/>
<reference href="http://iase.disa.mil/stigs/cci/Pages/index.aspx">366</reference>
<rationale xml:lang="en-US">The umask value influences the permissions assigned to files when they are created.
A misconfigured umask value could result in files with excessive permissions that can be read or
written to by unauthorized users.</rationale>
<check system="ocil-transitional">
<check-export export-name="the above command returns no output, or if the umask is configured incorrectly" value-id="xccdf_org.ssgproject.content_value_conditional_clause"/>
<check-content>
Verify the <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">umask</xhtml:code> setting is configured correctly in the <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/profile</xhtml:code> file by
running the following command:
<pre xmlns="http://www.w3.org/1999/xhtml">$ grep "umask" /etc/profile</pre>
All output must show the value of <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">umask</xhtml:code> set to 077, as shown in the below:
<pre xmlns="http://www.w3.org/1999/xhtml">$ grep "umask" /etc/profile
umask 077</pre>
</check-content>
</check>
</Rule>
<Rule id="xccdf_org.ssgproject.content_rule_accounts_umask_login_defs" selected="false" severity="low">
<title xml:lang="en-US">Ensure the Default Umask is Set Correctly in login.defs</title>
<description xml:lang="en-US">
To ensure the default umask controlled by <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/login.defs</xhtml:code> is set properly,
add or correct the <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">UMASK</xhtml:code> setting in <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/login.defs</xhtml:code> to read as follows:
<pre xmlns="http://www.w3.org/1999/xhtml">UMASK <sub xmlns="http://checklists.nist.gov/xccdf/1.2" idref="xccdf_org.ssgproject.content_value_var_accounts_user_umask" use="legacy"/></pre>
</description>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf"/>
<reference href="http://iase.disa.mil/stigs/cci/Pages/index.aspx">366</reference>
<rationale xml:lang="en-US">The umask value influences the permissions assigned to files when they are created.
A misconfigured umask value could result in files with excessive permissions that can be read and
written to by unauthorized users.</rationale>
<check system="ocil-transitional">
<check-export export-name="the above command returns no output, or if the umask is configured incorrectly" value-id="xccdf_org.ssgproject.content_value_conditional_clause"/>
<check-content>
Verify the <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">UMASK</xhtml:code> setting is configured correctly in the <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/login.defs</xhtml:code> file by
running the following command:
<pre xmlns="http://www.w3.org/1999/xhtml">$ grep -i "UMASK" /etc/login.defs</pre>
All output must show the value of <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">umask</xhtml:code> set to 077, as shown in the below:
<pre xmlns="http://www.w3.org/1999/xhtml">$ grep -i "UMASK" /etc/login.defs
umask 077</pre>
</check-content>
</check>
</Rule>
</Group>
</Group>
<Group id="xccdf_org.ssgproject.content_group_accounts-pam">
<title xml:lang="en-US">Protect Accounts by Configuring PAM</title>
<description xml:lang="en-US">PAM, or Pluggable Authentication Modules, is a system
which implements modular authentication for Linux programs. PAM provides
a flexible and configurable architecture for authentication, and it should be configured
to minimize exposure to unnecessary risk. This section contains
guidance on how to accomplish that.
<br xmlns="http://www.w3.org/1999/xhtml"/><br xmlns="http://www.w3.org/1999/xhtml"/>
PAM is implemented as a set of shared objects which are
loaded and invoked whenever an application wishes to authenticate a
user. Typically, the application must be running as root in order
to take advantage of PAM, because PAM's modules often need to be able
to access sensitive stores of account information, such as /etc/shadow.
Traditional privileged network listeners
(e.g. sshd) or SUID programs (e.g. sudo) already meet this
requirement. An SUID root application, userhelper, is provided so
that programs which are not SUID or privileged themselves can still
take advantage of PAM.
<br xmlns="http://www.w3.org/1999/xhtml"/><br xmlns="http://www.w3.org/1999/xhtml"/>
PAM looks in the directory <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/pam.d</xhtml:code> for
application-specific configuration information. For instance, if
the program login attempts to authenticate a user, then PAM's
libraries follow the instructions in the file <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/pam.d/login</xhtml:code>
to determine what actions should be taken.
<br xmlns="http://www.w3.org/1999/xhtml"/><br xmlns="http://www.w3.org/1999/xhtml"/>
One very important file in <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/pam.d</xhtml:code> is
<xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/pam.d/system-auth</xhtml:code>. This file, which is included by
many other PAM configuration files, defines 'default' system authentication
measures. Modifying this file is a good way to make far-reaching
authentication changes, for instance when implementing a
centralized authentication service.</description>
<warning xml:lang="en-US" override="false" category="general">Be careful when making changes to PAM's
configuration files. The syntax for these files is complex, and
modifications can have unexpected consequences. The default
configurations shipped with applications should be sufficient for
most users.</warning>
<warning xml:lang="en-US" override="false" category="general">Running <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">authconfig</xhtml:code> or
<xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">system-config-authentication</xhtml:code> will re-write the PAM configuration
files, destroying any manually made changes and replacing them with
a series of system defaults. One reference to the configuration
file syntax can be found at
http://www.kernel.org/pub/linux/libs/pam/Linux-PAM-html/sag-configuration-file.html.</warning>
<Value id="xccdf_org.ssgproject.content_value_var_password_pam_unix_remember" operator="equals" type="number">
<title xml:lang="en-US">remember</title>
<description xml:lang="en-US">The last n passwords for each user are saved in
<xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/security/opasswd</xhtml:code> in order to force password change history and
keep the user from alternating between the same password too
frequently.</description>
<value>24</value>
<value selector="0">0</value>
<value selector="5">5</value>
<value selector="10">10</value>
<value selector="24">24</value>
</Value>
<Rule id="xccdf_org.ssgproject.content_rule_display_login_attempts" selected="false" severity="low">
<title xml:lang="en-US">Set Last Logon/Access Notification</title>
<description xml:lang="en-US">To configure the system to notify users of last logon/access
using <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">pam_lastlog</xhtml:code>, add the following line immediately after <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">session required pam_limits.so</xhtml:code>:
<pre xmlns="http://www.w3.org/1999/xhtml">session required pam_lastlog.so showfailed</pre>
</description>
<reference href="http://iase.disa.mil/stigs/cci/Pages/index.aspx">53</reference>
<rationale xml:lang="en-US">
Users need to be aware of activity that occurs regarding
their account. Providing users with information regarding the number
of unsuccessful attempts that were made to login to their account
allows the user to determine if any unauthorized activity has occurred
and gives them an opportunity to notify administrators.
</rationale>
<check system="ocil-transitional">
<check-export export-name="that is not the case" value-id="xccdf_org.ssgproject.content_value_conditional_clause"/>
<check-content>
To ensure that last logon/access notification is configured correctly, run
the following command:
<pre xmlns="http://www.w3.org/1999/xhtml">$ grep pam_lastlog.so /etc/pam.d/system-auth</pre>
The output should show output <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">showfailed</xhtml:code>.
</check-content>
</check>
</Rule>
<Group id="xccdf_org.ssgproject.content_group_password_quality">
<title xml:lang="en-US">Set Password Quality Requirements</title>
<description xml:lang="en-US">The default <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">pam_pwquality</xhtml:code> PAM module provides strength
checking for passwords. It performs a number of checks, such as
making sure passwords are not similar to dictionary words, are of
at least a certain length, are not the previous password reversed,
and are not simply a change of case from the previous password. It
can also require passwords to be in certain character classes. The
<xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">pam_pwquality</xhtml:code> module is the preferred way of configuring
password requirements.
<br xmlns="http://www.w3.org/1999/xhtml"/><br xmlns="http://www.w3.org/1999/xhtml"/>
The <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">pam_cracklib</xhtml:code> PAM module can also provide strength
checking for passwords as the <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">pam_pwquality</xhtml:code> module.
It performs a number of checks, such as making sure passwords are
not similar to dictionary words, are of at least a certain length,
are not the previous password reversed, and are not simply a change
of case from the previous password. It can also require passwords to
be in certain character classes.
<br xmlns="http://www.w3.org/1999/xhtml"/><br xmlns="http://www.w3.org/1999/xhtml"/>
The <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">pam_passwdqc</xhtml:code> PAM module also provides the ability to enforce
stringent password strength requirements. It is provided
in an RPM of the same name and can be configured by setting the configuration
settings in <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/passwdqc.conf</xhtml:code>.
<br xmlns="http://www.w3.org/1999/xhtml"/><br xmlns="http://www.w3.org/1999/xhtml"/>
The man pages <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">pam_cracklib(8)</xhtml:code> and <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">pam_passwdqc(8)</xhtml:code>
provide information on the capabilities and configuration of
each.</description>
<Group id="xccdf_org.ssgproject.content_group_password_quality_pwquality">
<title xml:lang="en-US">Set Password Quality Requirements with pam_pwquality</title>
<description xml:lang="en-US">The <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">pam_pwquality</xhtml:code> PAM module can be configured to meet
requirements for a variety of policies.
<br xmlns="http://www.w3.org/1999/xhtml"/><br xmlns="http://www.w3.org/1999/xhtml"/>
For example, to configure <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">pam_pwquality</xhtml:code> to require at least one uppercase
character, lowercase character, digit, and other (special)
character, make sure that <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">pam_pwquality</xhtml:code> exists in <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/pam.d/system-auth</xhtml:code>:
<pre xmlns="http://www.w3.org/1999/xhtml">password requisite pam_pwquality.so try_first_pass local_users_only retry=3 authtok_type=</pre>
If no such line exists, add one as the first line of the password section in <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/pam.d/system-auth</xhtml:code>.
Next, modify the settings in <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/security/pwquality.conf</xhtml:code> to match the following:
<pre xmlns="http://www.w3.org/1999/xhtml">difok = 4
minlen = 14
dcredit = -1
ucredit = -1
lcredit = -1
ocredit = -1
maxrepeat = 3</pre>
The arguments can be modified to ensure compliance with
your organization's security policy. Discussion of each parameter follows.
</description>
<warning xml:lang="en-US" override="false" category="general">Note that the password quality
requirements are not enforced for the root account for some
reason.</warning>
<Value id="xccdf_org.ssgproject.content_value_var_password_pam_retry" operator="equals" type="number">
<title xml:lang="en-US">retry</title>
<description xml:lang="en-US">Number of retry attempts before erroring out</description>
<value>3</value>
<value selector="1">1</value>
<value selector="2">2</value>
<value selector="3">3</value>
</Value>
<Value id="xccdf_org.ssgproject.content_value_var_password_pam_maxrepeat" operator="equals" type="number">
<title xml:lang="en-US">maxrepeat</title>
<description xml:lang="en-US">Maximum Number of Consecutive Repeating Characters in a Password</description>
<value>3</value>
<value selector="1">1</value>
<value selector="2">2</value>
<value selector="3">3</value>
</Value>
<Value id="xccdf_org.ssgproject.content_value_var_password_pam_minlen" operator="equals" type="number">
<title xml:lang="en-US">minlen</title>
<description xml:lang="en-US">Minimum number of characters in password</description>
<value>14</value>
<value selector="6">6</value>
<value selector="8">8</value>
<value selector="10">10</value>
<value selector="12">12</value>
<value selector="14">14</value>
<value selector="15">15</value>
</Value>
<Value id="xccdf_org.ssgproject.content_value_var_password_pam_dcredit" operator="equals" type="number">
<title xml:lang="en-US">dcredit</title>
<description xml:lang="en-US">Minimum number of digits in password</description>
<value>-1</value>
<value selector="2">-2</value>
<value selector="1">-1</value>
<value selector="0">0</value>
</Value>
<Value id="xccdf_org.ssgproject.content_value_var_password_pam_ocredit" operator="equals" type="number">
<title xml:lang="en-US">ocredit</title>
<description xml:lang="en-US">Minimum number of other (special characters) in
password</description>
<value>-1</value>
<value selector="2">-2</value>
<value selector="1">-1</value>
<value selector="0">0</value>
</Value>
<Value id="xccdf_org.ssgproject.content_value_var_password_pam_lcredit" operator="equals" type="number">
<title xml:lang="en-US">lcredit</title>
<description xml:lang="en-US">Minimum number of lower case in password</description>
<value>-1</value>
<value selector="2">-2</value>
<value selector="1">-1</value>
<value selector="0">0</value>
</Value>
<Value id="xccdf_org.ssgproject.content_value_var_password_pam_ucredit" operator="equals" type="number">
<title xml:lang="en-US">ucredit</title>
<description xml:lang="en-US">Minimum number of upper case in password</description>
<value>-1</value>
<value selector="2">-2</value>
<value selector="1">-1</value>
<value selector="0">0</value>
</Value>
<Value id="xccdf_org.ssgproject.content_value_var_password_pam_difok" operator="equals" type="number">
<title xml:lang="en-US">difok</title>
<description xml:lang="en-US">Minimum number of characters not present in old
password</description>
<warning xml:lang="en-US" override="false" category="general">Keep this high for short
passwords</warning>
<value>4</value>
<value selector="2">2</value>
<value selector="3">3</value>
<value selector="4">4</value>
<value selector="5">5</value>
</Value>
<Value id="xccdf_org.ssgproject.content_value_var_password_pam_minclass" operator="equals" type="number">
<title xml:lang="en-US">minclass</title>
<description xml:lang="en-US">Minimum number of categories of characters that must exist in a password</description>
<value>3</value>
<value selector="1">1</value>
<value selector="2">2</value>
<value selector="3">3</value>
<value selector="4">4</value>
</Value>
<Value id="xccdf_org.ssgproject.content_value_var_accounts_passwords_pam_faillock_deny" operator="equals" type="number">
<title xml:lang="en-US">fail_deny</title>
<description xml:lang="en-US">Number of failed login attempts before account lockout</description>
<value>3</value>
<value selector="3">3</value>
<value selector="5">5</value>
<value selector="10">10</value>
</Value>
<Value id="xccdf_org.ssgproject.content_value_var_accounts_passwords_pam_faillock_unlock_time" operator="equals" type="number">
<title xml:lang="en-US">fail_unlock_time</title>
<description xml:lang="en-US">Seconds before automatic unlocking after excessive failed logins</description>
<value>604800</value>
<value selector="900">900</value>
<value selector="1800">1800</value>
<value selector="3600">3600</value>
<value selector="86400">86400</value>
<value selector="604800">604800</value>
</Value>
<Value id="xccdf_org.ssgproject.content_value_var_accounts_passwords_pam_faillock_fail_interval" operator="equals" type="number">
<title xml:lang="en-US">fail_interval</title>
<description xml:lang="en-US">Interval for counting failed login attempts before account lockout</description>
<value>900</value>
<value selector="900">900</value>
<value selector="1800">1800</value>
<value selector="3600">3600</value>
<value selector="86400">86400</value>
<value selector="100000000">100000000</value>
</Value>
<Rule id="xccdf_org.ssgproject.content_rule_accounts_password_pam_retry" selected="false" severity="low">
<title xml:lang="en-US">Set Password Retry Prompts Permitted Per-Session</title>
<description xml:lang="en-US">To configure the number of retry prompts that are permitted per-session:
<br xmlns="http://www.w3.org/1999/xhtml"/><br xmlns="http://www.w3.org/1999/xhtml"/>
Edit the <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">pam_pwquality.so</xhtml:code> statement in <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/pam.d/system-auth</xhtml:code> to
show <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">retry=<sub idref="xccdf_org.ssgproject.content_value_var_password_pam_retry" use="legacy"/></xhtml:code>, or a lower value if site policy is more restrictive.
<br xmlns="http://www.w3.org/1999/xhtml"/><br xmlns="http://www.w3.org/1999/xhtml"/>
The DoD requirement is a maximum of 3 prompts per session.
</description>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">IA-5(c)</reference>
<reference href="http://iase.disa.mil/stigs/cci/Pages/index.aspx"/>
<rationale xml:lang="en-US">
Setting the password retry prompts that are permitted on a per-session basis to a low value
requires some software, such as SSH, to re-connect. This can slow down and
draw additional attention to some types of password-guessing attacks. Note that this
is different from account lockout, which is provided by the pam_faillock module.
</rationale>
<check system="http://oval.mitre.org/XMLSchema/oval-definitions-5">
<check-export export-name="oval:ssg:var:467" value-id="xccdf_org.ssgproject.content_value_var_password_pam_retry"/>
<check-content-ref name="oval:ssg:def:185" href="ssg-fedora-oval.xml"/>
</check>
<check system="ocil-transitional">
<check-export export-name="it is not the required value" value-id="xccdf_org.ssgproject.content_value_conditional_clause"/>
<check-content>
To check how many retry attempts are permitted on a per-session basis, run the following command:
<pre xmlns="http://www.w3.org/1999/xhtml">$ grep pam_pwquality /etc/pam.d/system-auth</pre>
The <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">retry</xhtml:code> parameter will indicate how many attempts are permitted.
The DoD required value is less than or equal to 3.
This would appear as <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">retry=3</xhtml:code>, or a lower value.
</check-content>
</check>
</Rule>
<Rule id="xccdf_org.ssgproject.content_rule_accounts_password_pam_maxrepeat" selected="false" severity="low">
<title xml:lang="en-US">Set Password to Maximum of Three Consecutive Repeating Characters</title>
<description xml:lang="en-US">The pam_pwquality module's <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">maxrepeat</xhtml:code> parameter controls requirements for
consecutive repeating characters. When set to a positive number, it will reject passwords
which contain more than that number of consecutive characters. Modify the <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">maxrepeat</xhtml:code> setting
in <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/security/pwquality.conf</xhtml:code> to prevent a run of (<sub idref="xccdf_org.ssgproject.content_value_var_password_pam_maxrepeat" use="legacy"/> + 1) or more identical characters.
</description>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">IA-5(c)</reference>
<reference href="http://iase.disa.mil/stigs/cci/Pages/index.aspx">366</reference>
<rationale xml:lang="en-US">
Passwords with excessive repeating characters may be more vulnerable to password-guessing attacks.
</rationale>
<check system="http://oval.mitre.org/XMLSchema/oval-definitions-5">
<check-export export-name="oval:ssg:var:473" value-id="xccdf_org.ssgproject.content_value_var_password_pam_maxrepeat"/>
<check-content-ref name="oval:ssg:def:235" href="ssg-fedora-oval.xml"/>
</check>
<check system="ocil-transitional">
<check-export export-name="maxrepeat is not found or not set to the required value" value-id="xccdf_org.ssgproject.content_value_conditional_clause"/>
<check-content>
To check the maximum value for consecutive repeating characters, run the following command:
<pre xmlns="http://www.w3.org/1999/xhtml">$ grep maxrepeat /etc/security/pwquality.conf</pre>
Look for the value of the <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">maxrepeat</xhtml:code> parameter. The DoD requirement is 3 which would
appear as <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">maxrepeat = 3</xhtml:code>.
</check-content>
</check>
</Rule>
<Rule id="xccdf_org.ssgproject.content_rule_accounts_password_pam_dcredit" selected="false" severity="low">
<title xml:lang="en-US">Set Password Strength Minimum Digit Characters</title>
<description xml:lang="en-US">The pam_pwquality module's <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">dcredit</xhtml:code> parameter controls requirements for
usage of digits in a password. When set to a negative number, any password will be required to
contain that many digits. When set to a positive number, pam_pwquality will grant +1 additional
length credit for each digit. Modify the <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">dcredit</xhtml:code> setting in
<xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/security/pwquality.conf</xhtml:code> to require the use of a digit in passwords.
</description>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">IA-5(b)</reference>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">IA-5(c)</reference>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">194</reference>
<reference href="http://iase.disa.mil/stigs/cci/Pages/index.aspx"/>
<rationale xml:lang="en-US">
Requiring digits makes password guessing attacks more difficult by ensuring a larger
search space.
</rationale>
<check system="http://oval.mitre.org/XMLSchema/oval-definitions-5">
<check-export export-name="oval:ssg:var:478" value-id="xccdf_org.ssgproject.content_value_var_password_pam_dcredit"/>
<check-content-ref name="oval:ssg:def:285" href="ssg-fedora-oval.xml"/>
</check>
<check system="ocil-transitional">
<check-export export-name="dcredit is not found or not set to the required value" value-id="xccdf_org.ssgproject.content_value_conditional_clause"/>
<check-content>
To check how many digits are required in a password, run the following command:
<pre xmlns="http://www.w3.org/1999/xhtml">$ grep dcredit /etc/security/pwquality.conf</pre>
The <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">dcredit</xhtml:code> parameter (as a negative number) will indicate how many digits are required.
The DoD requires at least one digit in a password. This would appear as <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">dcredit = -1</xhtml:code>.
</check-content>
</check>
</Rule>
<Rule id="xccdf_org.ssgproject.content_rule_accounts_password_pam_minlen" selected="false" severity="low">
<title xml:lang="en-US">Set Password Minimum Length</title>
<description xml:lang="en-US">The pam_pwquality module's <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">minlen</xhtml:code> parameter controls requirements for
minimum characters required in a password. Add <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">minlen=<sub idref="xccdf_org.ssgproject.content_value_var_password_pam_minlen" use="legacy"/></xhtml:code>
after pam_pwquality to set minimum password length requirements.
</description>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">IA-5(1)(a)</reference>
<reference href="http://iase.disa.mil/stigs/cci/Pages/index.aspx">205</reference>
<reference href="">78</reference>
<rationale xml:lang="en-US">
Password length is one factor of several that helps to determine
strength and how long it takes to crack a password. Use of more characters in
a password helps to exponentially increase the time and/or resources
required to compromise the password.
</rationale>
<check system="http://oval.mitre.org/XMLSchema/oval-definitions-5">
<check-export export-name="oval:ssg:var:468" value-id="xccdf_org.ssgproject.content_value_var_password_pam_minlen"/>
<check-content-ref name="oval:ssg:def:190" href="ssg-fedora-oval.xml"/>
</check>
<check system="ocil-transitional">
<check-export export-name="minlen is not found or not set to the required value (or higher)" value-id="xccdf_org.ssgproject.content_value_conditional_clause"/>
<check-content>
To check how many characters are required in a password, run the following command:
<pre xmlns="http://www.w3.org/1999/xhtml">$ grep minlen /etc/security/pwquality.conf</pre>
Your output should contain <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">minlen = <sub idref="xccdf_org.ssgproject.content_value_var_password_pam_minlen" use="legacy"/></xhtml:code>
</check-content>
</check>
</Rule>
<Rule id="xccdf_org.ssgproject.content_rule_accounts_password_pam_ucredit" selected="false" severity="low">
<title xml:lang="en-US">Set Password Strength Minimum Uppercase Characters</title>
<description xml:lang="en-US">The pam_pwquality module's <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">ucredit=</xhtml:code> parameter controls requirements for
usage of uppercase letters in a password. When set to a negative number, any password will be required to
contain that many uppercase characters. When set to a positive number, pam_pwquality will grant +1 additional
length credit for each uppercase character. Modify the <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">ucredit</xhtml:code> setting in
<xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/security/pwquality.conf</xhtml:code> to require the use of an uppercase character in passwords.
</description>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">IA-5(b)</reference>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">IA-5(c)</reference>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">IA-5(1)(a)</reference>
<reference href="http://iase.disa.mil/stigs/cci/Pages/index.aspx"/>
<rationale xml:lang="en-US">
Requiring a minimum number of uppercase characters makes password guessing attacks
more difficult by ensuring a larger search space.
</rationale>
<check system="http://oval.mitre.org/XMLSchema/oval-definitions-5">
<check-export export-name="oval:ssg:var:469" value-id="xccdf_org.ssgproject.content_value_var_password_pam_ucredit"/>
<check-content-ref name="oval:ssg:def:214" href="ssg-fedora-oval.xml"/>
</check>
<check system="ocil-transitional">
<check-export export-name="ucredit is not found or not set to the required value" value-id="xccdf_org.ssgproject.content_value_conditional_clause"/>
<check-content>
To check how many uppercase characters are required in a password, run the following command:
<pre xmlns="http://www.w3.org/1999/xhtml">$ grep ucredit /etc/security/pwquality.conf</pre>
The <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">ucredit</xhtml:code> parameter (as a negative number) will indicate how many uppercase characters are required.
The DoD and FISMA require at least one uppercase character in a password.
This would appear as <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">ucredit = -1</xhtml:code>.
</check-content>
</check>
</Rule>
<Rule id="xccdf_org.ssgproject.content_rule_accounts_password_pam_ocredit" selected="false" severity="low">
<title xml:lang="en-US">Set Password Strength Minimum Special Characters</title>
<description xml:lang="en-US">The pam_pwquality module's <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">ocredit=</xhtml:code> parameter controls requirements for
usage of special (or "other") characters in a password. When set to a negative number, any password will be
required to contain that many special characters. When set to a positive number, pam_pwquality will grant +1
additional length credit for each special character. Modify the <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">ocredit</xhtml:code> setting in
<xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/security/pwquality.conf</xhtml:code> to require use of a special character in passwords.
</description>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">IA-5(b)</reference>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">IA-5(c)</reference>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">IA-5(1)(a)</reference>
<reference href="http://iase.disa.mil/stigs/cci/Pages/index.aspx"/>
<rationale xml:lang="en-US">
Requiring a minimum number of special characters makes password guessing attacks
more difficult by ensuring a larger search space.
</rationale>
<check system="http://oval.mitre.org/XMLSchema/oval-definitions-5">
<check-export export-name="oval:ssg:var:471" value-id="xccdf_org.ssgproject.content_value_var_password_pam_ocredit"/>
<check-content-ref name="oval:ssg:def:229" href="ssg-fedora-oval.xml"/>
</check>
<check system="ocil-transitional">
<check-export export-name="ocredit is not found or not set to the required value" value-id="xccdf_org.ssgproject.content_value_conditional_clause"/>
<check-content>
To check how many special characters are required in a password, run the following command:
<pre xmlns="http://www.w3.org/1999/xhtml">$ grep ocredit /etc/security/pwquality.conf</pre>
The <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">ocredit</xhtml:code> parameter (as a negative number) will indicate how many special characters are required.
The DoD and FISMA require at least one special character in a password.
This would appear as <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">ocredit = -1</xhtml:code>.
</check-content>
</check>
</Rule>
<Rule id="xccdf_org.ssgproject.content_rule_accounts_password_pam_lcredit" selected="false" severity="low">
<title xml:lang="en-US">Set Password Strength Minimum Lowercase Characters</title>
<description xml:lang="en-US">The pam_pwquality module's <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">lcredit</xhtml:code> parameter controls requirements for
usage of lowercase letters in a password. When set to a negative number, any password will be required to
contain that many lowercase characters. When set to a positive number, pam_pwquality will grant +1 additional
length credit for each lowercase character. Modify the <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">lcredit</xhtml:code> setting in
<xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/security/pwquality.conf</xhtml:code> to require the use of a lowercase character in passwords.
</description>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">IA-5(b)</reference>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">IA-5(c)</reference>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">IA-5(1)(a)</reference>
<reference href="http://iase.disa.mil/stigs/cci/Pages/index.aspx"/>
<rationale xml:lang="en-US">
Requiring a minimum number of lowercase characters makes password guessing attacks
more difficult by ensuring a larger search space.
</rationale>
<check system="http://oval.mitre.org/XMLSchema/oval-definitions-5">
<check-export export-name="oval:ssg:var:476" value-id="xccdf_org.ssgproject.content_value_var_password_pam_lcredit"/>
<check-content-ref name="oval:ssg:def:262" href="ssg-fedora-oval.xml"/>
</check>
<check system="ocil-transitional">
<check-export export-name="lcredit is not found or not set to the required value" value-id="xccdf_org.ssgproject.content_value_conditional_clause"/>
<check-content>
To check how many lowercase characters are required in a password, run the following command:
<pre xmlns="http://www.w3.org/1999/xhtml">$ grep lcredit /etc/security/pwquality.conf</pre>
The <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">lcredit</xhtml:code> parameter (as a negative number) will indicate how many special characters are required.
The DoD and FISMA require at least one lowercase character in a password.
This would appear as <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">lcredit = -1</xhtml:code>.
</check-content>
</check>
</Rule>
<Rule id="xccdf_org.ssgproject.content_rule_accounts_password_pam_difok" selected="false" severity="low">
<title xml:lang="en-US">Set Password Strength Minimum Different Characters</title>
<description xml:lang="en-US">The pam_pwquality module's <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">difok</xhtml:code> parameter controls requirements for usage of different
characters during a password change. Modify the <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">difok</xhtml:code> setting in <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/security/pwquality.conf</xhtml:code>
to require differing characters when changing passwords. The DoD requirement is <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">4</xhtml:code>.
</description>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">IA-5(b)</reference>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">IA-5(c)</reference>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">IA-5(1)(b)</reference>
<reference href="http://iase.disa.mil/stigs/cci/Pages/index.aspx"/>
<rationale xml:lang="en-US">
Requiring a minimum number of different characters during password changes ensures that
newly changed passwords should not resemble previously compromised ones.
Note that passwords which are changed on compromised systems will still be compromised, however.
</rationale>
<check system="http://oval.mitre.org/XMLSchema/oval-definitions-5">
<check-export export-name="oval:ssg:var:474" value-id="xccdf_org.ssgproject.content_value_var_password_pam_difok"/>
<check-content-ref name="oval:ssg:def:247" href="ssg-fedora-oval.xml"/>
</check>
<check system="ocil-transitional">
<check-export export-name="difok is not found or not set to the required value" value-id="xccdf_org.ssgproject.content_value_conditional_clause"/>
<check-content>
To check how many characters must differ during a password change, run the following command:
<pre xmlns="http://www.w3.org/1999/xhtml">$ grep difok /etc/security/pwquality.conf</pre>
The <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">difok</xhtml:code> parameter will indicate how many characters must differ. The DoD requires four characters
differ during a password change. This would appear as <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">difok = 4</xhtml:code>.
</check-content>
</check>
</Rule>
<Rule id="xccdf_org.ssgproject.content_rule_accounts_password_pam_minclass" selected="false" severity="low">
<title xml:lang="en-US">Set Password Strength Minimum Different Categories</title>
<description xml:lang="en-US">The pam_cracklib module's <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">minclass</xhtml:code> parameter controls requirements for
usage of different character classes, or types, of character that must exist in a password
before it is considered valid. For example, setting this value to three (3) requires that
any password must have characters from at least three different categories in order to be
approved. The default value is zero (0), meaning there are no required classes. There are
four categories available:
<pre xmlns="http://www.w3.org/1999/xhtml">
* Upper-case characters
* Lower-case characters
* Digits
* Special characters (for example, punctuation)
</pre>
Modify the <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">minclass</xhtml:code> setting in <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/security/pwquality.conf</xhtml:code> entry to require
differing categories of characters when changing passwords. The minimum requirement is <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">3</xhtml:code>.
</description>
<rationale xml:lang="en-US">
Requiring a minimum number of character categories makes password guessing attacks
more difficult by ensuring a larger search space.
</rationale>
<check system="http://oval.mitre.org/XMLSchema/oval-definitions-5">
<check-export export-name="oval:ssg:var:463" value-id="xccdf_org.ssgproject.content_value_var_password_pam_minclass"/>
<check-content-ref name="oval:ssg:def:129" href="ssg-fedora-oval.xml"/>
</check>
<check system="ocil-transitional">
<check-export export-name="minclass is not found or not set to the required value" value-id="xccdf_org.ssgproject.content_value_conditional_clause"/>
<check-content>
To check how many categories of characters must be used in password during a password change,
run the following command:
<pre xmlns="http://www.w3.org/1999/xhtml">$ grep minclass /etc/security/pwquality.conf</pre>
The <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">minclass</xhtml:code> parameter will indicate how many character classes must be used. If
the requirement was for the password to contain characters from three different categories,
then this would appear as <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">minclass = 3</xhtml:code>.
</check-content>
</check>
</Rule>
</Group>
</Group>
<Group id="xccdf_org.ssgproject.content_group_locking_out_password_attempts">
<title xml:lang="en-US">Set Lockouts for Failed Password Attempts</title>
<description xml:lang="en-US">The <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">pam_faillock</xhtml:code> PAM module provides the capability to
lock out user accounts after a number of failed login attempts. Its
documentation is available in
<xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/usr/share/doc/pam-VERSION/txts/README.pam_faillock</xhtml:code>.
<br xmlns="http://www.w3.org/1999/xhtml"/><br xmlns="http://www.w3.org/1999/xhtml"/>
</description>
<warning xml:lang="en-US" override="false" category="general">Locking out user accounts presents the
risk of a denial-of-service attack. The lockout policy
must weigh whether the risk of such a
denial-of-service attack outweighs the benefits of thwarting
password guessing attacks.</warning>
<Rule id="xccdf_org.ssgproject.content_rule_accounts_passwords_pam_faillock_deny" selected="false" severity="medium">
<title xml:lang="en-US">Set Deny For Failed Password Attempts</title>
<description xml:lang="en-US">
To configure the system to lock out accounts after a number of incorrect login
attempts using <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">pam_faillock.so</xhtml:code>:
<br xmlns="http://www.w3.org/1999/xhtml"/><br xmlns="http://www.w3.org/1999/xhtml"/>
Add the following lines immediately below the <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">pam_unix.so</xhtml:code> statement in <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">AUTH</xhtml:code> section of
both <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/pam.d/system-auth</xhtml:code> and /etc/pam.d/password-auth:
<pre xmlns="http://www.w3.org/1999/xhtml">auth [default=die] pam_faillock.so authfail deny=<sub xmlns="http://checklists.nist.gov/xccdf/1.2" idref="xccdf_org.ssgproject.content_value_var_accounts_passwords_pam_faillock_deny" use="legacy"/> unlock_time=604800 fail_interval=900</pre>
<pre xmlns="http://www.w3.org/1999/xhtml">auth required pam_faillock.so authsucc deny=<sub xmlns="http://checklists.nist.gov/xccdf/1.2" idref="xccdf_org.ssgproject.content_value_var_accounts_passwords_pam_faillock_deny" use="legacy"/> unlock_time=604800 fail_interval=900</pre>
</description>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">AC-7(a)</reference>
<reference href="http://iase.disa.mil/stigs/cci/Pages/index.aspx"/>
<rationale xml:lang="en-US">
Locking out user accounts after a number of incorrect attempts
prevents direct password guessing attacks.
</rationale>
<check system="http://oval.mitre.org/XMLSchema/oval-definitions-5">
<check-export export-name="oval:ssg:var:466" value-id="xccdf_org.ssgproject.content_value_var_accounts_passwords_pam_faillock_deny"/>
<check-content-ref name="oval:ssg:def:157" href="ssg-fedora-oval.xml"/>
</check>
<check system="ocil-transitional">
<check-export export-name="that is not the case" value-id="xccdf_org.ssgproject.content_value_conditional_clause"/>
<check-content>
To ensure the failed password attempt policy is configured correctly, run the following command:
<pre xmlns="http://www.w3.org/1999/xhtml">$ grep pam_faillock /etc/pam.d/system-auth</pre>
The output should show <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">deny=3</xhtml:code>.
</check-content>
</check>
</Rule>
<Rule id="xccdf_org.ssgproject.content_rule_accounts_passwords_pam_faillock_unlock_time" selected="false" severity="medium">
<title xml:lang="en-US">Set Lockout Time For Failed Password Attempts</title>
<description xml:lang="en-US">
To configure the system to lock out accounts after a number of incorrect login
attempts and require an administrator to unlock the account using <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">pam_faillock.so</xhtml:code>:
<br xmlns="http://www.w3.org/1999/xhtml"/><br xmlns="http://www.w3.org/1999/xhtml"/>
Add the following lines immediately below the <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">pam_env.so</xhtml:code> statement in <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/pam.d/system-auth</xhtml:code>:
<pre xmlns="http://www.w3.org/1999/xhtml">auth [default=die] pam_faillock.so authfail deny=3 unlock_time=<sub xmlns="http://checklists.nist.gov/xccdf/1.2" idref="xccdf_org.ssgproject.content_value_var_accounts_passwords_pam_faillock_unlock_time" use="legacy"/> fail_interval=900</pre>
<pre xmlns="http://www.w3.org/1999/xhtml">auth required pam_faillock.so authsucc deny=3 unlock_time=<sub xmlns="http://checklists.nist.gov/xccdf/1.2" idref="xccdf_org.ssgproject.content_value_var_accounts_passwords_pam_faillock_unlock_time" use="legacy"/> fail_interval=900</pre>
</description>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">AC-7(b)</reference>
<reference href="http://iase.disa.mil/stigs/cci/Pages/index.aspx">47</reference>
<rationale xml:lang="en-US">
Locking out user accounts after a number of incorrect attempts
prevents direct password guessing attacks. Ensuring that an administrator is
involved in unlocking locked accounts draws appropriate attention to such
situations.
</rationale>
<check system="ocil-transitional">
<check-export export-name="that is not the case" value-id="xccdf_org.ssgproject.content_value_conditional_clause"/>
<check-content>
To ensure the failed password attempt policy is configured correctly, run the following command:
<pre xmlns="http://www.w3.org/1999/xhtml">$ grep pam_faillock /etc/pam.d/system-auth</pre>
The output should show <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">unlock_time=<some-large-number></xhtml:code>.
</check-content>
</check>
</Rule>
<Rule id="xccdf_org.ssgproject.content_rule_accounts_passwords_pam_fail_interval" selected="false" severity="medium">
<title xml:lang="en-US">Set Interval For Counting Failed Password Attempts</title>
<description xml:lang="en-US">
Utilizing <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">pam_faillock.so</xhtml:code>, the <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">fail_interval</xhtml:code> directive configures the system to lock out accounts after a number of incorrect login
attempts.
<br xmlns="http://www.w3.org/1999/xhtml"/><br xmlns="http://www.w3.org/1999/xhtml"/>
Add the following <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">fail_interval</xhtml:code> directives to <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">pam_faillock.so</xhtml:code> immediately below the <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">pam_env.so</xhtml:code> statement in
<xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/pam.d/system-auth</xhtml:code> and <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/pam.d/password-auth</xhtml:code>:
<pre xmlns="http://www.w3.org/1999/xhtml">auth [default=die] pam_faillock.so authfail deny=3 unlock_time=604800 fail_interval=<sub xmlns="http://checklists.nist.gov/xccdf/1.2" idref="xccdf_org.ssgproject.content_value_var_accounts_passwords_pam_faillock_fail_interval" use="legacy"/></pre>
<pre xmlns="http://www.w3.org/1999/xhtml">auth required pam_faillock.so authsucc deny=3 unlock_time=604800 fail_interval=<sub xmlns="http://checklists.nist.gov/xccdf/1.2" idref="xccdf_org.ssgproject.content_value_var_accounts_passwords_pam_faillock_fail_interval" use="legacy"/></pre>
</description>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">AC-7(a)</reference>
<reference href="http://iase.disa.mil/stigs/cci/Pages/index.aspx">1452</reference>
<rationale xml:lang="en-US">
Locking out user accounts after a number of incorrect attempts within a
specific period of time prevents direct password guessing attacks.
</rationale>
<check system="ocil-transitional">
<check-export export-name="that is not the case" value-id="xccdf_org.ssgproject.content_value_conditional_clause"/>
<check-content>
To ensure the failed password attempt policy is configured correctly, run the following command:
<pre xmlns="http://www.w3.org/1999/xhtml">$ grep pam_faillock /etc/pam.d/system-auth /etc/pam.d/password-auth</pre>
For each file, the output should show <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">fail_interval=<interval-in-seconds></xhtml:code> where <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">interval-in-seconds</xhtml:code> is 900 (15 minutes) or greater. If the <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">fail_interval</xhtml:code> parameter is not set, the default setting of 900 seconds is acceptable.
</check-content>
</check>
</Rule>
<Rule id="xccdf_org.ssgproject.content_rule_accounts_password_pam_unix_remember" selected="false" severity="medium">
<title xml:lang="en-US">Limit Password Reuse</title>
<description xml:lang="en-US">Do not allow users to reuse recent passwords. This can
be accomplished by using the <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">remember</xhtml:code> option for the <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">pam_unix</xhtml:code> PAM
module. In the file <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/pam.d/system-auth</xhtml:code>, append <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">remember=<sub idref="xccdf_org.ssgproject.content_value_var_password_pam_unix_remember" use="legacy"/></xhtml:code> to the
line which refers to the <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">pam_unix.so</xhtml:code> module, as shown:
<pre xmlns="http://www.w3.org/1999/xhtml">password sufficient pam_unix.so <i>existing_options</i> remember=<sub xmlns="http://checklists.nist.gov/xccdf/1.2" idref="xccdf_org.ssgproject.content_value_var_password_pam_unix_remember" use="legacy"/></pre>
The DoD and FISMA requirement is 24 passwords.</description>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">IA-5(f)</reference>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">IA-5(1)(e)</reference>
<reference href="http://iase.disa.mil/stigs/cci/Pages/index.aspx"/>
<rationale xml:lang="en-US">
Preventing re-use of previous passwords helps ensure that a compromised password is not re-used by a user.
</rationale>
<check system="http://oval.mitre.org/XMLSchema/oval-definitions-5">
<check-export export-name="oval:ssg:var:470" value-id="xccdf_org.ssgproject.content_value_var_password_pam_unix_remember"/>
<check-content-ref name="oval:ssg:def:225" href="ssg-fedora-oval.xml"/>
</check>
<check system="ocil-transitional">
<check-export export-name="it does not" value-id="xccdf_org.ssgproject.content_value_conditional_clause"/>
<check-content>
To verify the password reuse setting is compliant, run the following command:
<pre xmlns="http://www.w3.org/1999/xhtml">$ grep remember /etc/pam.d/system-auth</pre>
The output should show the following at the end of the line:
<pre xmlns="http://www.w3.org/1999/xhtml">remember=24</pre>
</check-content>
</check>
</Rule>
</Group>
<Group id="xccdf_org.ssgproject.content_group_set_password_hashing_algorithm">
<title xml:lang="en-US">Set Password Hashing Algorithm</title>
<description xml:lang="en-US">The system's default algorithm for storing password hashes in
<xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/shadow</xhtml:code> is SHA-512. This can be configured in several
locations.</description>
<Rule id="xccdf_org.ssgproject.content_rule_set_password_hashing_algorithm_systemauth" selected="false" severity="medium">
<title xml:lang="en-US">Set Password Hashing Algorithm in /etc/pam.d/system-auth</title>
<description xml:lang="en-US">
In <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/pam.d/system-auth</xhtml:code>, the <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">password</xhtml:code> section of
the file controls which PAM modules execute during a password change.
Set the <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">pam_unix.so</xhtml:code> module in the
<xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">password</xhtml:code> section to include the argument <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">sha512</xhtml:code>, as shown below:
<pre xmlns="http://www.w3.org/1999/xhtml">password sufficient pam_unix.so sha512 <i>other arguments...</i></pre>
This will help ensure when local users change their passwords, hashes for the new
passwords will be generated using the SHA-512 algorithm.
This is the default.
</description>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">IA-5(b)</reference>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">IA-5(c)</reference>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">IA-5(1)(c)</reference>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">IA-7</reference>
<reference href="http://iase.disa.mil/stigs/cci/Pages/index.aspx"/>
<rationale xml:lang="en-US">
Using a stronger hashing algorithm makes password cracking attacks more difficult.
</rationale>
<check system="ocil-transitional">
<check-export export-name="it does not" value-id="xccdf_org.ssgproject.content_value_conditional_clause"/>
<check-content>
Inspect the <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">password</xhtml:code> section of <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/pam.d/system-auth</xhtml:code> and
ensure that the <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">pam_unix.so</xhtml:code> module includes the argument
<xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">sha512</xhtml:code>:
<pre xmlns="http://www.w3.org/1999/xhtml">$ grep sha512 /etc/pam.d/system-auth</pre>
</check-content>
</check>
</Rule>
<Rule id="xccdf_org.ssgproject.content_rule_set_password_hashing_algorithm_logindefs" selected="false" severity="medium">
<title xml:lang="en-US">Set Password Hashing Algorithm in /etc/login.defs</title>
<description xml:lang="en-US">
In <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/login.defs</xhtml:code>, add or correct the following line to ensure
the system will use SHA-512 as the hashing algorithm:
<pre xmlns="http://www.w3.org/1999/xhtml">ENCRYPT_METHOD SHA512</pre>
</description>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">IA-5(b)</reference>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">IA-5(c)</reference>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">IA-5(1)(c)</reference>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">IA-7</reference>
<reference href="http://iase.disa.mil/stigs/cci/Pages/index.aspx"/>
<rationale xml:lang="en-US">
Using a stronger hashing algorithm makes password cracking attacks more difficult.
</rationale>
<check system="http://oval.mitre.org/XMLSchema/oval-definitions-5">
<check-content-ref name="oval:ssg:def:153" href="ssg-fedora-oval.xml"/>
</check>
<check system="ocil-transitional">
<check-export export-name="it does not" value-id="xccdf_org.ssgproject.content_value_conditional_clause"/>
<check-content>
Inspect <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/login.defs</xhtml:code> and ensure the following line appears:
<pre xmlns="http://www.w3.org/1999/xhtml">ENCRYPT_METHOD SHA512</pre>
</check-content>
</check>
</Rule>
<Rule id="xccdf_org.ssgproject.content_rule_set_password_hashing_algorithm_libuserconf" selected="false" severity="medium">
<title xml:lang="en-US">Set Password Hashing Algorithm in /etc/libuser.conf</title>
<description xml:lang="en-US">
In <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/libuser.conf</xhtml:code>, add or correct the following line in its
<xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">[defaults]</xhtml:code> section to ensure the system will use the SHA-512
algorithm for password hashing:
<pre xmlns="http://www.w3.org/1999/xhtml">crypt_style = sha512</pre>
</description>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">IA-5(b)</reference>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">IA-5(c)</reference>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">IA-5(1)(c)</reference>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">IA-7</reference>
<reference href="http://iase.disa.mil/stigs/cci/Pages/index.aspx"/>
<rationale xml:lang="en-US">
Using a stronger hashing algorithm makes password cracking attacks more difficult.
</rationale>
<check system="ocil-transitional">
<check-export export-name="it does not" value-id="xccdf_org.ssgproject.content_value_conditional_clause"/>
<check-content>
Inspect <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/libuser.conf</xhtml:code> and ensure the following line appears
in the <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">[default]</xhtml:code> section:
<pre xmlns="http://www.w3.org/1999/xhtml">crypt_style = sha512</pre>
</check-content>
</check>
</Rule>
</Group>
</Group>
<Group id="xccdf_org.ssgproject.content_group_accounts-physical">
<title xml:lang="en-US">Protect Physical Console Access</title>
<description xml:lang="en-US">It is impossible to fully protect a system from an
attacker with physical access, so securing the space in which the
system is located should be considered a necessary step. However,
there are some steps which, if taken, make it more difficult for an
attacker to quickly or undetectably modify a system from its
console.</description>
<Group id="xccdf_org.ssgproject.content_group_bootloader">
<title xml:lang="en-US">Set Boot Loader Password</title>
<description xml:lang="en-US">During the boot process, the boot loader is
responsible for starting the execution of the kernel and passing
options to it. The boot loader allows for the selection of
different kernels - possibly on different partitions or media.
The default Fedora boot loader for x86 systems is called GRUB2.
Options it can pass to the kernel include <i xmlns="http://www.w3.org/1999/xhtml">single-user mode</i>, which
provides root access without any authentication, and the ability to
disable SELinux. To prevent local users from modifying the boot
parameters and endangering security, protect the boot loader configuration
with a password and ensure its configuration file's permissions
are set properly.
</description>
<Rule id="xccdf_org.ssgproject.content_rule_file_user_owner_grub2_cfg" selected="false" severity="medium">
<title xml:lang="en-US">Verify /boot/grub2/grub.cfg User Ownership</title>
<description xml:lang="en-US">The file <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/boot/grub2/grub.cfg</xhtml:code> should
be owned by the <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">root</xhtml:code> user to prevent destruction
or modification of the file.
To properly set the owner of <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/boot/grub2/grub.cfg</xhtml:code>, run the command:
<xhtml:pre xmlns:xhtml="http://www.w3.org/1999/xhtml" xml:space="preserve"># chown root/boot/grub2/grub.cfg</xhtml:pre>
</description>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf"/>
<reference href="http://iase.disa.mil/stigs/cci/Pages/index.aspx">225</reference>
<rationale xml:lang="en-US">
Only root should be able to modify important boot parameters.
</rationale>
<check system="http://oval.mitre.org/XMLSchema/oval-definitions-5">
<check-content-ref name="oval:ssg:def:237" href="ssg-fedora-oval.xml"/>
</check>
<check system="ocil-transitional">
<check-export export-name="it does not" value-id="xccdf_org.ssgproject.content_value_conditional_clause"/>
<check-content>
To check the ownership of <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/boot/grub2/grub.cfg</xhtml:code>, run the command:
<xhtml:pre xmlns:xhtml="http://www.w3.org/1999/xhtml">$ ls -lL /boot/grub2/grub.cfg</xhtml:pre>
If properly configured, the output should indicate the following owner:
<xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">root</xhtml:code>
</check-content>
</check>
</Rule>
<Rule id="xccdf_org.ssgproject.content_rule_file_group_owner_grub2_cfg" selected="false" severity="medium">
<title xml:lang="en-US">Verify /boot/grub2/grub.cfg Group Ownership</title>
<description xml:lang="en-US">The file <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/boot/grub2/grub.cfg</xhtml:code> should
be group-owned by the <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">root</xhtml:code> group to prevent
destruction or modification of the file.
To properly set the group owner of <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/boot/grub2/grub.cfg</xhtml:code>, run the command:
<xhtml:pre xmlns:xhtml="http://www.w3.org/1999/xhtml" xml:space="preserve"># chgrp root/boot/grub2/grub.cfg</xhtml:pre>
</description>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf"/>
<reference href="http://iase.disa.mil/stigs/cci/Pages/index.aspx">225</reference>
<rationale xml:lang="en-US">
The <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">root</xhtml:code> group is a highly-privileged group. Furthermore, the group-owner of this
file should not have any access privileges anyway.
</rationale>
<check system="http://oval.mitre.org/XMLSchema/oval-definitions-5">
<check-content-ref name="oval:ssg:def:278" href="ssg-fedora-oval.xml"/>
</check>
<check system="ocil-transitional">
<check-export export-name="it does not" value-id="xccdf_org.ssgproject.content_value_conditional_clause"/>
<check-content>
To check the group ownership of <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/boot/grub2/grub.cfg</xhtml:code>, run the command:
<xhtml:pre xmlns:xhtml="http://www.w3.org/1999/xhtml">$ ls -lL /boot/grub2/grub.cfg</xhtml:pre>
If properly configured, the output should indicate the following group-owner.
<xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">root</xhtml:code>
</check-content>
</check>
</Rule>
<Rule id="xccdf_org.ssgproject.content_rule_file_permissions_grub2_cfg" selected="false" severity="medium">
<title xml:lang="en-US">Verify /boot/grub2/grub.cfg Permissions</title>
<description xml:lang="en-US">File permissions for <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/boot/grub2/grub.cfg</xhtml:code> should be set to 600, which
is the default.
To properly set the permissions of <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/boot/grub2/grub.cfg</xhtml:code>, run the command:
<xhtml:pre xmlns:xhtml="http://www.w3.org/1999/xhtml" xml:space="preserve"># chmod 600/boot/grub2/grub.cfg</xhtml:pre>
</description>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf"/>
<reference href="http://iase.disa.mil/stigs/cci/Pages/index.aspx">225</reference>
<rationale xml:lang="en-US">
Proper permissions ensure that only the root user can modify important boot
parameters.
</rationale>
<check system="http://oval.mitre.org/XMLSchema/oval-definitions-5">
<check-content-ref name="oval:ssg:def:192" href="ssg-fedora-oval.xml"/>
</check>
<check system="ocil-transitional">
<check-export export-name="it does not" value-id="xccdf_org.ssgproject.content_value_conditional_clause"/>
<check-content>
To check the permissions of /boot/grub2/grub.cfg, run the command:
<pre xmlns="http://www.w3.org/1999/xhtml">$ sudo ls -lL /boot/grub2/grub.cfg</pre>
If properly configured, the output should indicate the following
permissions: <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">-rw-------</xhtml:code>
</check-content>
</check>
</Rule>
<Rule id="xccdf_org.ssgproject.content_rule_bootloader_password" selected="false" severity="medium">
<title xml:lang="en-US">Set Boot Loader Password</title>
<description xml:lang="en-US">The grub2 boot loader should have a superuser account and password
protection enabled to protect boot-time settings.
<br xmlns="http://www.w3.org/1999/xhtml"/><br xmlns="http://www.w3.org/1999/xhtml"/>
To do so, select a superuser account and password and add them into the
appropriate grub2 configuration file(s) under <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/grub.d</xhtml:code>.
Since plaintext passwords are a security risk, generate a hash for the pasword
by running the following command:
<pre xmlns="http://www.w3.org/1999/xhtml">$ grub2-mkpasswd-pbkdf2</pre>
When prompted, enter the password that was selected and insert the returned
password hash into the appropriate grub2 configuration file(s) under
<xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/grub.d</xhtml:code> immediately after the superuser account.
(Use the output from <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">grub2-mkpasswd-pbkdf2</xhtml:code> as the value of
<b xmlns="http://www.w3.org/1999/xhtml">password-hash</b>):
<pre xmlns="http://www.w3.org/1999/xhtml">password_pbkdf2 <b>superusers-account</b> <b>password-hash</b></pre>
NOTE: It is recommended not to use common administrator account names like root,
admin, or administrator for the grub2 superuser account.
<br xmlns="http://www.w3.org/1999/xhtml"/>
To meet FISMA Moderate, the bootloader superuser account and password MUST
differ from the root account and password.
Once the superuser account and password have been added, update the
<xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">grub.cfg</xhtml:code> file by running:
<pre xmlns="http://www.w3.org/1999/xhtml">grub2-mkconfig -o /boot/grub2/grub.cfg</pre>
NOTE: Do NOT manually add the superuser account and password to the
<xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">grub.cfg</xhtml:code> file as the grub2-mkconfig command overwrites this file.
</description>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">IA-2(1)</reference>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">IA-5(e)</reference>
<reference href="http://iase.disa.mil/stigs/cci/Pages/index.aspx">213</reference>
<rationale xml:lang="en-US">
Password protection on the boot loader configuration ensures
users with physical access cannot trivially alter
important bootloader settings. These include which kernel to use,
and whether to enter single-user mode. For more information on how to configure
the grub2 superuser account and password, please refer to
<ul xmlns="http://www.w3.org/1999/xhtml"><li>https://docs.redhat.com/docs/en-US/Red_Hat_Enterprise_Linux/7/html/System_Administrators_Guide/sec-GRUB_2_Password_Protection.html</li>.
</ul>
</rationale>
<check system="http://oval.mitre.org/XMLSchema/oval-definitions-5">
<check-content-ref name="oval:ssg:def:264" href="ssg-fedora-oval.xml"/>
</check>
<check system="ocil-transitional">
<check-export export-name="it does not" value-id="xccdf_org.ssgproject.content_value_conditional_clause"/>
<check-content>
To verify the boot loader superuser account and superuser account password have
been set, and the password encrypted, run the following command:
<pre xmlns="http://www.w3.org/1999/xhtml">sudo grep -A1 "superusers\|password" /etc/grub2.cfg</pre>
The output should show the following:
<pre xmlns="http://www.w3.org/1999/xhtml">set superusers="<b>superusers-account</b>"
password_pbkdf2 <b>superusers-account</b> <b>password-hash</b></pre>
</check-content>
</check>
</Rule>
</Group>
<Rule id="xccdf_org.ssgproject.content_rule_require_singleuser_auth" selected="false" severity="medium">
<title xml:lang="en-US">Require Authentication for Single User Mode</title>
<description xml:lang="en-US">Single-user mode is intended as a system recovery
method, providing a single user root access to the system by
providing a boot option at startup. By default, no authentication
is performed if single-user mode is selected.
<br xmlns="http://www.w3.org/1999/xhtml"/><br xmlns="http://www.w3.org/1999/xhtml"/>
By default, single-user mode is protected by requiring a password and is set
in <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/usr/lib/systemd/system/rescue.service</xhtml:code>.
</description>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">IA-2(1)</reference>
<reference href="http://iase.disa.mil/stigs/cci/Pages/index.aspx">213</reference>
<rationale xml:lang="en-US">
This prevents attackers with physical access from trivially bypassing security
on the machine and gaining root access. Such accesses are further prevented
by configuring the bootloader password.
</rationale>
<check system="http://oval.mitre.org/XMLSchema/oval-definitions-5">
<check-content-ref name="oval:ssg:def:298" href="ssg-fedora-oval.xml"/>
</check>
<check system="ocil-transitional">
<check-export export-name="the output is different" value-id="xccdf_org.ssgproject.content_value_conditional_clause"/>
<check-content>
To check if authentication is required for single-user mode, run the following command:
<pre xmlns="http://www.w3.org/1999/xhtml">$ grep sulogin /usr/lib/systemd/system/rescue.service</pre>
The output should be similar to the following, and the line must begin with
ExecStart and /sbin/sulogin:
<pre xmlns="http://www.w3.org/1999/xhtml">ExecStart=-/sbin/sulogin</pre>
</check-content>
</check>
</Rule>
<Rule id="xccdf_org.ssgproject.content_rule_disable_ctrlaltdel_reboot" selected="false" severity="high">
<title xml:lang="en-US">Disable Ctrl-Alt-Del Reboot Activation</title>
<description xml:lang="en-US">
By default, the system includes the following line in
<xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/init/control-alt-delete.conf</xhtml:code>
to reboot the system when the Ctrl-Alt-Del key sequence is pressed:
<pre xmlns="http://www.w3.org/1999/xhtml">exec /sbin/shutdown -r now "Control-Alt-Delete pressed"</pre>
<br xmlns="http://www.w3.org/1999/xhtml"/>
To configure the system to log a message instead of
rebooting the system, alter that line to read as follows:
<pre xmlns="http://www.w3.org/1999/xhtml">exec /usr/bin/logger -p security.info "Control-Alt-Delete pressed"</pre>
</description>
<rationale xml:lang="en-US">
A locally logged-in user who presses Ctrl-Alt-Del, when at the console,
can reboot the system. If accidentally pressed, as could happen in
the case of mixed OS environment, this can create the risk of short-term
loss of availability of systems due to unintentional reboot.
In the GNOME graphical environment, risk of unintentional reboot from the
Ctrl-Alt-Del sequence is reduced because the user will be
prompted before any action is taken.
</rationale>
<check system="ocil-transitional">
<check-export export-name="the system is configured to run the shutdown command" value-id="xccdf_org.ssgproject.content_value_conditional_clause"/>
<check-content>
To ensure the system is configured to log a message instead of rebooting the system when
Ctrl-Alt-Del is pressed, ensure the following line is in <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/init/control-alt-delete.conf</xhtml:code>:
<pre xmlns="http://www.w3.org/1999/xhtml">exec /usr/bin/logger -p security.info "Control-Alt-Delete pressed"</pre>
</check-content>
</check>
</Rule>
<Rule id="xccdf_org.ssgproject.content_rule_disable_interactive_boot" selected="false" severity="medium">
<title xml:lang="en-US">Disable Interactive Boot</title>
<description xml:lang="en-US">
To disable the ability for users to perform interactive startups,
edit the file <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/sysconfig/init</xhtml:code>.
Add or correct the line:
<pre xmlns="http://www.w3.org/1999/xhtml">PROMPT=no</pre>
The <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">PROMPT</xhtml:code> option allows the console user to perform an
interactive system startup, in which it is possible to select the
set of services which are started on boot.
</description>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">SC-2</reference>
<reference href="http://iase.disa.mil/stigs/cci/Pages/index.aspx">213</reference>
<rationale xml:lang="en-US">
Using interactive boot,
the console user could disable auditing, firewalls, or other
services, weakening system security.
</rationale>
<check system="ocil-transitional">
<check-export export-name="it does not" value-id="xccdf_org.ssgproject.content_value_conditional_clause"/>
<check-content>
To check whether interactive boot is disabled, run the following command:
<pre xmlns="http://www.w3.org/1999/xhtml">$ grep PROMPT /etc/sysconfig/init</pre>
If interactive boot is disabled, the output will show:
<pre xmlns="http://www.w3.org/1999/xhtml">PROMPT=no</pre>
</check-content>
</check>
</Rule>
<Group id="xccdf_org.ssgproject.content_group_screen_locking">
<title xml:lang="en-US">Configure Screen Locking</title>
<description xml:lang="en-US">When a user must temporarily leave an account
logged-in, screen locking should be employed to prevent passersby
from abusing the account. User education and training is
particularly important for screen locking to be effective, and policies
can be implemented to reinforce this.
<br xmlns="http://www.w3.org/1999/xhtml"/><br xmlns="http://www.w3.org/1999/xhtml"/>
Automatic screen locking is only meant as a safeguard for
those cases where a user forgot to lock the screen.</description>
<Group id="xccdf_org.ssgproject.content_group_gui_screen_locking">
<title xml:lang="en-US">Configure GUI Screen Locking</title>
<description xml:lang="en-US">In the default GNOME3 desktop, the screen can be locked
by selecting the user name in the far right corner of the main panel and
selecting <b xmlns="http://www.w3.org/1999/xhtml">Lock</b>.
<br xmlns="http://www.w3.org/1999/xhtml"/><br xmlns="http://www.w3.org/1999/xhtml"/>
The following sections detail commands to enforce idle activation of the screensaver,
screen locking, a blank-screen screensaver, and an idle
activation time.
<br xmlns="http://www.w3.org/1999/xhtml"/><br xmlns="http://www.w3.org/1999/xhtml"/>
Because users should be trained to lock the screen when they
step away from the computer, the automatic locking feature is only
meant as a backup.
<br xmlns="http://www.w3.org/1999/xhtml"/><br xmlns="http://www.w3.org/1999/xhtml"/>
The root account can be screen-locked; however,
the root account should <i xmlns="http://www.w3.org/1999/xhtml">never</i> be used
to log into an X Windows environment and should only be used to
for direct login via console in emergency circumstances.
<br xmlns="http://www.w3.org/1999/xhtml"/><br xmlns="http://www.w3.org/1999/xhtml"/>
For more information about enforcing preferences in the GNOME3 environment using the DConf
configuration system, see <b xmlns="http://www.w3.org/1999/xhtml">http://wiki.gnome.org/dconf</b> and
the man page <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">dconf(1)</xhtml:code>. For Red Hat specific information on configuring DConf
settings, see <b xmlns="http://www.w3.org/1999/xhtml">https://docs.redhat.com/docs/en-US/Red_Hat_Enterprise_Linux/7/html/Desktop_Migration_and_Administration_Guide/part-Configuration_and_Administration.html</b>
</description>
<Value id="xccdf_org.ssgproject.content_value_inactivity_timeout_value" operator="equals" type="number">
<title xml:lang="en-US">Inactivity timeout</title>
<description xml:lang="en-US">Choose allowed duration of inactive SSH connections, shells, and X sessions</description>
<value>900</value>
<value selector="5_minutes">300</value>
<value selector="10_minutes">600</value>
<value selector="15_minutes">900</value>
</Value>
<Rule id="xccdf_org.ssgproject.content_rule_dconf_gnome_screensaver_idle_delay" selected="false" severity="medium">
<title xml:lang="en-US">Set GNOME3 Screensaver Inactivity Timeout</title>
<description xml:lang="en-US">
To set the idle time-out value for inactivity in the GNOME3 desktop to 5 minutes (in seconds),
the <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">idle-delay</xhtml:code> setting must be set under an appropriate
configuration file(s) in the <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/dconf/db/local.d</xhtml:code> directory
and locked in <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/dconf/db/local.d/locks</xhtml:code> directory to prevent user modification.
After the settings have been set, run <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">dconf update</xhtml:code>.
</description>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">AC-11(a)</reference>
<reference href="http://iase.disa.mil/stigs/cci/Pages/index.aspx">57</reference>
<rationale xml:lang="en-US">
Setting the idle delay controls when the
screensaver will start, and can be combined with
screen locking to prevent access from passersby.
</rationale>
<check system="http://oval.mitre.org/XMLSchema/oval-definitions-5">
<check-export export-name="oval:ssg:var:479" value-id="xccdf_org.ssgproject.content_value_inactivity_timeout_value"/>
<check-content-ref name="oval:ssg:def:294" href="ssg-fedora-oval.xml"/>
</check>
<check system="ocil-transitional">
<check-export export-name="it is not" value-id="xccdf_org.ssgproject.content_value_conditional_clause"/>
<check-content>
To check the current idle time-out value, run the following command:
<pre xmlns="http://www.w3.org/1999/xhtml">$ gsettings get org.gnome.desktop.session idle-delay</pre>
If properly configured, the output should be <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">300</xhtml:code>.
To ensure that users cannot change the screensaver inactivity timeout setting, run the following:
<pre xmlns="http://www.w3.org/1999/xhtml">$ grep idle-delay /etc/dconf/db/local.d/locks/*</pre>
If properly configured, the output should be <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/org/gnome/desktop/session/idle-delay</xhtml:code>
</check-content>
</check>
</Rule>
<Rule id="xccdf_org.ssgproject.content_rule_dconf_gnome_screensaver_idle_activation_enabled" selected="false" severity="medium">
<title xml:lang="en-US">Enable GNOME3 Screensaver Idle Activation</title>
<description xml:lang="en-US">
To activate the screensaver in the GNOME3 desktop after a period of inactivity,
the <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">idle-activation-enabled</xhtml:code> setting must be set under an appropriate
configuration file(s) in the <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/dconf/db/local.d</xhtml:code> directory
and locked in <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/dconf/db/local.d/locks</xhtml:code> directory to prevent user modification.
After the settings have been set, run <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">dconf update</xhtml:code>.
</description>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">AC-11(a)</reference>
<reference href="http://iase.disa.mil/stigs/cci/Pages/index.aspx">57</reference>
<rationale xml:lang="en-US">
Enabling idle activation of the screensaver ensures the screensaver will
be activated after the idle delay. Applications requiring continuous,
real-time screen display (such as network management products) require the
login session does not have administrator rights and the display station is located in a
controlled-access area.
</rationale>
<check system="http://oval.mitre.org/XMLSchema/oval-definitions-5">
<check-content-ref name="oval:ssg:def:269" href="ssg-fedora-oval.xml"/>
</check>
<check system="ocil-transitional">
<check-export export-name="it is not" value-id="xccdf_org.ssgproject.content_value_conditional_clause"/>
<check-content>To check the screensaver mandatory use status, run the following command:
<pre xmlns="http://www.w3.org/1999/xhtml">$ gsettings get org.gnome.desktop.screensaver idle-activation-enabled</pre>
If properly configured, the output should be <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">true</xhtml:code>.
To ensure that users cannot disable the screensaver idle inactivity setting, run the following:
<pre xmlns="http://www.w3.org/1999/xhtml">$ grep idle-activation-enabled /etc/dconf/db/local.d/locks/*</pre>
If properly configured, the output should be <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/org/gnome/desktop/screensaver/idle-activation-enabled</xhtml:code>
</check-content>
</check>
</Rule>
<Rule id="xccdf_org.ssgproject.content_rule_dconf_gnome_screensaver_lock_enabled" selected="false" severity="medium">
<title xml:lang="en-US">Enable GNOME3 Screensaver Lock After Idle Period</title>
<description xml:lang="en-US">
To activate locking of the screensaver in the GNOME3 desktop when it is activated,
the <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">lock-enabled</xhtml:code> and <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">lock-delay</xhtml:code> setting must be set under an appropriate
configuration file(s) in the <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/dconf/db/local.d</xhtml:code> directory
and locked in <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/dconf/db/local.d/locks</xhtml:code> directory to prevent user modification.
After the settings have been set, run <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">dconf update</xhtml:code>.
</description>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">AC-11(a)</reference>
<reference href="http://iase.disa.mil/stigs/cci/Pages/index.aspx">57</reference>
<rationale xml:lang="en-US">
Enabling the activation of the screen lock after an idle period
ensures password entry will be required in order to
access the system, preventing access by passersby.
</rationale>
<check system="http://oval.mitre.org/XMLSchema/oval-definitions-5">
<check-content-ref name="oval:ssg:def:287" href="ssg-fedora-oval.xml"/>
</check>
<check system="ocil-transitional">
<check-export export-name="it is not" value-id="xccdf_org.ssgproject.content_value_conditional_clause"/>
<check-content>
To check the status of the idle screen lock activation, run the following command:
<pre xmlns="http://www.w3.org/1999/xhtml">$ gsettings get org.gnome.desktop.screensaver lock-enabled</pre>
If properly configured, the output should be <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">true</xhtml:code>.
To check that the screen locks when activated, run the following command:
<pre xmlns="http://www.w3.org/1999/xhtml">$ gsettings get org.gnome.desktop.screensaver lock-delay</pre>
If properly configured, the output should be <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">0</xhtml:code>.
To ensure that users cannot change how long until the the screensaver locks, run the following:
<pre xmlns="http://www.w3.org/1999/xhtml">$ grep 'lock-enabled\|lock-delay' /etc/dconf/db/local.d/locks/*</pre>
If properly configured, the output for <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">lock-enabled</xhtml:code> should be <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/org/gnome/desktop/screensaver/lock-enabled</xhtml:code>
If properly configured, the output for <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">lock-delay</xhtml:code> should be <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/org/gnome/desktop/screensaver/lock-delay</xhtml:code>
</check-content>
</check>
</Rule>
<Rule id="xccdf_org.ssgproject.content_rule_dconf_gnome_screensaver_mode_blank" selected="false" severity="low">
<title xml:lang="en-US">Implement Blank Screensaver</title>
<description xml:lang="en-US">
To set the screensaver mode in the GNOME3 desktop to a blank screen,
the <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">picture-uri</xhtml:code> setting must be set under an appropriate
configuration file(s) in the <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/dconf/db/local.d</xhtml:code> directory
and locked in <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/dconf/db/local.d/locks</xhtml:code> directory to prevent user modification.
After the settings have been set, run <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">dconf update</xhtml:code>.
</description>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">AC-11(b)</reference>
<reference href="http://iase.disa.mil/stigs/cci/Pages/index.aspx">60</reference>
<rationale xml:lang="en-US">
Setting the screensaver mode to blank-only conceals the
contents of the display from passersby.
</rationale>
<check system="http://oval.mitre.org/XMLSchema/oval-definitions-5">
<check-content-ref name="oval:ssg:def:172" href="ssg-fedora-oval.xml"/>
</check>
<check system="ocil-transitional">
<check-export export-name="it is not" value-id="xccdf_org.ssgproject.content_value_conditional_clause"/>
<check-content>
To ensure the screensaver is configured to be blank, run the following command:
<pre xmlns="http://www.w3.org/1999/xhtml">$ gsettings get org.gnome.desktop.screensaver picture-uri</pre>
If properly configured, the output should be <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">''</xhtml:code>.
To ensure that users cannot set the screensaver background, run the following:
<pre xmlns="http://www.w3.org/1999/xhtml">$ grep picture-uri /etc/dconf/db/local.d/locks/*</pre>
If properly configured, the output should be <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/org/gnome/desktop/screensaver/picture-uri</xhtml:code>
</check-content>
</check>
</Rule>
</Group>
<Group id="xccdf_org.ssgproject.content_group_console_screen_locking">
<title xml:lang="en-US">Configure Console Screen Locking</title>
<description xml:lang="en-US">
A console screen locking mechanism is provided in the
<xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">screen</xhtml:code> package, which is not installed by default.
</description>
<Rule id="xccdf_org.ssgproject.content_rule_package_screen_installed" selected="false" severity="low">
<title xml:lang="en-US">Install the screen Package</title>
<description xml:lang="en-US">
To enable console screen locking, install the <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">screen</xhtml:code> package:
<pre xmlns="http://www.w3.org/1999/xhtml">$ sudo yum install screen</pre>
Instruct users to begin new terminal sessions with the following command:
<pre xmlns="http://www.w3.org/1999/xhtml">$ screen</pre>
The console can now be locked with the following key combination:
<pre xmlns="http://www.w3.org/1999/xhtml">ctrl+a x</pre>
</description>
<reference href="http://iase.disa.mil/stigs/cci/Pages/index.aspx">58</reference>
<rationale xml:lang="en-US">
Installing <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">screen</xhtml:code> ensures a console locking capability is available
for users who may need to suspend console logins.
</rationale>
<check system="ocil-transitional">
<check-export export-name="the package is not installed" value-id="xccdf_org.ssgproject.content_value_conditional_clause"/>
<check-content>
Run the following command to determine if the <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">screen</xhtml:code> package is installed:
<xhtml:pre xmlns:xhtml="http://www.w3.org/1999/xhtml"># rpm -q screen</xhtml:pre>
</check-content>
</check>
</Rule>
</Group>
<Group id="xccdf_org.ssgproject.content_group_smart_card_login">
<title xml:lang="en-US">Hardware Tokens for Authentication</title>
<description xml:lang="en-US">
The use of hardware tokens such as smart cards for system login
provides stronger, two-factor authentication than using a username/password.
In Fedora servers and workstations, hardware token login
is not enabled by default and must be enabled in the system settings.
</description>
<Rule id="xccdf_org.ssgproject.content_rule_smartcard_auth" selected="false" severity="medium">
<title xml:lang="en-US">Enable Smart Card Login</title>
<description xml:lang="en-US">
To enable smart card authentication, consult the documentation at:
<ul xmlns="http://www.w3.org/1999/xhtml"><li>https://docs.fedoraproject.org/docs/en-US/Fedora/18/html/Security_Guide/sect-Security_Guide-Single_Sign_on_SSO-Getting_Started_with_your_new_Smart_Card.html</li></ul>
</description>
<reference href="http://iase.disa.mil/stigs/cci/Pages/index.aspx">765</reference>
<reference href="http://iase.disa.mil/stigs/cci/Pages/index.aspx">766</reference>
<reference href="http://iase.disa.mil/stigs/cci/Pages/index.aspx">767</reference>
<reference href="http://iase.disa.mil/stigs/cci/Pages/index.aspx">768</reference>
<reference href="http://iase.disa.mil/stigs/cci/Pages/index.aspx">771</reference>
<reference href="http://iase.disa.mil/stigs/cci/Pages/index.aspx">772</reference>
<reference href="http://iase.disa.mil/stigs/cci/Pages/index.aspx">884</reference>
<rationale xml:lang="en-US">Smart card login provides two-factor authentication stronger than
that provided by a username and password combination. Smart cards leverage PKI
(public key infrastructure) in order to provide and verify credentials.
</rationale>
<check system="ocil-transitional">
<check-export export-name="non-exempt accounts are not using CAC authentication" value-id="xccdf_org.ssgproject.content_value_conditional_clause"/>
<check-content>
Interview the SA to determine if all accounts not exempted by policy are
using CAC authentication.
</check-content>
</check>
</Rule>
</Group>
</Group>
</Group>
<Group id="xccdf_org.ssgproject.content_group_accounts-banners">
<title xml:lang="en-US">Warning Banners for System Accesses</title>
<description xml:lang="en-US">Each system should expose as little information about
itself as possible.
<br xmlns="http://www.w3.org/1999/xhtml"/><br xmlns="http://www.w3.org/1999/xhtml"/>
System banners, which are typically displayed just before a
login prompt, give out information about the service or the host's
operating system. This might include the distribution name and the
system kernel version, and the particular version of a network
service. This information can assist intruders in gaining access to
the system as it can reveal whether the system is running
vulnerable software. Most network services can be configured to
limit what information is displayed.
<br xmlns="http://www.w3.org/1999/xhtml"/><br xmlns="http://www.w3.org/1999/xhtml"/>
Many organizations implement security policies that require a
system banner provide notice of the system's ownership, provide
warning to unauthorized users, and remind authorized users of their
consent to monitoring.</description>
<Value id="xccdf_org.ssgproject.content_value_login_banner_text" operator="equals" type="string">
<title xml:lang="en-US">Login Banner Verbiage</title>
<description xml:lang="en-US">Enter an appropriate login banner for your organization. Please note that new lines must
be expressed by the '\n' character and special characters like parentheses and quotation marks must be escaped with '\'.</description>
<value selector="usgcb_default">--[\s\n]+WARNING[\s\n]+--[\s\n]*This[\s\n]+system[\s\n]+is[\s\n]+for[\s\n]+the[\s\n]+use[\s\n]+of[\s\n]+authorized[\s\n]+users[\s\n]+only.[\s\n]+Individuals[\s\n]*using[\s\n]+this[\s\n]+computer[\s\n]+system[\s\n]+without[\s\n]+authority[\s\n]+or[\s\n]+in[\s\n]+excess[\s\n]+of[\s\n]+their[\s\n]*authority[\s\n]+are[\s\n]+subject[\s\n]+to[\s\n]+having[\s\n]+all[\s\n]+their[\s\n]+activities[\s\n]+on[\s\n]+this[\s\n]+system[\s\n]*monitored[\s\n]+and[\s\n]+recorded[\s\n]+by[\s\n]+system[\s\n]+personnel.[\s\n]+Anyone[\s\n]+using[\s\n]+this[\s\n]*system[\s\n]+expressly[\s\n]+consents[\s\n]+to[\s\n]+such[\s\n]+monitoring[\s\n]+and[\s\n]+is[\s\n]+advised[\s\n]+that[\s\n]*if[\s\n]+such[\s\n]+monitoring[\s\n]+reveals[\s\n]+possible[\s\n]+evidence[\s\n]+of[\s\n]+criminal[\s\n]+activity[\s\n]*system[\s\n]+personal[\s\n]+may[\s\n]+provide[\s\n]+the[\s\n]+evidence[\s\n]+of[\s\n]+such[\s\n]+monitoring[\s\n]+to[\s\n]+law[\s\n]*enforcement[\s\n]+officials.</value>
<value selector="dod_default">You[\s\n]+are[\s\n]+accessing[\s\n]+a[\s\n]+U.S.[\s\n]+Government[\s\n]+\(USG\)[\s\n]+Information[\s\n]+System[\s\n]+\(IS\)[\s\n]+that[\s\n]+is[\s\n]+provided[\s\n]+for[\s\n]+USG-authorized[\s\n]+use[\s\n]+only.[\s\n]*By[\s\n]+using[\s\n]+this[\s\n]+IS[\s\n]+\(which[\s\n]+includes[\s\n]+any[\s\n]+device[\s\n]+attached[\s\n]+to[\s\n]+this[\s\n]+IS\),[\s\n]+you[\s\n]+consent[\s\n]+to[\s\n]+the[\s\n]+following[\s\n]+conditions\:[\s\n]*-[\s\n]*The[\s\n]+USG[\s\n]+routinely[\s\n]+intercepts[\s\n]+and[\s\n]+monitors[\s\n]+communications[\s\n]+on[\s\n]+this[\s\n]+IS[\s\n]+for[\s\n]+purposes[\s\n]+including,[\s\n]+but[\s\n]+not[\s\n]+limited[\s\n]+to,[\s\n]+penetration[\s\n]+testing,[\s\n]+COMSEC[\s\n]+monitoring,[\s\n]+network[\s\n]+operations[\s\n]+and[\s\n]+defense,[\s\n]+personnel[\s\n]+misconduct[\s\n]+\(PM\),[\s\n]+law[\s\n]+enforcement[\s\n]+\(LE\),[\s\n]+and[\s\n]+counterintelligence[\s\n]+\(CI\)[\s\n]+investigations.[\s\n]*-[\s\n]*At[\s\n]+any[\s\n]+time,[\s\n]+the[\s\n]+USG[\s\n]+may[\s\n]+inspect[\s\n]+and[\s\n]+seize[\s\n]+data[\s\n]+stored[\s\n]+on[\s\n]+this[\s\n]+IS.[\s\n]*-[\s\n]*Communications[\s\n]+using,[\s\n]+or[\s\n]+data[\s\n]+stored[\s\n]+on,[\s\n]+this[\s\n]+IS[\s\n]+are[\s\n]+not[\s\n]+private,[\s\n]+are[\s\n]+subject[\s\n]+to[\s\n]+routine[\s\n]+monitoring,[\s\n]+interception,[\s\n]+and[\s\n]+search,[\s\n]+and[\s\n]+may[\s\n]+be[\s\n]+disclosed[\s\n]+or[\s\n]+used[\s\n]+for[\s\n]+any[\s\n]+USG-authorized[\s\n]+purpose.[\s\n]*-[\s\n]*This[\s\n]+IS[\s\n]+includes[\s\n]+security[\s\n]+measures[\s\n]+\(e.g.,[\s\n]+authentication[\s\n]+and[\s\n]+access[\s\n]+controls\)[\s\n]+to[\s\n]+protect[\s\n]+USG[\s\n]+interests[\s\n]+--[\s\n]+not[\s\n]+for[\s\n]+your[\s\n]+personal[\s\n]+benefit[\s\n]+or[\s\n]+privacy.[\s\n]*-[\s\n]*Notwithstanding[\s\n]+the[\s\n]+above,[\s\n]+using[\s\n]+this[\s\n]+IS[\s\n]+does[\s\n]+not[\s\n]+constitute[\s\n]+consent[\s\n]+to[\s\n]+PM,[\s\n]+LE[\s\n]+or[\s\n]+CI[\s\n]+investigative[\s\n]+searching[\s\n]+or[\s\n]+monitoring[\s\n]+of[\s\n]+the[\s\n]+content[\s\n]+of[\s\n]+privileged[\s\n]+communications,[\s\n]+or[\s\n]+work[\s\n]+product,[\s\n]+related[\s\n]+to[\s\n]+personal[\s\n]+representation[\s\n]+or[\s\n]+services[\s\n]+by[\s\n]+attorneys,[\s\n]+psychotherapists,[\s\n]+or[\s\n]+clergy,[\s\n]+and[\s\n]+their[\s\n]+assistants.[\s\n]+Such[\s\n]+communications[\s\n]+and[\s\n]+work[\s\n]+product[\s\n]+are[\s\n]+private[\s\n]+and[\s\n]+confidential.[\s\n]+See[\s\n]+User[\s\n]+Agreement[\s\n]+for[\s\n]+details.</value>
<value selector="dod_short">I\'ve[\s\n]+read[\s\n]+\&[\s\n]+consent[\s\n]+to[\s\n]+terms[\s\n]+in[\s\n]+IS[\s\n]+user[\s\n]+agreem\'t.</value>
</Value>
<Rule id="xccdf_org.ssgproject.content_rule_set_system_login_banner" selected="false" severity="medium">
<title xml:lang="en-US">Modify the System Login Banner</title>
<description xml:lang="en-US">
To configure the system login banner:
<br xmlns="http://www.w3.org/1999/xhtml"/><br xmlns="http://www.w3.org/1999/xhtml"/>
Edit <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/issue</xhtml:code>. Replace the default text with a message
compliant with the local site policy or a legal disclaimer.
The DoD required text is either:
<br xmlns="http://www.w3.org/1999/xhtml"/><br xmlns="http://www.w3.org/1999/xhtml"/>
<xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">You are accessing a U.S. Government (USG) Information System (IS) that is
provided for USG-authorized use only. By using this IS (which includes any
device attached to this IS), you consent to the following conditions:
<br xmlns="http://www.w3.org/1999/xhtml"/>-The USG routinely intercepts and monitors communications on this IS for purposes
including, but not limited to, penetration testing, COMSEC monitoring, network
operations and defense, personnel misconduct (PM), law enforcement (LE), and
counterintelligence (CI) investigations.
<br xmlns="http://www.w3.org/1999/xhtml"/>-At any time, the USG may inspect and seize data stored on this IS.
<br xmlns="http://www.w3.org/1999/xhtml"/>-Communications using, or data stored on, this IS are not private, are subject
to routine monitoring, interception, and search, and may be disclosed or used
for any USG-authorized purpose.
<br xmlns="http://www.w3.org/1999/xhtml"/>-This IS includes security measures (e.g., authentication and access controls)
to protect USG interests -- not for your personal benefit or privacy.
<br xmlns="http://www.w3.org/1999/xhtml"/>-Notwithstanding the above, using this IS does not constitute consent to PM, LE or CI investigative
searching or monitoring of the content of privileged communications, or work
product, related to personal representation or services by attorneys,
psychotherapists, or clergy, and their assistants. Such communications and work
product are private and confidential. See User Agreement for details.</xhtml:code>
<br xmlns="http://www.w3.org/1999/xhtml"/><br xmlns="http://www.w3.org/1999/xhtml"/>
OR:
<br xmlns="http://www.w3.org/1999/xhtml"/><br xmlns="http://www.w3.org/1999/xhtml"/>
<xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">I've read & consent to terms in IS user agreem't.</xhtml:code>
</description>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">AC-8(a)</reference>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">AC-8(b)</reference>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">AC-8(c)</reference>
<reference href="http://iase.disa.mil/stigs/cci/Pages/index.aspx">48</reference>
<reference href="http://iase.disa.mil/stigs/cci/Pages/index.aspx">1384</reference>
<reference href="http://iase.disa.mil/stigs/cci/Pages/index.aspx">1385</reference>
<reference href="http://iase.disa.mil/stigs/cci/Pages/index.aspx">1386</reference>
<reference href="http://iase.disa.mil/stigs/cci/Pages/index.aspx">1387</reference>
<reference href="http://iase.disa.mil/stigs/cci/Pages/index.aspx">1388</reference>
<rationale xml:lang="en-US">
An appropriate warning message reinforces policy awareness during the logon
process and facilitates possible legal action against attackers.
</rationale>
<check system="http://oval.mitre.org/XMLSchema/oval-definitions-5">
<check-export export-name="oval:ssg:var:456" value-id="xccdf_org.ssgproject.content_value_login_banner_text"/>
<check-content-ref name="oval:ssg:def:253" href="ssg-fedora-oval.xml"/>
</check>
<check system="ocil-transitional">
<check-export export-name="it does not display the required banner" value-id="xccdf_org.ssgproject.content_value_conditional_clause"/>
<check-content>
To check if the system login banner is compliant,
run the following command:
<pre xmlns="http://www.w3.org/1999/xhtml">$ cat /etc/issue</pre>
</check-content>
</check>
</Rule>
<Group id="xccdf_org.ssgproject.content_group_gui_login_banner">
<title xml:lang="en-US">Implement a GUI Warning Banner</title>
<description xml:lang="en-US">In the default graphical environment, users logging
directly into the system are greeted with a login screen provided
by the GNOME3 Display Manager (GDM). The warning banner should be
displayed in this graphical environment for these users.
The following sections describe how to configure the GDM login
banner.
</description>
<Rule id="xccdf_org.ssgproject.content_rule_dconf_gnome_banner_enabled" selected="false" severity="medium">
<title xml:lang="en-US">Enable GNOME3 Login Warning Banner</title>
<description xml:lang="en-US">
To enable displaying a login warning banner in the GNOME
Display Manager's login screen, the <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">banner-message-enable</xhtml:code> setting must be
set under an appropriate configuration file(s) in the <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/dconf/db/gdm.d</xhtml:code> directory
and locked in <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/dconf/db/gdm.d/locks</xhtml:code> directory to prevent user modification.
After the settings have been set, run <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">dconf update</xhtml:code>.
To display a banner, this setting must be enabled, and the user must be prevented
from making changes. The banner text must also be set.
</description>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">AC-8(a)</reference>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">AC-8(b)</reference>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">AC-8(c)</reference>
<reference href="http://iase.disa.mil/stigs/cci/Pages/index.aspx">48</reference>
<reference href="http://iase.disa.mil/stigs/cci/Pages/index.aspx">50</reference>
<rationale xml:lang="en-US">
An appropriate warning message reinforces policy awareness during the logon
process and facilitates possible legal action against attackers.
</rationale>
<check system="http://oval.mitre.org/XMLSchema/oval-definitions-5">
<check-content-ref name="oval:ssg:def:144" href="ssg-fedora-oval.xml"/>
</check>
<check system="ocil-transitional">
<check-export export-name="it is not" value-id="xccdf_org.ssgproject.content_value_conditional_clause"/>
<check-content>
To ensure a login warning banner is enabled, run the following:
<pre xmlns="http://www.w3.org/1999/xhtml">$ grep banner-message-enable /etc/dconf/db/gdm.d/*</pre>
If properly configured, the output should be <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">true</xhtml:code>.
To ensure a login warning banner is locked and cannot be changed by a user, run the following:
<pre xmlns="http://www.w3.org/1999/xhtml">$ grep banner-message-enable /etc/dconf/db/gdm.d/locks/*</pre>
If properly configured, the output should be <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/org/gnome/login-screen/banner-message-enable</xhtml:code>.
</check-content>
</check>
</Rule>
<Rule id="xccdf_org.ssgproject.content_rule_dconf_gnome_login_banner_text" selected="false" severity="medium">
<title xml:lang="en-US">Set the GNOME3 Login Warning Banner Text</title>
<description xml:lang="en-US">
To set the text shown by the GNOME3 Display Manager
in the login screen, the <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">banner-message-text</xhtml:code> setting must be set under an
appropriate configuration file(s) in the <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/dconf/db/gdm.d</xhtml:code> directory and locked
in <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/dconf/db/gdm.d/locks</xhtml:code> directory to prevent user modification.
After the settings have been set, run <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">dconf update</xhtml:code>.
When entering a warning banner that spans several lines, remember
to begin and end the string with <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">'</xhtml:code> and use <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">\n</xhtml:code> for new lines.
</description>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">AC-8(a)</reference>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">AC-8(b)</reference>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">AC-8(c)</reference>
<reference href="http://iase.disa.mil/stigs/cci/Pages/index.aspx">48</reference>
<reference href="http://iase.disa.mil/stigs/cci/Pages/index.aspx">1384</reference>
<reference href="http://iase.disa.mil/stigs/cci/Pages/index.aspx">1385</reference>
<reference href="http://iase.disa.mil/stigs/cci/Pages/index.aspx">1386</reference>
<reference href="http://iase.disa.mil/stigs/cci/Pages/index.aspx">1387</reference>
<reference href="http://iase.disa.mil/stigs/cci/Pages/index.aspx">1388</reference>
<rationale xml:lang="en-US">
An appropriate warning message reinforces policy awareness during the logon
process and facilitates possible legal action against attackers.
</rationale>
<check system="http://oval.mitre.org/XMLSchema/oval-definitions-5">
<check-export export-name="oval:ssg:var:456" value-id="xccdf_org.ssgproject.content_value_login_banner_text"/>
<check-content-ref name="oval:ssg:def:197" href="ssg-fedora-oval.xml"/>
</check>
<check system="ocil-transitional">
<check-export export-name="it does not" value-id="xccdf_org.ssgproject.content_value_conditional_clause"/>
<check-content>
To ensure the login warning banner text is properly set, run the following:
<pre xmlns="http://www.w3.org/1999/xhtml">$ grep banner-message-text /etc/dconf/db/gdm.d/*</pre>
If properly configured, the proper banner text will appear.
To ensure the login warning banner text is locked and cannot be changed by a user, run the following:
<pre xmlns="http://www.w3.org/1999/xhtml">$ grep banner-message-enable /etc/dconf/db/gdm.d/locks/*</pre>
If properly configured, the output should be <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/org/gnome/login-screen/banner-message-text</xhtml:code>.
</check-content>
</check>
</Rule>
</Group>
<Rule id="xccdf_org.ssgproject.content_rule_dconf_gnome_disable_user_list" selected="false" severity="low">
<title xml:lang="en-US">Disable the GNOME3 Login User List</title>
<description xml:lang="en-US">In the default graphical environment, users logging
directly into the system are greeted with a login screen that displays
all known users. This functionality should be disabled.
<br xmlns="http://www.w3.org/1999/xhtml"/><br xmlns="http://www.w3.org/1999/xhtml"/>
The <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">disable-user-list</xhtml:code> setting must be
set under an appropriate configuration file(s) in the <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/dconf/db/gdm.d</xhtml:code> directory
and locked in <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/dconf/db/gdm.d/locks</xhtml:code> directory to prevent user modification.
After the settings have been set, run <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">dconf update</xhtml:code>.
</description>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">AC-23</reference>
<rationale xml:lang="en-US">Leaving the user list enabled is a security risk since it allows anyone
with physical access to the system to quickly enumerate known user accounts
without logging in.</rationale>
<check system="ocil-transitional">
<check-export export-name="it is not" value-id="xccdf_org.ssgproject.content_value_conditional_clause"/>
<check-content>
To ensure the user list is disabled, run the following command:
<pre xmlns="http://www.w3.org/1999/xhtml">$ grep disable-user-list /etc/dconf/db/gdm.d/*</pre>
The output should be <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">true</xhtml:code>.
To ensure that users cannot enable displaying the user list, run the following:
<pre xmlns="http://www.w3.org/1999/xhtml">$ grep disable-user-list /etc/dconf/db/gdm.d/locks/*</pre>
If properly configured, the output should be <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/org/gnome/login-screen/disable-user-list</xhtml:code>
</check-content>
</check>
</Rule>
</Group>
</Group>
<Group id="xccdf_org.ssgproject.content_group_network">
<title xml:lang="en-US">Network Configuration and Firewalls</title>
<description xml:lang="en-US">Most machines must be connected to a network of some
sort, and this brings with it the substantial risk of network
attack. This section discusses the security impact of decisions
about networking which must be made when configuring a system.
<br xmlns="http://www.w3.org/1999/xhtml"/><br xmlns="http://www.w3.org/1999/xhtml"/>
This section also discusses firewalls, network access
controls, and other network security frameworks, which allow
system-level rules to be written that can limit an attackers' ability
to connect to your system. These rules can specify that network
traffic should be allowed or denied from certain IP addresses,
hosts, and networks. The rules can also specify which of the
system's network services are available to particular hosts or
networks.</description>
<Group id="xccdf_org.ssgproject.content_group_network_disable_unused_interfaces">
<title xml:lang="en-US">Disable Unused Interfaces</title>
<description xml:lang="en-US">Network interfaces expand the attack surface of the
system. Unused interfaces are not monitored or controlled, and
should be disabled.
<br xmlns="http://www.w3.org/1999/xhtml"/><br xmlns="http://www.w3.org/1999/xhtml"/>
If the system does not require network communications but still
needs to use the loopback interface, remove all files of the form
<xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">ifcfg-<i xmlns="http://www.w3.org/1999/xhtml">interface</i></xhtml:code> except for <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">ifcfg-lo</xhtml:code> from
<xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/sysconfig/network-scripts</xhtml:code>:
<pre xmlns="http://www.w3.org/1999/xhtml">$ sudo rm /etc/sysconfig/network-scripts/ifcfg-<i>interface</i></pre>
If the system is a standalone machine with no need for network access or even
communication over the loopback device, then disable this service.
The <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">network</xhtml:code> service can be disabled with the following command:
<xhtml:pre xmlns:xhtml="http://www.w3.org/1999/xhtml"># systemctl disable network.service</xhtml:pre>
</description>
</Group>
<Rule id="xccdf_org.ssgproject.content_rule_network_disable_zeroconf" selected="false" severity="low">
<title xml:lang="en-US">Disable Zeroconf Networking</title>
<description xml:lang="en-US">Zeroconf networking allows the system to assign itself an IP
address and engage in IP communication without a statically-assigned address or
even a DHCP server. Automatic address assignment via Zeroconf (or DHCP) is not
recommended. To disable Zeroconf automatic route assignment in the 169.254.0.0
subnet, add or correct the following line in <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/sysconfig/network</xhtml:code>:
<pre xmlns="http://www.w3.org/1999/xhtml">NOZEROCONF=yes</pre>
</description>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">CM-7</reference>
<rationale xml:lang="en-US">Zeroconf addresses are in the network 169.254.0.0. The networking
scripts add entries to the system's routing table for these addresses. Zeroconf
address assignment commonly occurs when the system is configured to use DHCP
but fails to receive an address assignment from the DHCP server.
</rationale>
</Rule>
<Rule id="xccdf_org.ssgproject.content_rule_network_sniffer_disabled" selected="false" severity="low">
<title xml:lang="en-US">Ensure System is Not Acting as a Network Sniffer</title>
<description xml:lang="en-US">The system should not be acting as a network sniffer, which can
capture all traffic on the network to which it is connected. Run the following
to determine if any interface is running in promiscuous mode:
<pre xmlns="http://www.w3.org/1999/xhtml">$ ip link | grep PROMISC</pre>
</description>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">CM-7</reference>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">MA-3</reference>
<rationale xml:lang="en-US">If any results are returned, then a sniffing process (such as tcpdump
or Wireshark) is likely to be using the interface and this should be
investigated.
</rationale>
</Rule>
<Group id="xccdf_org.ssgproject.content_group_network-ipv6">
<title xml:lang="en-US">IPv6</title>
<description xml:lang="en-US">The system includes support for Internet Protocol
version 6. A major and often-mentioned improvement over IPv4 is its
enormous increase in the number of available addresses. Another
important feature is its support for automatic configuration of
many network settings.</description>
<Group id="xccdf_org.ssgproject.content_group_disabling_ipv6">
<title xml:lang="en-US">Disable Support for IPv6 Unless Needed</title>
<description xml:lang="en-US">
Despite configuration that suggests support for IPv6 has
been disabled, link-local IPv6 address auto-configuration occurs
even when only an IPv4 address is assigned. The only way to
effectively prevent execution of the IPv6 networking stack is to
instruct the system not to activate the IPv6 kernel module.
</description>
<Rule id="xccdf_org.ssgproject.content_rule_sysctl_kernel_ipv6_disable" selected="false" severity="medium">
<title xml:lang="en-US">Disable IPv6 Networking Support Automatic Loading</title>
<description xml:lang="en-US">To disable support for (<xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">ipv6</xhtml:code>) add the following line to
<xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/sysctl.d/ipv6.conf</xhtml:code> (or another file in
<xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/sysctl.d</xhtml:code>):
<pre xmlns="http://www.w3.org/1999/xhtml">net.ipv6.conf.all.disable_ipv6 = 1</pre>
This disables IPv6 on all network interfaces as other services and system
functionality require the IPv6 stack loaded to work.
</description>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">CM-7</reference>
<reference href="http://iase.disa.mil/stigs/cci/Pages/index.aspx">1551</reference>
<rationale xml:lang="en-US">
Any unnecessary network stacks - including IPv6 - should be disabled, to reduce
the vulnerability to exploitation.
</rationale>
<check system="http://oval.mitre.org/XMLSchema/oval-definitions-5">
<check-content-ref name="oval:ssg:def:259" href="ssg-fedora-oval.xml"/>
</check>
<check system="ocil-transitional">
<check-export export-name="the ipv6 support is disabled on network interfaces" value-id="xccdf_org.ssgproject.content_value_conditional_clause"/>
<check-content>
If the system uses IPv6, this is not applicable.
<br xmlns="http://www.w3.org/1999/xhtml"/><br xmlns="http://www.w3.org/1999/xhtml"/>
If the system is configured to prevent the usage of the
<xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">ipv6</xhtml:code> on network interfaces, it will contain a line
of the form:
<pre xmlns="http://www.w3.org/1999/xhtml">net.ipv6.conf.all.disable_ipv6 = 1</pre>
Such lines may be inside any file in the <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/sysctl.d</xhtml:code> directory.
This permits insertion of the IPv6 kernel module (which other parts of
the system expect to be present), but otherwise keeps all network interfaces
from using IPv6.
Run the following command to search for such
lines in all files in <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/sysctl.d</xhtml:code>:
<pre xmlns="http://www.w3.org/1999/xhtml" xml:space="preserve">$ grep -r ipv6 /etc/sysctl.d</pre>
</check-content>
</check>
</Rule>
<Rule id="xccdf_org.ssgproject.content_rule_network_ipv6_disable_interfaces" selected="false" severity="low">
<title xml:lang="en-US">Disable Interface Usage of IPv6</title>
<description xml:lang="en-US">To disable interface usage of IPv6, add or correct the following lines in <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/sysconfig/network</xhtml:code>:
<pre xmlns="http://www.w3.org/1999/xhtml">NETWORKING_IPV6=no
IPV6INIT=no</pre>
</description>
</Rule>
<Rule id="xccdf_org.ssgproject.content_rule_network_ipv6_disable_rpc" selected="false" severity="low">
<title xml:lang="en-US">Disable Support for RPC IPv6</title>
<description xml:lang="en-US">RPC services for NFSv4 try to load transport modules for
<xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">udp6</xhtml:code> and <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">tcp6</xhtml:code> by default, even if IPv6 has been disabled in
<xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/modprobe.d</xhtml:code>. To prevent RPC services such as <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">rpc.mountd</xhtml:code>
from attempting to start IPv6 network listeners, remove or comment out the
following two lines in <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/netconfig</xhtml:code>:
<pre xmlns="http://www.w3.org/1999/xhtml">udp6 tpi_clts v inet6 udp - -
tcp6 tpi_cots_ord v inet6 tcp - -</pre>
</description>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">CM-7</reference>
</Rule>
</Group>
<Group id="xccdf_org.ssgproject.content_group_configuring_ipv6">
<title xml:lang="en-US">Configure IPv6 Settings if Necessary</title>
<description xml:lang="en-US">A major feature of IPv6 is the extent to which systems
implementing it can automatically configure their networking
devices using information from the network. From a security
perspective, manually configuring important configuration
information is preferable to accepting it from the network
in an unauthenticated fashion.</description>
<Group id="xccdf_org.ssgproject.content_group_disabling_ipv6_autoconfig">
<title xml:lang="en-US">Disable Automatic Configuration</title>
<description xml:lang="en-US">Disable the system's acceptance of router
advertisements and redirects by adding or correcting the following
line in <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/sysconfig/network</xhtml:code> (note that this does not disable
sending router solicitations):
<pre xmlns="http://www.w3.org/1999/xhtml">IPV6_AUTOCONF=no</pre>
</description>
<Value id="xccdf_org.ssgproject.content_value_sysconfig_network_IPV6_AUTOCONF_value" operator="equals" type="string">
<title xml:lang="en-US">IPV6_AUTOCONF</title>
<description xml:lang="en-US">Toggle global IPv6 auto-configuration (only, if global
forwarding is disabled)</description>
<value>no</value>
<value selector="enabled">yes</value>
<value selector="disabled">no</value>
</Value>
<Value id="xccdf_org.ssgproject.content_value_sysctl_net_ipv6_conf_default_accept_ra_value" operator="equals" type="string">
<title xml:lang="en-US">net.ipv6.conf.default.accept_ra</title>
<description xml:lang="en-US">Accept default router advertisements?</description>
<value>0</value>
<value selector="enabled">1</value>
<value selector="disabled">0</value>
</Value>
<Value id="xccdf_org.ssgproject.content_value_sysctl_net_ipv6_conf_default_accept_redirects_value" operator="equals" type="string">
<title xml:lang="en-US">net.ipv6.conf.default.accept_redirects</title>
<description xml:lang="en-US">Toggle ICMP Redirect Acceptance</description>
<value>0</value>
<value selector="enabled">1</value>
<value selector="disabled">0</value>
</Value>
<Rule id="xccdf_org.ssgproject.content_rule_sysctl_net_ipv6_conf_default_accept_ra" selected="false" severity="low">
<title xml:lang="en-US">Disable Accepting IPv6 Router Advertisements</title>
<description xml:lang="en-US">
To set the runtime status of the <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">net.ipv6.conf.default.accept_ra</xhtml:code> kernel parameter,
run the following command:
<xhtml:pre xmlns:xhtml="http://www.w3.org/1999/xhtml" xml:space="preserve"># sysctl -w net.ipv6.conf.default.accept_ra=0</xhtml:pre>
If this is not the system's default value, add the following line to <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/sysctl.conf</xhtml:code>:
<xhtml:pre xmlns:xhtml="http://www.w3.org/1999/xhtml" xml:space="preserve">net.ipv6.conf.default.accept_ra = 0</xhtml:pre>
</description>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">CM-7</reference>
<rationale xml:lang="en-US">
An illicit router advertisement message could result in a man-in-the-middle attack.
</rationale>
<check system="ocil-transitional">
<check-export export-name="the correct value is not returned" value-id="xccdf_org.ssgproject.content_value_conditional_clause"/>
<check-content>
The status of the <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">net.ipv6.conf.default.accept_ra</xhtml:code> kernel parameter can be queried
by running the following command:
<xhtml:pre xmlns:xhtml="http://www.w3.org/1999/xhtml" xml:space="preserve">$ sysctl net.ipv6.conf.default.accept_ra</xhtml:pre>
The output of the command should indicate a value of <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">0</xhtml:code>.
If this value is not the default value, investigate how it could have been
adjusted at runtime, and verify it is not set improperly in
<xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/sysctl.conf</xhtml:code>.
</check-content>
</check>
</Rule>
<Rule id="xccdf_org.ssgproject.content_rule_sysctl_net_ipv6_conf_default_accept_redirects" selected="false" severity="medium">
<title xml:lang="en-US">Disable Accepting IPv6 Redirects</title>
<description xml:lang="en-US">
To set the runtime status of the <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">net.ipv6.conf.default.accept_redirects</xhtml:code> kernel parameter,
run the following command:
<xhtml:pre xmlns:xhtml="http://www.w3.org/1999/xhtml" xml:space="preserve"># sysctl -w net.ipv6.conf.default.accept_redirects=0</xhtml:pre>
If this is not the system's default value, add the following line to <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/sysctl.conf</xhtml:code>:
<xhtml:pre xmlns:xhtml="http://www.w3.org/1999/xhtml" xml:space="preserve">net.ipv6.conf.default.accept_redirects = 0</xhtml:pre>
</description>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">CM-7</reference>
<reference href="http://iase.disa.mil/stigs/cci/Pages/index.aspx">1551</reference>
<rationale xml:lang="en-US">
An illicit ICMP redirect message could result in a man-in-the-middle attack.
</rationale>
<check system="ocil-transitional">
<check-export export-name="the correct value is not returned" value-id="xccdf_org.ssgproject.content_value_conditional_clause"/>
<check-content>
The status of the <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">net.ipv6.conf.default.accept_redirects</xhtml:code> kernel parameter can be queried
by running the following command:
<xhtml:pre xmlns:xhtml="http://www.w3.org/1999/xhtml" xml:space="preserve">$ sysctl net.ipv6.conf.default.accept_redirects</xhtml:pre>
The output of the command should indicate a value of <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">0</xhtml:code>.
If this value is not the default value, investigate how it could have been
adjusted at runtime, and verify it is not set improperly in
<xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/sysctl.conf</xhtml:code>.
</check-content>
</check>
</Rule>
</Group>
<Rule id="xccdf_org.ssgproject.content_rule_network_ipv6_static_address" selected="false" severity="low">
<title xml:lang="en-US">Manually Assign Global IPv6 Address</title>
<description xml:lang="en-US">To manually assign an IP address for an interface, edit the
file <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/sysconfig/network-scripts/ifcfg-<i xmlns="http://www.w3.org/1999/xhtml">interface</i></xhtml:code>. Add or correct the
following line (substituting the correct IPv6 address):
<pre xmlns="http://www.w3.org/1999/xhtml">IPV6ADDR=2001:0DB8::ABCD/64</pre>
Manually assigning an IP address is preferable to accepting one from routers or
from the network otherwise. The example address here is an IPv6 address
reserved for documentation purposes, as defined by RFC3849.
</description>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf"/>
</Rule>
<Rule id="xccdf_org.ssgproject.content_rule_network_ipv6_privacy_extensions" selected="false" severity="low">
<title xml:lang="en-US">Use Privacy Extensions for Address</title>
<description xml:lang="en-US">To introduce randomness into the automatic generation of IPv6
addresses, add or correct the following line in
<xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/sysconfig/network-scripts/ifcfg-<i xmlns="http://www.w3.org/1999/xhtml">interface</i></xhtml:code>:
<pre xmlns="http://www.w3.org/1999/xhtml">IPV6_PRIVACY=rfc3041</pre>
Automatically-generated IPv6 addresses are based on the underlying hardware
(e.g. Ethernet) address, and so it becomes possible to track a piece of
hardware over its lifetime using its traffic. If it is important for a system's
IP address to not trivially reveal its hardware address, this setting should be
applied.
</description>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf"/>
</Rule>
<Rule id="xccdf_org.ssgproject.content_rule_network_ipv6_default_gateway" selected="false" severity="low">
<title xml:lang="en-US">Manually Assign IPv6 Router Address</title>
<description xml:lang="en-US">Edit the file
<xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/sysconfig/network-scripts/ifcfg-<i xmlns="http://www.w3.org/1999/xhtml">interface</i></xhtml:code>, and add or correct
the following line (substituting your gateway IP as appropriate):
<pre xmlns="http://www.w3.org/1999/xhtml">IPV6_DEFAULTGW=2001:0DB8::0001</pre>
Router addresses should be manually set and not accepted via any
auto-configuration or router advertisement.
</description>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf"/>
</Rule>
<Group id="xccdf_org.ssgproject.content_group_network_ipv6_limit_requests">
<title xml:lang="en-US">Limit Network-Transmitted Configuration if Using Static IPv6 Addresses</title>
<description xml:lang="en-US">To limit the configuration information requested from other
systems and accepted from the network on a system that uses
statically-configured IPv6 addresses, add the following lines to
<xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/sysctl.conf</xhtml:code>:
<pre xmlns="http://www.w3.org/1999/xhtml">net.ipv6.conf.default.router_solicitations = 0
net.ipv6.conf.default.accept_ra_rtr_pref = 0
net.ipv6.conf.default.accept_ra_pinfo = 0
net.ipv6.conf.default.accept_ra_defrtr = 0
net.ipv6.conf.default.autoconf = 0
net.ipv6.conf.default.dad_transmits = 0
net.ipv6.conf.default.max_addresses = 1</pre>
The <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">router_solicitations</xhtml:code> setting determines how many router
solicitations are sent when bringing up the interface. If addresses are
statically assigned, there is no need to send any solicitations.
<br xmlns="http://www.w3.org/1999/xhtml"/><br xmlns="http://www.w3.org/1999/xhtml"/>
The <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">accept_ra_pinfo</xhtml:code> setting controls whether the system will accept
prefix info from the router.
<br xmlns="http://www.w3.org/1999/xhtml"/><br xmlns="http://www.w3.org/1999/xhtml"/>
The <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">accept_ra_defrtr</xhtml:code> setting controls whether the system will accept
Hop Limit settings from a router advertisement. Setting it to 0 prevents a
router from changing your default IPv6 Hop Limit for outgoing packets.
<br xmlns="http://www.w3.org/1999/xhtml"/><br xmlns="http://www.w3.org/1999/xhtml"/>
The <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">autoconf</xhtml:code> setting controls whether router advertisements can cause
the system to assign a global unicast address to an interface.
<br xmlns="http://www.w3.org/1999/xhtml"/><br xmlns="http://www.w3.org/1999/xhtml"/>
The <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">dad_transmits</xhtml:code> setting determines how many neighbor solicitations
to send out per address (global and link-local) when bringing up an interface
to ensure the desired address is unique on the network.
<br xmlns="http://www.w3.org/1999/xhtml"/><br xmlns="http://www.w3.org/1999/xhtml"/>
The <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">max_addresses</xhtml:code> setting determines how many global unicast IPv6
addresses can be assigned to each interface. The default is 16, but it should
be set to exactly the number of statically configured global addresses
required.
</description>
</Group>
</Group>
</Group>
</Group>
</Group>
<Group id="xccdf_org.ssgproject.content_group_services">
<title xml:lang="en-US">Services</title>
<description xml:lang="en-US">
The best protection against vulnerable software is running less software. This
section describes how to review the software which Fedora installs on a system
and disable software which is not needed. It then enumerates the software
packages installed on a default Fedora system and provides guidance about which
ones can be safely disabled.
<br xmlns="http://www.w3.org/1999/xhtml"/><br xmlns="http://www.w3.org/1999/xhtml"/>
Fedora provides a convenient minimal install option that essentially installs
the bare necessities for a functional system. When building Fedora servers, it
is highly recommended to select the minimal packages and then build up the
system from there.
</description>
<Group id="xccdf_org.ssgproject.content_group_ssh">
<title xml:lang="en-US">SSH Server</title>
<description xml:lang="en-US">The SSH protocol is recommended for remote login and remote file
transfer. SSH provides confidentiality and integrity for data exchanged between
two systems, as well as server authentication, through the use of public key
cryptography. The implementation included with the system is called OpenSSH,
and more detailed documentation is available from its website,
http://www.openssh.org. Its server program is called <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">sshd</xhtml:code> and
provided by the RPM package <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">openssh-server</xhtml:code>.</description>
<Value id="xccdf_org.ssgproject.content_value_sshd_idle_timeout_value" operator="equals" type="number">
<title xml:lang="en-US">SSH session Idle time</title>
<description xml:lang="en-US">Specify duration of allowed idle time.</description>
<value>300</value>
<value selector="5_minutes">300</value>
<value selector="10_minutes">600</value>
<value selector="15_minutes">900</value>
</Value>
<Group id="xccdf_org.ssgproject.content_group_ssh_server">
<title xml:lang="en-US">Configure OpenSSH Server if Necessary</title>
<description xml:lang="en-US">If the system needs to act as an SSH server, then certain changes
should be made to the OpenSSH daemon configuration file
<xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/ssh/sshd_config</xhtml:code>. The following recommendations can be applied
to this file. See the <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">sshd_config(5)</xhtml:code> man page for more detailed
information.</description>
<Rule id="xccdf_org.ssgproject.content_rule_sshd_disable_root_login" selected="false" severity="medium">
<title xml:lang="en-US">SSH Root Login Disabled</title>
<description xml:lang="en-US">The root user should never be allowed to login to a system
directly over a network. To disable root login via SSH, add or correct the
following line in <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/ssh/sshd_config</xhtml:code>:
<pre xmlns="http://www.w3.org/1999/xhtml">PermitRootLogin no</pre>
</description>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">AC-6(2)</reference>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">IA-2(1)</reference>
<reference href="http://iase.disa.mil/stigs/cci/Pages/index.aspx">770</reference>
<rationale xml:lang="en-US">
Permitting direct root login reduces auditable information about who ran
privileged commands on the system and also allows direct attack attempts on
root's password.
</rationale>
<fix system="urn:xccdf:fix:script:sh">
SSHD_CONFIG='/etc/ssh/sshd_config'
# Obtain line number of first uncommented case-insensitive occurrence of Match
# block directive (possibly prefixed with whitespace) present in $SSHD_CONFIG
FIRST_MATCH_BLOCK=$(sed -n '/^[[:space:]]*Match[^\n]*/I{=;q}' $SSHD_CONFIG)
# Obtain line number of first uncommented case-insensitive occurence of
# PermitRootLogin directive (possibly prefixed with whitespace) present in
# $SSHD_CONFIG
FIRST_PERMIT_ROOT_LOGIN=$(sed -n '/^[[:space:]]*PermitRootLogin[^\n]*/I{=;q}' $SSHD_CONFIG)
# Case: Match block directive not present in $SSHD_CONFIG
if [ -z "$FIRST_MATCH_BLOCK" ]
then
# Case: PermitRootLogin directive not present in $SSHD_CONFIG yet
if [ -z "$FIRST_PERMIT_ROOT_LOGIN" ]
then
# Append 'PermitRootLogin no' at the end of $SSHD_CONFIG
echo -e "\nPermitRootLogin no" >> $SSHD_CONFIG
# Case: PermitRootLogin directive present in $SSHD_CONFIG already
else
# Replace first uncommented case-insensitive occurrence
# of PermitRootLogin directive
sed -i "$FIRST_PERMIT_ROOT_LOGIN s/^[[:space:]]*PermitRootLogin.*$/PermitRootLogin no/I" $SSHD_CONFIG
fi
# Case: Match block directive present in $SSHD_CONFIG
else
# Case: PermitRootLogin directive not present in $SSHD_CONFIG yet
if [ -z "$FIRST_PERMIT_ROOT_LOGIN" ]
then
# Prepend 'PermitRootLogin no' before first uncommented
# case-insensitive occurrence of Match block directive
sed -i "$FIRST_MATCH_BLOCK s/^\([[:space:]]*Match[^\n]*\)/PermitRootLogin no\n\1/I" $SSHD_CONFIG
# Case: PermitRootLogin directive present in $SSHD_CONFIG and placed
# before first Match block directive
elif [ "$FIRST_PERMIT_ROOT_LOGIN" -lt "$FIRST_MATCH_BLOCK" ]
then
# Replace first uncommented case-insensitive occurrence
# of PermitRootLogin directive
sed -i "$FIRST_PERMIT_ROOT_LOGIN s/^[[:space:]]*PermitRootLogin.*$/PermitRootLogin no/I" $SSHD_CONFIG
# Case: PermitRootLogin directive present in $SSHD_CONFIG and placed
# after first Match block directive
else
# Prepend 'PermitRootLogin no' before first uncommented
# case-insensitive occurrence of Match block directive
sed -i "$FIRST_MATCH_BLOCK s/^\([[:space:]]*Match[^\n]*\)/PermitRootLogin no\n\1/I" $SSHD_CONFIG
fi
fi
</fix>
<check system="http://oval.mitre.org/XMLSchema/oval-definitions-5">
<check-content-ref name="oval:ssg:def:243" href="ssg-fedora-oval.xml"/>
</check>
</Rule>
<Rule id="xccdf_org.ssgproject.content_rule_sshd_disable_empty_passwords" selected="false" severity="high">
<title xml:lang="en-US">SSH Access via Empty Passwords Disabled</title>
<description xml:lang="en-US">To explicitly disallow remote login from accounts with empty
passwords, add or correct the following line in <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/ssh/sshd_config</xhtml:code>:
<pre xmlns="http://www.w3.org/1999/xhtml">PermitEmptyPasswords no</pre>
Any accounts with empty passwords should be disabled immediately, and PAM
configuration should prevent users from being able to assign themselves empty
passwords.
</description>
<reference href="http://iase.disa.mil/stigs/cci/Pages/index.aspx">765</reference>
<reference href="http://iase.disa.mil/stigs/cci/Pages/index.aspx">766</reference>
<rationale xml:lang="en-US">
Configuring this setting for the SSH daemon provides additional assurance that
remote login via SSH will require a password, even in the event of
misconfiguration elsewhere.
</rationale>
<fix system="urn:xccdf:fix:script:sh">
SSHD_CONFIG='/etc/ssh/sshd_config'
# Obtain line number of first uncommented case-insensitive occurrence of Match
# block directive (possibly prefixed with whitespace) present in $SSHD_CONFIG
FIRST_MATCH_BLOCK=$(sed -n '/^[[:space:]]*Match[^\n]*/I{=;q}' $SSHD_CONFIG)
# Obtain line number of first uncommented case-insensitive occurence of
# PermitEmptyPasswords directive (possibly prefixed with whitespace) present in
# $SSHD_CONFIG
FIRST_PERMIT_EMPTY_PASSWORDS=$(sed -n '/^[[:space:]]*PermitEmptyPasswords[^\n]*/I{=;q}' $SSHD_CONFIG)
# Case: Match block directive not present in $SSHD_CONFIG
if [ -z "$FIRST_MATCH_BLOCK" ]
then
# Case: PermitEmptyPasswords directive not present in $SSHD_CONFIG yet
if [ -z "$FIRST_PERMIT_EMPTY_PASSWORDS" ]
then
# Append 'PermitEmptyPasswords no' at the end of $SSHD_CONFIG
echo -e "\nPermitEmptyPasswords no" >> $SSHD_CONFIG
# Case: PermitEmptyPasswords directive present in $SSHD_CONFIG already
else
# Replace first uncommented case-insensitive occurrence
# of PermitEmptyPasswords directive
sed -i "$FIRST_PERMIT_EMPTY_PASSWORDS s/^[[:space:]]*PermitEmptyPasswords.*$/PermitEmptyPasswords no/I" $SSHD_CONFIG
fi
# Case: Match block directive present in $SSHD_CONFIG
else
# Case: PermitEmptyPasswords directive not present in $SSHD_CONFIG yet
if [ -z "$FIRST_PERMIT_EMPTY_PASSWORDS" ]
then
# Prepend 'PermitEmptyPasswords no' before first uncommented
# case-insensitive occurrence of Match block directive
sed -i "$FIRST_MATCH_BLOCK s/^\([[:space:]]*Match[^\n]*\)/PermitEmptyPasswords no\n\1/I" $SSHD_CONFIG
# Case: PermitEmptyPasswords directive present in $SSHD_CONFIG and placed
# before first Match block directive
elif [ "$FIRST_PERMIT_EMPTY_PASSWORDS" -lt "$FIRST_MATCH_BLOCK" ]
then
# Replace first uncommented case-insensitive occurrence
# of PermitEmptyPasswords directive
sed -i "$FIRST_PERMIT_EMPTY_PASSWORDS s/^[[:space:]]*PermitEmptyPasswords.*$/PermitEmptyPasswords no/I" $SSHD_CONFIG
# Case: PermitEmptyPasswords directive present in $SSHD_CONFIG and placed
# after first Match block directive
else
# Prepend 'PermitEmptyPasswords no' before first uncommented
# case-insensitive occurrence of Match block directive
sed -i "$FIRST_MATCH_BLOCK s/^\([[:space:]]*Match[^\n]*\)/PermitEmptyPasswords no\n\1/I" $SSHD_CONFIG
fi
fi
</fix>
<check system="http://oval.mitre.org/XMLSchema/oval-definitions-5">
<check-content-ref name="oval:ssg:def:227" href="ssg-fedora-oval.xml"/>
</check>
</Rule>
<Rule id="xccdf_org.ssgproject.content_rule_sshd_set_idle_timeout" selected="false" severity="low">
<title xml:lang="en-US">SSH Idle Timeout Interval Used</title>
<description xml:lang="en-US">SSH allows administrators to set an idle timeout interval.
After this interval has passed, the idle user will be automatically logged out.
<br xmlns="http://www.w3.org/1999/xhtml"/><br xmlns="http://www.w3.org/1999/xhtml"/>
To set an idle timeout interval, edit the <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/ssh/sshd_config</xhtml:code> file,
locate the following line:
<pre xmlns="http://www.w3.org/1999/xhtml">ClientAliveInterval <b>INTERVAL</b></pre>
and correct it to have the form of:
<pre xmlns="http://www.w3.org/1999/xhtml">ClientAliveInterval <b><sub xmlns="http://checklists.nist.gov/xccdf/1.2" idref="xccdf_org.ssgproject.content_value_sshd_idle_timeout_value" use="legacy"/></b></pre>
The timeout <b xmlns="http://www.w3.org/1999/xhtml">INTERVAL</b> is given in seconds. To have a timeout of 15
minutes, set <b xmlns="http://www.w3.org/1999/xhtml">INTERVAL</b> to 900.
<br xmlns="http://www.w3.org/1999/xhtml"/><br xmlns="http://www.w3.org/1999/xhtml"/>
If a shorter timeout has already been set for the login shell, that value will
preempt any SSH setting made here. Keep in mind that some processes may stop
SSH from correctly detecting that the user is idle.
</description>
<reference href="http://iase.disa.mil/stigs/cci/Pages/index.aspx">879</reference>
<reference href="http://iase.disa.mil/stigs/cci/Pages/index.aspx">1133</reference>
<rationale xml:lang="en-US">
Causing idle users to be automatically logged out guards against compromises
one system leading trivially to compromises on another.
</rationale>
<fix system="urn:xccdf:fix:script:sh">sshd_idle_timeout_value="<sub idref="xccdf_org.ssgproject.content_value_sshd_idle_timeout_value" use="legacy"/>"
SSHD_CONFIG='/etc/ssh/sshd_config'
# Obtain line number of first uncommented case-insensitive occurrence of Match
# block directive (possibly prefixed with whitespace) present in $SSHD_CONFIG
FIRST_MATCH_BLOCK=$(sed -n '/^[[:space:]]*Match[^\n]*/I{=;q}' $SSHD_CONFIG)
# Obtain line number of first uncommented case-insensitive occurence of
# ClientAliveInterval directive (possibly prefixed with whitespace) present in
# $SSHD_CONFIG
FIRST_CLIENT_ALIVE_INTERVAL=$(sed -n '/^[[:space:]]*ClientAliveInterval[^\n]*/I{=;q}' $SSHD_CONFIG)
# Case: Match block directive not present in $SSHD_CONFIG
if [ -z "$FIRST_MATCH_BLOCK" ]
then
# Case: ClientAliveInterval directive not present in $SSHD_CONFIG yet
if [ -z "$FIRST_CLIENT_ALIVE_INTERVAL" ]
then
# Append 'ClientAliveInterval $sshd_idle_timeout_value' at the end of $SSHD_CONFIG
echo -e "\nClientAliveInterval $sshd_idle_timeout_value" >> $SSHD_CONFIG
# Case: ClientAliveInterval directive present in $SSHD_CONFIG already
else
# Replace first uncommented case-insensitive occurrence
# of ClientAliveInterval directive
sed -i "$FIRST_CLIENT_ALIVE_INTERVAL s/^[[:space:]]*ClientAliveInterval.*$/ClientAliveInterval $sshd_idle_timeout_value/I" $SSHD_CONFIG
fi
# Case: Match block directive present in $SSHD_CONFIG
else
# Case: ClientAliveInterval directive not present in $SSHD_CONFIG yet
if [ -z "$FIRST_CLIENT_ALIVE_INTERVAL" ]
then
# Prepend 'ClientAliveInterval $sshd_idle_timeout_value' before first uncommented
# case-insensitive occurrence of Match block directive
sed -i "$FIRST_MATCH_BLOCK s/^\([[:space:]]*Match[^\n]*\)/ClientAliveInterval $sshd_idle_timeout_value\n\1/I" $SSHD_CONFIG
# Case: ClientAliveInterval directive present in $SSHD_CONFIG and placed
# before first Match block directive
elif [ "$FIRST_CLIENT_ALIVE_INTERVAL" -lt "$FIRST_MATCH_BLOCK" ]
then
# Replace first uncommented case-insensitive occurrence
# of ClientAliveInterval directive
sed -i "$FIRST_CLIENT_ALIVE_INTERVAL s/^[[:space:]]*ClientAliveInterval.*$/ClientAliveInterval $sshd_idle_timeout_value/I" $SSHD_CONFIG
# Case: ClientAliveInterval directive present in $SSHD_CONFIG and placed
# after first Match block directive
else
# Prepend 'ClientAliveInterval $sshd_idle_timeout_value' before first uncommented
# case-insensitive occurrence of Match block directive
sed -i "$FIRST_MATCH_BLOCK s/^\([[:space:]]*Match[^\n]*\)/ClientAliveInterval $sshd_idle_timeout_value\n\1/I" $SSHD_CONFIG
fi
fi
</fix>
<check system="http://oval.mitre.org/XMLSchema/oval-definitions-5">
<check-export export-name="oval:ssg:var:465" value-id="xccdf_org.ssgproject.content_value_sshd_idle_timeout_value"/>
<check-content-ref name="oval:ssg:def:141" href="ssg-fedora-oval.xml"/>
</check>
</Rule>
<Rule id="xccdf_org.ssgproject.content_rule_sshd_set_keepalive" selected="false" severity="low">
<title xml:lang="en-US">SSH Client Alive Count Used</title>
<description xml:lang="en-US">To ensure the SSH idle timeout occurs precisely when the
<xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">ClientAliveCountMax</xhtml:code> is set, edit <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/ssh/sshd_config</xhtml:code> as
follows:
<pre xmlns="http://www.w3.org/1999/xhtml">ClientAliveCountMax 0</pre>
</description>
<reference href="http://iase.disa.mil/stigs/cci/Pages/index.aspx">879</reference>
<reference href="http://iase.disa.mil/stigs/cci/Pages/index.aspx">1133</reference>
<rationale xml:lang="en-US">
This ensures a user login will be terminated as soon as the
<xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">ClientAliveCountMax</xhtml:code> is reached.
</rationale>
<fix system="urn:xccdf:fix:script:sh">
SSHD_CONFIG='/etc/ssh/sshd_config'
# Obtain line number of first uncommented case-insensitive occurrence of Match
# block directive (possibly prefixed with whitespace) present in $SSHD_CONFIG
FIRST_MATCH_BLOCK=$(sed -n '/^[[:space:]]*Match[^\n]*/I{=;q}' $SSHD_CONFIG)
# Obtain line number of first uncommented case-insensitive occurence of
# ClientAliveCountMax directive (possibly prefixed with whitespace) present in
# $SSHD_CONFIG
FIRST_CLIENT_ALIVE_COUNT_MAX=$(sed -n '/^[[:space:]]*ClientAliveCountMax[^\n]*/I{=;q}' $SSHD_CONFIG)
# Case: Match block directive not present in $SSHD_CONFIG
if [ -z "$FIRST_MATCH_BLOCK" ]
then
# Case: ClientAliveCountMax directive not present in $SSHD_CONFIG yet
if [ -z "$FIRST_CLIENT_ALIVE_COUNT_MAX" ]
then
# Append 'ClientAliveCountMax 0' at the end of $SSHD_CONFIG
echo -e "\nClientAliveCountMax 0" >> $SSHD_CONFIG
# Case: ClientAliveCountMax directive present in $SSHD_CONFIG already
else
# Replace first uncommented case-insensitive occurrence
# of ClientAliveCountMax directive
sed -i "$FIRST_CLIENT_ALIVE_COUNT_MAX s/^[[:space:]]*ClientAliveCountMax.*$/ClientAliveCountMax 0/I" $SSHD_CONFIG
fi
# Case: Match block directive present in $SSHD_CONFIG
else
# Case: ClientAliveCountMax directive not present in $SSHD_CONFIG yet
if [ -z "$FIRST_CLIENT_ALIVE_COUNT_MAX" ]
then
# Prepend 'ClientAliveCountMax 0' before first uncommented
# case-insensitive occurrence of Match block directive
sed -i "$FIRST_MATCH_BLOCK s/^\([[:space:]]*Match[^\n]*\)/ClientAliveCountMax 0\n\1/I" $SSHD_CONFIG
# Case: ClientAliveCountMax directive present in $SSHD_CONFIG and placed
# before first Match block directive
elif [ "$FIRST_CLIENT_ALIVE_COUNT_MAX" -lt "$FIRST_MATCH_BLOCK" ]
then
# Replace first uncommented case-insensitive occurrence
# of ClientAliveCountMax directive
sed -i "$FIRST_CLIENT_ALIVE_COUNT_MAX s/^[[:space:]]*ClientAliveCountMax.*$/ClientAliveCountMax 0/I" $SSHD_CONFIG
# Case: ClientAliveCountMax directive present in $SSHD_CONFIG and placed
# after first Match block directive
else
# Prepend 'ClientAliveCountMax 0' before first uncommented
# case-insensitive occurrence of Match block directive
sed -i "$FIRST_MATCH_BLOCK s/^\([[:space:]]*Match[^\n]*\)/ClientAliveCountMax 0\n\1/I" $SSHD_CONFIG
fi
fi
</fix>
<check system="http://oval.mitre.org/XMLSchema/oval-definitions-5">
<check-content-ref name="oval:ssg:def:205" href="ssg-fedora-oval.xml"/>
</check>
</Rule>
</Group>
</Group>
<Group id="xccdf_org.ssgproject.content_group_ntp">
<title xml:lang="en-US">Network Time Protocol</title>
<description xml:lang="en-US">The Network Time Protocol is used to manage the system
clock over a network. Computer clocks are not very accurate, so
time will drift unpredictably on unmanaged systems. Central time
protocols can be used both to ensure that time is consistent among
a network of machines, and that their time is consistent with the
outside world.
<br xmlns="http://www.w3.org/1999/xhtml"/><br xmlns="http://www.w3.org/1999/xhtml"/>
If every system on a network reliably reports the same time, then it is much
easier to correlate log messages in case of an attack. In addition, a number of
cryptographic protocols (such as Kerberos) use timestamps to prevent certain
types of attacks. If your network does not have synchronized time, these
protocols may be unreliable or even unusable.
<br xmlns="http://www.w3.org/1999/xhtml"/><br xmlns="http://www.w3.org/1999/xhtml"/>
Depending on the specifics of the network, global time accuracy may be just as
important as local synchronization, or not very important at all. If your
network is connected to the Internet, using a
public timeserver (or one provided by your enterprise) provides globally
accurate timestamps which may be essential in investigating or responding to
an attack which originated outside of your network.
<br xmlns="http://www.w3.org/1999/xhtml"/><br xmlns="http://www.w3.org/1999/xhtml"/>
A typical network setup involves a small number of internal systems operating as NTP
servers, and the remainder obtaining time information from those
internal servers.
<br xmlns="http://www.w3.org/1999/xhtml"/><br xmlns="http://www.w3.org/1999/xhtml"/>
More information on how to configure the NTP server software,
including configuration of cryptographic authentication for
time data, is available at http://www.ntp.org.
</description>
<Rule id="xccdf_org.ssgproject.content_rule_service_ntpd_enabled" selected="false" severity="medium">
<title xml:lang="en-US">Enable the NTP Daemon</title>
<description xml:lang="en-US">
The <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">ntpd</xhtml:code> service can be enabled with the following command:
<xhtml:pre xmlns:xhtml="http://www.w3.org/1999/xhtml"># systemctl enable ntpd.service</xhtml:pre>
</description>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">AU-8(1)</reference>
<reference href="http://iase.disa.mil/stigs/cci/Pages/index.aspx">160</reference>
<rationale xml:lang="en-US">Enabling the <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">ntpd</xhtml:code> service ensures that the <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">ntpd</xhtml:code>
service will be running and that the system will synchronize its time to
any servers specified. This is important whether the system is configured to be
a client (and synchronize only its own clock) or it is also acting as an NTP
server to other systems. Synchronizing time is essential for authentication
services such as Kerberos, but it is also important for maintaining accurate
logs and auditing possible security breaches.
<br xmlns="http://www.w3.org/1999/xhtml"/><br xmlns="http://www.w3.org/1999/xhtml"/>
The NTP daemon offers all of the functionality of <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">ntpdate</xhtml:code>, which is now
deprecated. Additional information on this is available at
http://support.ntp.org/bin/view/Dev/DeprecatingNtpdate</rationale>
<fix system="urn:xccdf:fix:script:sh">#
# Install ntp package if necessary
#
yum -y install ntp
#
# Enable ntpd service (for current systemd target)
#
systemctl enable ntpd.service
#
# Start ntpd if not currently running
#
systemctl start ntpd.service
</fix>
<check system="http://oval.mitre.org/XMLSchema/oval-definitions-5">
<check-content-ref name="oval:ssg:def:272" href="ssg-fedora-oval.xml"/>
</check>
<check system="ocil-transitional">
<check-export export-name="the service is not running" value-id="xccdf_org.ssgproject.content_value_conditional_clause"/>
<check-content>
Run the following command to determine the current status of the
<xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">ntpd</xhtml:code> service:
<xhtml:pre xmlns:xhtml="http://www.w3.org/1999/xhtml"># service ntpd status</xhtml:pre>
If the service is enabled, it should return the following: <xhtml:pre xmlns:xhtml="http://www.w3.org/1999/xhtml">ntpd is running...</xhtml:pre>
</check-content>
</check>
</Rule>
<Rule id="xccdf_org.ssgproject.content_rule_ntpd_specify_remote_server" selected="false" severity="medium">
<title xml:lang="en-US">Specify a Remote NTP Server</title>
<description xml:lang="en-US">To specify a remote NTP server for time synchronization, edit
the file <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/ntp.conf</xhtml:code>. Add or correct the following lines,
substituting the IP or hostname of a remote NTP server for <em xmlns="http://www.w3.org/1999/xhtml">ntpserver</em>:
<pre xmlns="http://www.w3.org/1999/xhtml">server <i>ntpserver</i></pre>
This instructs the NTP software to contact that remote server to obtain time
data.
</description>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">AU-8(1)</reference>
<reference href="http://iase.disa.mil/stigs/cci/Pages/index.aspx">160</reference>
<rationale xml:lang="en-US">Synchronizing with an NTP server makes it possible
to collate system logs from multiple sources or correlate computer events with
real time events.
</rationale>
<check system="http://oval.mitre.org/XMLSchema/oval-definitions-5">
<check-content-ref name="oval:ssg:def:203" href="ssg-fedora-oval.xml"/>
</check>
<check system="ocil-transitional">
<check-export export-name="this is not the case" value-id="xccdf_org.ssgproject.content_value_conditional_clause"/>
<check-content>
To verify that a remote NTP service is configured for time synchronization,
open the following file:
<pre xmlns="http://www.w3.org/1999/xhtml">/etc/ntp.conf</pre>
In the file, there should be a section similar to the following:
<pre xmlns="http://www.w3.org/1999/xhtml">server <i>ntpserver</i></pre>
</check-content>
</check>
</Rule>
<Rule id="xccdf_org.ssgproject.content_rule_ntpd_specify_multiple_servers" selected="false" severity="low">
<title xml:lang="en-US">Specify Additional Remote NTP Servers</title>
<description xml:lang="en-US">Additional NTP servers can be specified for time synchronization
in the file <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/ntp.conf</xhtml:code>. To do so, add additional lines of the
following form, substituting the IP address or hostname of a remote NTP server for
<em xmlns="http://www.w3.org/1999/xhtml">ntpserver</em>:
<pre xmlns="http://www.w3.org/1999/xhtml">server <i>ntpserver</i></pre>
</description>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">AU-8(1)</reference>
<rationale xml:lang="en-US">Specifying additional NTP servers increases the availability of
accurate time data, in the event that one of the specified servers becomes
unavailable. This is typical for a system acting as an NTP server for
other systems.
</rationale>
<check system="http://oval.mitre.org/XMLSchema/oval-definitions-5">
<check-content-ref name="oval:ssg:def:125" href="ssg-fedora-oval.xml"/>
</check>
</Rule>
</Group>
<Group id="xccdf_org.ssgproject.content_group_ftp">
<title xml:lang="en-US">FTP Server</title>
<description xml:lang="en-US">FTP is a common method for allowing remote access to
files. Like telnet, the FTP protocol is unencrypted, which means
that passwords and other data transmitted during the session can be
captured and that the session is vulnerable to hijacking.
Therefore, running the FTP server software is not recommended.
<br xmlns="http://www.w3.org/1999/xhtml"/><br xmlns="http://www.w3.org/1999/xhtml"/>
However, there are some FTP server configurations which may
be appropriate for some environments, particularly those which
allow only read-only anonymous access as a means of downloading
data available to the public.</description>
<Group id="xccdf_org.ssgproject.content_group_disabling_vsftpd">
<title xml:lang="en-US">Disable vsftpd if Possible</title>
<Rule id="xccdf_org.ssgproject.content_rule_disable_vsftpd" selected="false" severity="low">
<title xml:lang="en-US">Disable vsftpd Service</title>
<description xml:lang="en-US">
The <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">vsftpd</xhtml:code> service can be disabled with the following command:
<xhtml:pre xmlns:xhtml="http://www.w3.org/1999/xhtml"># systemctl disable vsftpd.service</xhtml:pre>
</description>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">CM-7</reference>
<reference href="http://iase.disa.mil/stigs/cci/Pages/index.aspx">1436</reference>
<rationale xml:lang="en-US">
Running FTP server software provides a network-based avenue
of attack, and should be disabled if not needed.
Furthermore, the FTP protocol is unencrypted and creates
a risk of compromising sensitive information.
</rationale>
<check system="ocil-transitional">
<check-export export-name="the service is running" value-id="xccdf_org.ssgproject.content_value_conditional_clause"/>
<check-content>
To check that the <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">vsftpd</xhtml:code> service is disabled in system boot configuration, run the following command:
<xhtml:pre xmlns:xhtml="http://www.w3.org/1999/xhtml"># chkconfig <xhtml:code>vsftpd</xhtml:code> --list</xhtml:pre>
Output should indicate the <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">vsftpd</xhtml:code> service has either not been installed,
or has been disabled at all runlevels, as shown in the example below:
<xhtml:pre xmlns:xhtml="http://www.w3.org/1999/xhtml"># chkconfig <xhtml:code>vsftpd</xhtml:code> --list
<xhtml:code>vsftpd</xhtml:code> 0:off 1:off 2:off 3:off 4:off 5:off 6:off</xhtml:pre>
Run the following command to verify <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">vsftpd</xhtml:code> is disabled through current runtime configuration:
<xhtml:pre xmlns:xhtml="http://www.w3.org/1999/xhtml"># service vsftpd status</xhtml:pre>
If the service is disabled the command will return the following output:
<xhtml:pre xmlns:xhtml="http://www.w3.org/1999/xhtml">vsftpd is stopped</xhtml:pre>
</check-content>
</check>
</Rule>
<Rule id="xccdf_org.ssgproject.content_rule_uninstall_vsftpd" selected="false" severity="low">
<title xml:lang="en-US">Uninstall vsftpd Package</title>
<description xml:lang="en-US">
The <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">vsftpd</xhtml:code> package can be removed with the following command:
<xhtml:pre xmlns:xhtml="http://www.w3.org/1999/xhtml"># yum erase vsftpd</xhtml:pre>
</description>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">CM-7</reference>
<reference href="http://iase.disa.mil/stigs/cci/Pages/index.aspx">1436</reference>
<rationale xml:lang="en-US">
Removing the vsftpd package decreases the risk of its
accidental activation.
</rationale>
<check system="ocil-transitional">
<check-export export-name="the package is installed" value-id="xccdf_org.ssgproject.content_value_conditional_clause"/>
<check-content>
Run the following command to determine if the <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">vsftpd</xhtml:code> package is installed:
<xhtml:pre xmlns:xhtml="http://www.w3.org/1999/xhtml"># rpm -q vsftpd</xhtml:pre>
</check-content>
</check>
</Rule>
</Group>
<Group id="xccdf_org.ssgproject.content_group_ftp_use_vsftpd">
<title xml:lang="en-US">Use vsftpd to Provide FTP Service if Necessary</title>
<Rule id="xccdf_org.ssgproject.content_rule_package_vsftpd_installed" selected="false" severity="low">
<title xml:lang="en-US">Install vsftpd Package</title>
<description xml:lang="en-US">If this machine must operate as an FTP server, install the <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">vsftpd</xhtml:code> package via the standard channels.
<pre xmlns="http://www.w3.org/1999/xhtml"># yum install vsftpd</pre>
</description>
<reference href="http://csrc.nist.gov/publications/nistpubs/800-53-Rev3/sp800-53-rev3-final.pdf">CM-7</reference>
<rationale xml:lang="en-US">After RHEL 2.1, Red Hat switched from distributing wu-ftpd with RHEL to distributing vsftpd. For security
and for consistency with future Red Hat releases, the use of vsftpd is recommended.</rationale>
<check system="http://oval.mitre.org/XMLSchema/oval-definitions-5">
<check-content-ref name="oval:ssg:def:168" href="ssg-fedora-oval.xml"/>
</check>
</Rule>
</Group>
<Group id="xccdf_org.ssgproject.content_group_ftp_configure_vsftpd">
<title xml:lang="en-US">Use vsftpd to Provide FTP Service if Necessary</title>
<description xml:lang="en-US">The primary vsftpd configuration file is
<xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/vsftpd.conf</xhtml:code>, if that file exists, or
<xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/vsftpd/vsftpd.conf</xhtml:code> if it does not.
</description>
<Rule id="xccdf_org.ssgproject.content_rule_ftp_log_transactions" selected="false" severity="low">
<title xml:lang="en-US">Enable Logging of All FTP Transactions</title>
<description xml:lang="en-US">Add or correct the following configuration options within the <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">vsftpd</xhtml:code>
configuration file, located at <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/vsftpd/vsftpd.conf</xhtml:code>:
<pre xmlns="http://www.w3.org/1999/xhtml">xferlog_enable=YES
xferlog_std_format=NO
log_ftp_protocol=YES</pre>
</description>
<warning xml:lang="en-US" override="false" category="general">If verbose logging to <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">vsftpd.log</xhtml:code> is done, sparse logging of downloads to <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/var/log/xferlog</xhtml:code> will not also occur. However, the information about what files were downloaded is included in the information logged to <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">vsftpd.log</xhtml:code></warning>
<rationale xml:lang="en-US">To trace malicious activity facilitated by the FTP service, it must be configured to ensure that all commands sent to
the FTP server are logged using the verbose vsftpd log
format. The default vsftpd log file is <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/var/log/vsftpd.log</xhtml:code>.</rationale>
<check system="http://oval.mitre.org/XMLSchema/oval-definitions-5">
<check-content-ref name="oval:ssg:def:167" href="ssg-fedora-oval.xml"/>
</check>
<check system="ocil-transitional">
<check-export export-name="xferlog_enable is missing, or is not set to yes" value-id="xccdf_org.ssgproject.content_value_conditional_clause"/>
<check-content>
Find if logging is applied to the FTP daemon.
<br xmlns="http://www.w3.org/1999/xhtml"/><br xmlns="http://www.w3.org/1999/xhtml"/>
Procedures:
<br xmlns="http://www.w3.org/1999/xhtml"/><br xmlns="http://www.w3.org/1999/xhtml"/>
If vsftpd is started by xinetd the following command will indicate the xinetd.d startup file:
<pre xmlns="http://www.w3.org/1999/xhtml"># grep vsftpd /etc/xinetd.d/*</pre>
<pre xmlns="http://www.w3.org/1999/xhtml"># grep server_args <i>vsftpd xinetd.d startup file</i></pre>
This will indicate the vsftpd config file used when starting through xinetd.
If the <i xmlns="http://www.w3.org/1999/xhtml">server_args</i> line is missing or does not include the vsftpd configuration file, then the default config file (/etc/vsftpd/vsftpd.conf) is used.
<pre xmlns="http://www.w3.org/1999/xhtml"># grep xferlog_enable <i>vsftpd config file</i></pre>
</check-content>
</check>
</Rule>
<Rule id="xccdf_org.ssgproject.content_rule_ftp_present_banner" selected="false" severity="medium">
<title xml:lang="en-US">Create Warning Banners for All FTP Users</title>
<description xml:lang="en-US">Edit the vsftpd configuration file, which resides at <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/vsftpd/vsftpd.conf</xhtml:code>
by default. Add or correct the following configuration options:
<pre xmlns="http://www.w3.org/1999/xhtml">banner_file=/etc/issue</pre>
</description>
<reference href="http://iase.disa.mil/stigs/cci/Pages/index.aspx">48</reference>
<rationale xml:lang="en-US">This setting will cause the system greeting banner to be used for FTP connections as well.</rationale>
<check system="http://oval.mitre.org/XMLSchema/oval-definitions-5">
<check-content-ref name="oval:ssg:def:292" href="ssg-fedora-oval.xml"/>
</check>
<check system="ocil-transitional">
<check-export export-name="it does not" value-id="xccdf_org.ssgproject.content_value_conditional_clause"/>
<check-content>
If FTP services are not installed, this is not applicable.
<br xmlns="http://www.w3.org/1999/xhtml"/><br xmlns="http://www.w3.org/1999/xhtml"/>
To verify this configuration, run the following command:
<pre xmlns="http://www.w3.org/1999/xhtml">grep "banner_file" /etc/vsftpd/vsftpd.conf</pre>
The output should show the value of <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">banner_file</xhtml:code> is set to <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/issue</xhtml:code>, an example of which is shown below:
<pre xmlns="http://www.w3.org/1999/xhtml"># grep "banner_file" /etc/vsftpd/vsftpd.conf
banner_file=/etc/issue</pre>
</check-content>
</check>
</Rule>
<Group id="xccdf_org.ssgproject.content_group_ftp_restrict_users">
<title xml:lang="en-US">Restrict the Set of Users Allowed to Access FTP</title>
<description xml:lang="en-US">This section describes how to disable non-anonymous (password-based) FTP logins, or, if it is not possible to
do this entirely due to legacy applications, how to restrict insecure FTP login to only those users who have an
identified need for this access.</description>
<Rule id="xccdf_org.ssgproject.content_rule_ftp_restrict_to_anon" selected="false" severity="low">
<title xml:lang="en-US">Restrict Access to Anonymous Users if Possible</title>
<description xml:lang="en-US">Is there a mission-critical reason for users to transfer files to/from their own accounts using FTP, rather than
using a secure protocol like SCP/SFTP? If not, edit the vsftpd configuration file. Add or correct the following configuration option:
<pre xmlns="http://www.w3.org/1999/xhtml">local_enable=NO</pre>
If non-anonymous FTP logins are necessary, follow the guidance in the remainder of this section to secure
these logins as much as possible.</description>
<rationale xml:lang="en-US">The use of non-anonymous FTP logins is strongly discouraged. Since SSH clients and servers are widely available, and since SSH provides support for a transfer mode which resembles FTP in user interface, there is no good reason to allow password-based FTP access. </rationale>
</Rule>
<Group id="xccdf_org.ssgproject.content_group_ftp_limit_users">
<title xml:lang="en-US">Limit Users Allowed FTP Access if Necessary</title>
<description xml:lang="en-US">If there is a mission-critical reason for users to access their accounts via the insecure FTP protocol, limit the set of users who are allowed this access. Edit the vsftpd configuration file. Add or correct the following configuration options:
<pre xmlns="http://www.w3.org/1999/xhtml">userlist_enable=YES
userlist_file=/etc/vsftp.ftpusers
userlist_deny=NO</pre>
Edit the file <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/vsftp.ftpusers</xhtml:code>. For each user USERNAME who should be allowed to access the system via FTP, add a line containing that user's name:
<pre xmlns="http://www.w3.org/1999/xhtml">USERNAME</pre>
If anonymous access is also required, add the anonymous usernames to <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/vsftp.ftpusers</xhtml:code> as well.
<pre xmlns="http://www.w3.org/1999/xhtml">anonymous
ftp</pre>
</description>
<rationale xml:lang="en-US">Historically, the file <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/ftpusers</xhtml:code> contained a list of users who were not allowed to access the system via FTP. It was used to prevent system users such as the root user from logging in via the insecure FTP protocol. However, when the configuration option <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">userlist deny=NO</xhtml:code> is set, vsftpd interprets ftpusers as the set of users who are allowed to login via FTP. Since it should be possible for most users to access their accounts via secure protocols, it is recommended that this setting be used, so that non-anonymous FTP access can be limited to legacy users who have been explicitly identified.</rationale>
</Group>
</Group>
<Rule id="xccdf_org.ssgproject.content_rule_ftp_disable_uploads" selected="false" severity="low">
<title xml:lang="en-US">Disable FTP Uploads if Possible</title>
<description xml:lang="en-US">Is there a mission-critical reason for users to upload files via FTP? If not,
edit the vsftpd configuration file to add or correct the following configuration options:
<pre xmlns="http://www.w3.org/1999/xhtml">write_enable=NO</pre>
If FTP uploads are necessary, follow the guidance in the remainder of this section to secure these transactions
as much as possible.</description>
<rationale xml:lang="en-US">Anonymous FTP can be a convenient way to make files available for universal download. However, it is less
common to have a need to allow unauthenticated users to place files on the FTP server. If this must be done, it
is necessary to ensure that files cannot be uploaded and downloaded from the same directory.
</rationale>
</Rule>
<Rule id="xccdf_org.ssgproject.content_rule_ftp_home_partition" selected="false" severity="low">
<title xml:lang="en-US">Place the FTP Home Directory on its Own Partition</title>
<description xml:lang="en-US">By default, the anonymous FTP root is the home directory of the FTP user account. The df command can
be used to verify that this directory is on its own partition.</description>
<rationale xml:lang="en-US">If there is a mission-critical reason for anonymous users to upload files, precautions must be taken to prevent
these users from filling a disk used by other services.</rationale>
</Rule>
<Group id="xccdf_org.ssgproject.content_group_ftp_configure_firewall">
<title xml:lang="en-US">Configure Firewalls to Protect the FTP Server</title>
<description xml:lang="en-US">By default, <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">iptables</xhtml:code>
blocks access to the ports used by the web server.
To configure <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">iptables</xhtml:code> to allow port
21 traffic one must edit
<xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/sysconfig/iptables</xhtml:code> and
<xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/sysconfig/ip6tables</xhtml:code> (if IPv6 is in use).
Add the following line, ensuring that it appears before the final LOG
and DROP lines for the INPUT chain:
<xhtml:pre xmlns:xhtml="http://www.w3.org/1999/xhtml" xml:space="preserve">-A INPUT -m state --state NEW -p tcp --dport 21 -j ACCEPT</xhtml:pre>
Edit the file <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/sysconfig/iptables-config</xhtml:code>. Ensure that the space-separated list of modules contains
the FTP connection tracking module:
<pre xmlns="http://www.w3.org/1999/xhtml">IPTABLES_MODULES="ip_conntrack_ftp"</pre></description>
<rationale xml:lang="en-US">These settings configure iptables to allow connections to an FTP server. The first line allows initial connections
to the FTP server port.
FTP is an older protocol which is not very compatible with firewalls. During the initial FTP dialogue, the client
and server negotiate an arbitrary port to be used for data transfer. The <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">ip_conntrack_ftp</xhtml:code> module is used by
iptables to listen to that dialogue and allow connections to the data ports which FTP negotiates. This allows an
FTP server to operate on a machine which is running a firewall.</rationale>
</Group>
</Group>
</Group>
<Group id="xccdf_org.ssgproject.content_group_snmp">
<title xml:lang="en-US">SNMP Server</title>
<description xml:lang="en-US">The Simple Network Management Protocol allows
administrators to monitor the state of network devices, including
computers. Older versions of SNMP were well-known for weak
security, such as plaintext transmission of the community string
(used for authentication) and usage of easily-guessable
choices for the community string.</description>
<Group id="xccdf_org.ssgproject.content_group_disabling_snmp_service">
<title xml:lang="en-US">Disable SNMP Server if Possible</title>
<description xml:lang="en-US">The system includes an SNMP daemon that allows for its remote
monitoring, though it not installed by default. If it was installed and
activated but is not needed, the software should be disabled and removed.
</description>
<Rule id="xccdf_org.ssgproject.content_rule_disable_snmpd" selected="false" severity="low">
<title xml:lang="en-US">Disable snmpd Service</title>
<description xml:lang="en-US">
The <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">snmpd</xhtml:code> service can be disabled with the following command:
<xhtml:pre xmlns:xhtml="http://www.w3.org/1999/xhtml"># systemctl disable snmpd.service</xhtml:pre>
</description>
<rationale xml:lang="en-US">
Running SNMP software provides a network-based avenue of attack, and
should be disabled if not needed.
</rationale>
<check system="ocil-transitional">
<check-export export-name="the service is running" value-id="xccdf_org.ssgproject.content_value_conditional_clause"/>
<check-content>
To check that the <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">snmpd</xhtml:code> service is disabled in system boot configuration, run the following command:
<xhtml:pre xmlns:xhtml="http://www.w3.org/1999/xhtml"># chkconfig <xhtml:code>snmpd</xhtml:code> --list</xhtml:pre>
Output should indicate the <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">snmpd</xhtml:code> service has either not been installed,
or has been disabled at all runlevels, as shown in the example below:
<xhtml:pre xmlns:xhtml="http://www.w3.org/1999/xhtml"># chkconfig <xhtml:code>snmpd</xhtml:code> --list
<xhtml:code>snmpd</xhtml:code> 0:off 1:off 2:off 3:off 4:off 5:off 6:off</xhtml:pre>
Run the following command to verify <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">snmpd</xhtml:code> is disabled through current runtime configuration:
<xhtml:pre xmlns:xhtml="http://www.w3.org/1999/xhtml"># service snmpd status</xhtml:pre>
If the service is disabled the command will return the following output:
<xhtml:pre xmlns:xhtml="http://www.w3.org/1999/xhtml">snmpd is stopped</xhtml:pre>
</check-content>
</check>
</Rule>
<Rule id="xccdf_org.ssgproject.content_rule_package_net-snmp_removed" selected="false" severity="low">
<title xml:lang="en-US">Uninstall net-snmp Package</title>
<description xml:lang="en-US">The <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">net-snmp</xhtml:code> package provides the snmpd service.
The <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">net-snmp</xhtml:code> package can be removed with the following command:
<xhtml:pre xmlns:xhtml="http://www.w3.org/1999/xhtml"># yum erase net-snmp</xhtml:pre>
</description>
<rationale xml:lang="en-US">
If there is no need to run SNMP server software,
removing the package provides a safeguard against its
activation.
</rationale>
<fix system="urn:xccdf:fix:script:sh">if rpm -qa | grep -q net-snmp; then
yum -y remove net-snmp
fi
</fix>
<check system="http://oval.mitre.org/XMLSchema/oval-definitions-5">
<check-content-ref name="oval:ssg:def:165" href="ssg-fedora-oval.xml"/>
</check>
<check system="ocil-transitional">
<check-export export-name="the package is installed" value-id="xccdf_org.ssgproject.content_value_conditional_clause"/>
<check-content>
Run the following command to determine if the <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">net-snmp</xhtml:code> package is installed:
<xhtml:pre xmlns:xhtml="http://www.w3.org/1999/xhtml"># rpm -q net-snmp</xhtml:pre>
</check-content>
</check>
</Rule>
</Group>
<Group id="xccdf_org.ssgproject.content_group_snmp_configure_server">
<title xml:lang="en-US">Configure SNMP Server if Necessary</title>
<description xml:lang="en-US">If it is necessary to run the snmpd agent on the system, some best
practices should be followed to minimize the security risk from the
installation. The multiple security models implemented by SNMP cannot be fully
covered here so only the following general configuration advice can be offered:
<ul xmlns="http://www.w3.org/1999/xhtml"><li>use only SNMP version 3 security models and enable the use of authentication and encryption</li><li>write access to the MIB (Management Information Base) should be allowed only if necessary</li><li>all access to the MIB should be restricted following a principle of least privilege</li><li>network access should be limited to the maximum extent possible including restricting to expected network
addresses both in the configuration files and in the system firewall rules</li><li>ensure SNMP agents send traps only to, and accept SNMP queries only from, authorized management
stations</li><li>ensure that permissions on the <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">snmpd.conf</xhtml:code> configuration file (by default, in <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/snmp</xhtml:code>) are 640 or more restrictive</li><li>ensure that any MIB files' permissions are also 640 or more restrictive</li></ul>
</description>
<Rule id="xccdf_org.ssgproject.content_rule_snmpd_use_newer_protocol" selected="false" severity="medium">
<title xml:lang="en-US">Configure SNMP Service to Use Only SNMPv3 or Newer </title>
<description xml:lang="en-US">
Edit <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/snmp/snmpd.conf</xhtml:code>, removing any references to <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">rocommunity</xhtml:code>, <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">rwcommunity</xhtml:code>, or <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">com2sec</xhtml:code>.
Upon doing that, restart the SNMP service:
<pre xmlns="http://www.w3.org/1999/xhtml"># service snmpd restart</pre>
</description>
<rationale xml:lang="en-US">
Earlier versions of SNMP are considered insecure, as they potentially allow
unauthorized access to detailed system management information.
</rationale>
<check system="http://oval.mitre.org/XMLSchema/oval-definitions-5">
<check-content-ref name="oval:ssg:def:164" href="ssg-fedora-oval.xml"/>
</check>
<check system="ocil-transitional">
<check-export export-name="there is output" value-id="xccdf_org.ssgproject.content_value_conditional_clause"/>
<check-content>
To ensure only SNMPv3 or newer is used, run the following command:
<pre xmlns="http://www.w3.org/1999/xhtml"># grep 'rocommunity\|rwcommunity\|com2sec' /etc/snmp/snmpd.conf | grep -v "^#"</pre>
There should be no output.
</check-content>
</check>
</Rule>
<Rule id="xccdf_org.ssgproject.content_rule_snmpd_not_default_password" selected="false" severity="medium">
<title xml:lang="en-US">Ensure Default Password Is Not Used</title>
<description xml:lang="en-US">
Edit <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/snmp/snmpd.conf</xhtml:code>, remove default community string <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">public</xhtml:code>.
Upon doing that, restart the SNMP service:
<pre xmlns="http://www.w3.org/1999/xhtml"># service snmpd restart</pre>
</description>
<rationale xml:lang="en-US">
Presence of the default SNMP password enables querying of different system
aspects and could result in unauthorized knowledge of the system.
</rationale>
<check system="http://oval.mitre.org/XMLSchema/oval-definitions-5">
<check-content-ref name="oval:ssg:def:212" href="ssg-fedora-oval.xml"/>
</check>
<check system="ocil-transitional">
<check-export export-name="there is output" value-id="xccdf_org.ssgproject.content_value_conditional_clause"/>
<check-content>
To ensure the default password is not set, run the following command:
<pre xmlns="http://www.w3.org/1999/xhtml"># grep -v "^#" /etc/snmp/snmpd.conf| grep public</pre>
There should be no output.
</check-content>
</check>
</Rule>
</Group>
</Group>
<Group id="xccdf_org.ssgproject.content_group_nfs_and_rpc">
<title xml:lang="en-US">NFS and RPC</title>
<description xml:lang="en-US">The Network File System is a popular distributed filesystem for
the Unix environment, and is very widely deployed. This section discusses the
circumstances under which it is possible to disable NFS and its dependencies,
and then details steps which should be taken to secure
NFS's configuration. This section is relevant to machines operating as NFS
clients, as well as to those operating as NFS servers.
</description>
<Group id="xccdf_org.ssgproject.content_group_disabling_nfs">
<title xml:lang="en-US">Disable All NFS Services if Possible</title>
<description xml:lang="en-US">If there is not a reason for the system to operate as either an
NFS client or an NFS server, follow all instructions in this section to disable
subsystems required by NFS.
</description>
<warning xml:lang="en-US" override="false" category="general">The steps in this section will prevent a machine
from operating as either an NFS client or an NFS server. Only perform these
steps on machines which do not need NFS at all.</warning>
<Group id="xccdf_org.ssgproject.content_group_disabling_nfs_services">
<title xml:lang="en-US">Disable Services Used Only by NFS</title>
<description xml:lang="en-US">If NFS is not needed, disable the NFS client daemons nfslock, rpcgssd, and rpcidmapd.
<br xmlns="http://www.w3.org/1999/xhtml"/><br xmlns="http://www.w3.org/1999/xhtml"/>
All of these daemons run with elevated privileges, and many listen for network
connections. If they are not needed, they should be disabled to improve system
security posture.</description>
<Rule id="xccdf_org.ssgproject.content_rule_service_nfslock_disabled" selected="false" severity="low">
<title xml:lang="en-US">Disable Network File System Lock Service (nfslock)</title>
<description xml:lang="en-US">The Network File System Lock (nfslock) service starts the required
remote procedure call (RPC) processes which allow clients to lock files on the
server. If the local machine is not configured to mount NFS filesystems then
this service should be disabled.
The <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">nfslock</xhtml:code> service can be disabled with the following command:
<xhtml:pre xmlns:xhtml="http://www.w3.org/1999/xhtml"># systemctl disable nfslock.service</xhtml:pre>
</description>
</Rule>
<Rule id="xccdf_org.ssgproject.content_rule_service_rpcgssd_disabled" selected="false" severity="low">
<title xml:lang="en-US">Disable Secure RPC Client Service (rpcgssd)</title>
<description xml:lang="en-US">
The rpcgssd service manages RPCSEC GSS contexts required to secure protocols
that use RPC (most often Kerberos and NFS). The rpcgssd service is the
client-side of RPCSEC GSS. If the system does not require secure RPC then this
service should be disabled.
The <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">rpcgssd</xhtml:code> service can be disabled with the following command:
<xhtml:pre xmlns:xhtml="http://www.w3.org/1999/xhtml"># systemctl disable rpcgssd.service</xhtml:pre>
</description>
</Rule>
<Rule id="xccdf_org.ssgproject.content_rule_service_rpcidmapd_disabled" selected="false" severity="low">
<title xml:lang="en-US">Disable RPC ID Mapping Service (rpcidmapd)</title>
<description xml:lang="en-US">The rpcidmapd service is used to map user names and groups to UID
and GID numbers on NFSv4 mounts. If NFS is not in use on the local system then
this service should be disabled.
The <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">rpcidmapd</xhtml:code> service can be disabled with the following command:
<xhtml:pre xmlns:xhtml="http://www.w3.org/1999/xhtml"># systemctl disable rpcidmapd.service</xhtml:pre>
</description>
</Rule>
</Group>
<Group id="xccdf_org.ssgproject.content_group_disabling_netfs">
<title xml:lang="en-US">Disable netfs if Possible</title>
<description xml:lang="en-US">To determine if any network filesystems handled by netfs are
currently mounted on the system execute the following command:
<pre xmlns="http://www.w3.org/1999/xhtml"># mount -t nfs,nfs4,smbfs,cifs,ncpfs</pre>
If the command did not return any output then disable netfs.
</description>
<Rule id="xccdf_org.ssgproject.content_rule_service_netfs_disabled" selected="false" severity="low">
<title xml:lang="en-US">Disable Network File Systems (netfs)</title>
<description xml:lang="en-US">The netfs script manages the boot-time mounting of several types
of networked filesystems, of which NFS and Samba are the most common. If these
filesystem types are not in use, the script can be disabled, protecting the
system somewhat against accidental or malicious changes to <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/fstab</xhtml:code>
and against flaws in the netfs script itself.
The <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">netfs</xhtml:code> service can be disabled with the following command:
<xhtml:pre xmlns:xhtml="http://www.w3.org/1999/xhtml"># systemctl disable netfs.service</xhtml:pre>
</description>
</Rule>
</Group>
</Group>
<Group id="xccdf_org.ssgproject.content_group_nfs_configuring_all_machines">
<title xml:lang="en-US">Configure All Machines which Use NFS</title>
<description xml:lang="en-US">The steps in this section are appropriate for all machines which
run NFS, whether they operate as clients or as servers.</description>
<Group id="xccdf_org.ssgproject.content_group_nfs_client_or_server_not_both">
<title xml:lang="en-US">Make Each Machine a Client or a Server, not Both</title>
<description xml:lang="en-US">If NFS must be used, it should be deployed in the simplest
configuration possible to avoid maintainability problems which may lead to
unnecessary security exposure. Due to the reliability and security problems
caused by NFS (specially NFSv3 and NFSv2), it is not a good idea for machines
which act as NFS servers to also mount filesystems via NFS. At the least,
crossed mounts (the situation in which each of two servers mounts a filesystem
from the other) should never be used.
</description>
</Group>
<Group id="xccdf_org.ssgproject.content_group_nfs_configure_fixed_ports">
<title xml:lang="en-US">Configure NFS Services to Use Fixed Ports (NFSv3 and NFSv2)</title>
<description xml:lang="en-US">Firewalling should be done at each host and at the border
firewalls to protect the NFS daemons from remote access, since NFS servers
should never be accessible from outside the organization. However, by default
for NFSv3 and NFSv2, the RPC Bind service assigns each NFS service to a port
dynamically at service startup time. Dynamic ports cannot be protected by port
filtering firewalls such as iptables.
<br xmlns="http://www.w3.org/1999/xhtml"/><br xmlns="http://www.w3.org/1999/xhtml"/>
Therefore, restrict each service to always use a given port, so that
firewalling can be done effectively. Note that, because of the way RPC is
implemented, it is not possible to disable the RPC Bind service even if ports
are assigned statically to all RPC services.
<br xmlns="http://www.w3.org/1999/xhtml"/><br xmlns="http://www.w3.org/1999/xhtml"/>
In NFSv4, the mounting and locking protocols have been incorporated into the
protocol, and the server listens on the the well-known TCP port 2049. As such,
NFSv4 does not need to interact with the <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">rpcbind, lockd, and rpc.statd</xhtml:code>
daemons, which can and should be disabled in a pure NFSv4 environment. The
<xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">rpc.mountd</xhtml:code> daemon is still required on the NFS server to setup
exports, but is not involved in any over-the-wire operations.
</description>
<Rule id="xccdf_org.ssgproject.content_rule_nfs_fixed_lockd_tcp_port" selected="false" severity="low">
<title xml:lang="en-US">Configure lockd to use static TCP port</title>
<description xml:lang="en-US">Configure the <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">lockd</xhtml:code> daemon to use a static TCP port as
opposed to letting the RPC Bind service dynamically assign a port. Edit the
file <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/sysconfig/nfs</xhtml:code>. Add or correct the following line:
<pre xmlns="http://www.w3.org/1999/xhtml">LOCKD_TCPPORT=lockd-port</pre>
Where <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">lockd-port</xhtml:code> is a port which is not used by any other service on
your network.
</description>
<rationale xml:lang="en-US">
Restrict service to always use a given port, so that firewalling can be done
effectively.
</rationale>
</Rule>
<Rule id="xccdf_org.ssgproject.content_rule_nfs_fixed_lockd_udp_port" selected="false" severity="low">
<title xml:lang="en-US">Configure lockd to use static UDP port</title>
<description xml:lang="en-US">Configure the <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">lockd</xhtml:code> daemon to use a static UDP port as
opposed to letting the RPC Bind service dynamically assign a port. Edit the
file <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/sysconfig/nfs</xhtml:code>. Add or correct the following line:
<pre xmlns="http://www.w3.org/1999/xhtml">LOCKD_UDPPORT=lockd-port</pre>
Where <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">lockd-port</xhtml:code> is a port which is not used by any other service on
your network.
</description>
<rationale xml:lang="en-US"> Restricting services to always use a given port enables firewalling
to be done more effectively.
</rationale>
</Rule>
<Rule id="xccdf_org.ssgproject.content_rule_nfs_fixed_statd_port" selected="false" severity="low">
<title xml:lang="en-US">Configure statd to use static port</title>
<description xml:lang="en-US">Configure the <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">statd</xhtml:code> daemon to use a static port as
opposed to letting the RPC Bind service dynamically assign a port. Edit the
file <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/sysconfig/nfs</xhtml:code>. Add or correct the following line:
<pre xmlns="http://www.w3.org/1999/xhtml">STATD_PORT=statd-port</pre>
Where <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">statd-port</xhtml:code> is a port which is not used by any other service on your network.
</description>
<rationale xml:lang="en-US"> Restricting services to always use a given port enables firewalling
to be done more effectively.
</rationale>
</Rule>
<Rule id="xccdf_org.ssgproject.content_rule_nfs_fixed_mountd_port" selected="false" severity="low">
<title xml:lang="en-US">Configure mountd to use static port</title>
<description xml:lang="en-US">Configure the <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">mountd</xhtml:code> daemon to use a static port as
opposed to letting the RPC Bind service dynamically assign a port. Edit the
file <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/sysconfig/nfs</xhtml:code>. Add or correct the following line:
<pre xmlns="http://www.w3.org/1999/xhtml">MOUNTD_PORT=statd-port</pre>
Where <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">mountd-port</xhtml:code> is a port which is not used by any other service on your network.
</description>
<rationale xml:lang="en-US"> Restricting services to always use a given port enables firewalling
to be done more effectively.
</rationale>
</Rule>
</Group>
</Group>
<Group id="xccdf_org.ssgproject.content_group_nfs_configuring_clients">
<title xml:lang="en-US">Configure NFS Clients</title>
<description xml:lang="en-US">The steps in this section are appropriate for machines which operate as NFS clients.</description>
<Group id="xccdf_org.ssgproject.content_group_disabling_nfsd">
<title xml:lang="en-US">Disable NFS Server Daemons</title>
<description xml:lang="en-US">
There is no need to run the NFS server daemons <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">nfs</xhtml:code> and
<xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">rpcsvcgssd</xhtml:code> except on a small number of properly secured machines
designated as NFS servers. Ensure that these daemons are turned off on
clients.</description>
<Rule id="xccdf_org.ssgproject.content_rule_nfs_no_anonymous" selected="false" severity="low">
<title xml:lang="en-US">Specify UID and GID for Anonymous NFS Connections</title>
<description xml:lang="en-US">To specify the UID and GID for remote root users, edit the <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/exports</xhtml:code> file and add the following for each export:
<pre xmlns="http://www.w3.org/1999/xhtml">
anonuid=-1
anongid=-1
</pre>
</description>
<rationale xml:lang="en-US">Specifying the anonymous UID and GID as -1 ensures that the remote root user is mapped to a local account which has no permissions on the system.</rationale>
</Rule>
<Rule id="xccdf_org.ssgproject.content_rule_service_nfs_disabled" selected="false" severity="low">
<title xml:lang="en-US">Disable Network File System (nfs)</title>
<description xml:lang="en-US">The Network File System (NFS) service allows remote hosts to mount
and interact with shared filesystems on the local machine. If the local machine
is not designated as a NFS server then this service should be disabled.
The <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">nfs</xhtml:code> service can be disabled with the following command:
<xhtml:pre xmlns:xhtml="http://www.w3.org/1999/xhtml"># systemctl disable nfs.service</xhtml:pre>
</description>
<rationale xml:lang="en-US">Unnecessary services should be disabled to decrease the attack surface of the system.</rationale>
<check system="ocil-transitional">
<check-export export-name="it does not" value-id="xccdf_org.ssgproject.content_value_conditional_clause"/>
<check-content>
It is prudent to ensure the <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">nfs</xhtml:code> service is disabled in system boot, as well as
not currently running. First, run the following to verify the service is stopped:
<pre xmlns="http://www.w3.org/1999/xhtml">$ service nfs status</pre>
If the service is stopped or disabled, it will return the following:
<pre xmlns="http://www.w3.org/1999/xhtml">rpc.svcgssd is stopped
rpc.mountd is stopped
nfsd is stopped
rpc.rquotad is stopped</pre>
To verify that the <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">nfs</xhtml:code> service is disabled, run the following command:
<pre xmlns="http://www.w3.org/1999/xhtml">$ chkconfig --list nfs</pre>
If properly configured, the output should look like:
<pre xmlns="http://www.w3.org/1999/xhtml">nfs 0:off 1:off 2:off 3:off 4:off 5:off 6:off</pre>
</check-content>
</check>
</Rule>
<Rule id="xccdf_org.ssgproject.content_rule_service_rpcsvcgssd_disabled" selected="false" severity="low">
<title xml:lang="en-US">Disable Secure RPC Server Service (rpcsvcgssd)</title>
<description xml:lang="en-US">The rpcsvcgssd service manages RPCSEC GSS contexts required to
secure protocols that use RPC (most often Kerberos and NFS). The rpcsvcgssd
service is the server-side of RPCSEC GSS. If the system does not require secure
RPC then this service should be disabled.
The <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">rpcsvcgssd</xhtml:code> service can be disabled with the following command:
<xhtml:pre xmlns:xhtml="http://www.w3.org/1999/xhtml"># systemctl disable rpcsvcgssd.service</xhtml:pre>
</description>
<rationale xml:lang="en-US">Unnecessary services should be disabled to decrease the attack surface of the system.</rationale>
<check system="ocil-transitional">
<check-export export-name="the service is running" value-id="xccdf_org.ssgproject.content_value_conditional_clause"/>
<check-content>
To check that the <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">rpcsvcgssd</xhtml:code> service is disabled in system boot configuration, run the following command:
<xhtml:pre xmlns:xhtml="http://www.w3.org/1999/xhtml"># chkconfig <xhtml:code>rpcsvcgssd</xhtml:code> --list</xhtml:pre>
Output should indicate the <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">rpcsvcgssd</xhtml:code> service has either not been installed,
or has been disabled at all runlevels, as shown in the example below:
<xhtml:pre xmlns:xhtml="http://www.w3.org/1999/xhtml"># chkconfig <xhtml:code>rpcsvcgssd</xhtml:code> --list
<xhtml:code>rpcsvcgssd</xhtml:code> 0:off 1:off 2:off 3:off 4:off 5:off 6:off</xhtml:pre>
Run the following command to verify <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">rpcsvcgssd</xhtml:code> is disabled through current runtime configuration:
<xhtml:pre xmlns:xhtml="http://www.w3.org/1999/xhtml"># service rpcsvcgssd status</xhtml:pre>
If the service is disabled the command will return the following output:
<xhtml:pre xmlns:xhtml="http://www.w3.org/1999/xhtml">rpcsvcgssd is stopped</xhtml:pre>
</check-content>
</check>
</Rule>
</Group>
<Group id="xccdf_org.ssgproject.content_group_mounting_remote_filesystems">
<title xml:lang="en-US">Mount Remote Filesystems with Restrictive Options</title>
<description xml:lang="en-US">Edit the file <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/fstab</xhtml:code>. For each filesystem whose type
(column 3) is <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">nfs</xhtml:code> or <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">nfs4</xhtml:code>, add the text
<xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">,nodev,nosuid</xhtml:code> to the list of mount options in column 4. If
appropriate, also add <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">,noexec</xhtml:code>.
<br xmlns="http://www.w3.org/1999/xhtml"/><br xmlns="http://www.w3.org/1999/xhtml"/>
See the section titled "Restrict Partition Mount Options" for a description of
the effects of these options. In general, execution of files mounted via NFS
should be considered risky because of the possibility that an adversary could
intercept the request and substitute a malicious file. Allowing setuid files to
be executed from remote servers is particularly risky, both for this reason and
because it requires the clients to extend root-level trust to the NFS
server.</description>
<Rule id="xccdf_org.ssgproject.content_rule_use_nodev_option_on_nfs_mounts" selected="false" severity="medium">
<title xml:lang="en-US">Mount Remote Filesystems with nodev</title>
<description xml:lang="en-US">
Add the <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">nodev</xhtml:code> option to the fourth column of
<xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/fstab</xhtml:code> for the line which controls mounting of
any NFS mounts.
</description>
<rationale xml:lang="en-US">Legitimate device files should only exist in the /dev directory. NFS mounts
should not present device files to users.</rationale>
<check system="ocil-transitional">
<check-export export-name="the setting does not show" value-id="xccdf_org.ssgproject.content_value_conditional_clause"/>
<check-content>
To verify the <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">nodev</xhtml:code> option is configured for all NFS mounts, run the following command:
<pre xmlns="http://www.w3.org/1999/xhtml">$ mount | grep nfs</pre>
All NFS mounts should show the <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">nodev</xhtml:code> setting in parentheses. This is not applicable if NFS is
not implemented.
</check-content>
</check>
</Rule>
<Rule id="xccdf_org.ssgproject.content_rule_use_nosuid_option_on_nfs_mounts" selected="false" severity="medium">
<title xml:lang="en-US">Mount Remote Filesystems with nosuid</title>
<description xml:lang="en-US">
Add the <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">nosuid</xhtml:code> option to the fourth column of
<xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/fstab</xhtml:code> for the line which controls mounting of
any NFS mounts.
</description>
<rationale xml:lang="en-US">NFS mounts should not present suid binaries to users. Only vendor-supplied suid executables
should be installed to their default location on the local filesystem.</rationale>
<check system="ocil-transitional">
<check-export export-name="the setting does not show" value-id="xccdf_org.ssgproject.content_value_conditional_clause"/>
<check-content>
To verify the <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">nosuid</xhtml:code> option is configured for all NFS mounts, run the following command:
<pre xmlns="http://www.w3.org/1999/xhtml">$ mount | grep nfs</pre>
All NFS mounts should show the <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">nosuid</xhtml:code> setting in parentheses. This is not applicable if NFS is
not implemented.
</check-content>
</check>
</Rule>
</Group>
</Group>
<Group id="xccdf_org.ssgproject.content_group_nfs_configuring_servers">
<title xml:lang="en-US">Configure NFS Servers</title>
<description xml:lang="en-US">The steps in this section are appropriate for machines which operate as NFS servers.</description>
<Group id="xccdf_org.ssgproject.content_group_configure_exports_restrictively">
<title xml:lang="en-US">Configure the Exports File Restrictively</title>
<description xml:lang="en-US">Linux's NFS implementation uses the file <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/exports</xhtml:code> to control what filesystems
and directories may be accessed via NFS. (See the <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">exports(5)</xhtml:code> manpage for more information about the
format of this file.)
<br xmlns="http://www.w3.org/1999/xhtml"/><br xmlns="http://www.w3.org/1999/xhtml"/>
The syntax of the <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">exports</xhtml:code> file is not necessarily checked fully on reload, and syntax errors
can leave your NFS configuration more open than intended. Therefore, exercise caution when modifying
the file.
<br xmlns="http://www.w3.org/1999/xhtml"/><br xmlns="http://www.w3.org/1999/xhtml"/>
The syntax of each line in <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/exports</xhtml:code> is:
<pre xmlns="http://www.w3.org/1999/xhtml">/DIR host1(opt1,opt2) host2(opt3)</pre>
where <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/DIR</xhtml:code> is a directory or filesystem to export, <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">hostN</xhtml:code> is an IP address, netblock,
hostname, domain, or netgroup to which to export, and <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">optN</xhtml:code> is an option.
</description>
</Group>
<Group id="xccdf_org.ssgproject.content_group_use_acl_enforce_auth_restrictions">
<title xml:lang="en-US">Use Access Lists to Enforce Authorization Restrictions</title>
<description xml:lang="en-US">When configuring NFS exports, ensure that each export line in <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/exports</xhtml:code> contains
a list of hosts which are allowed to access that export. If no hosts are specified on an export line,
then that export is available to any remote host which requests it. All lines of the exports file should
specify the hosts (or subnets, if needed) which are allowed to access the exported directory, so that
unknown or remote hosts will be denied.
<br xmlns="http://www.w3.org/1999/xhtml"/><br xmlns="http://www.w3.org/1999/xhtml"/>
Authorized hosts can be specified in several different formats:
<ul xmlns="http://www.w3.org/1999/xhtml"><li>Name or alias that is recognized by the resolver</li><li>Fully qualified domain name</li><li>IP address</li><li>IP subnets in the format <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">address/netmask</xhtml:code> or <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">address/CIDR</xhtml:code></li></ul>
</description>
</Group>
<Group id="xccdf_org.ssgproject.content_group_export_filesystems_read_only">
<title xml:lang="en-US">Export Filesystems Read-Only if Possible</title>
<description xml:lang="en-US">If a filesystem is being exported so that users can view the files in a convenient
fashion, but there is no need for users to edit those files, exporting the filesystem read-only
removes an attack vector against the server. The default filesystem export mode is <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">ro</xhtml:code>,
so do not specify <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">rw</xhtml:code> without a good reason.
</description>
</Group>
<Rule id="xccdf_org.ssgproject.content_rule_use_root_squashing_all_exports" selected="false" severity="low">
<title xml:lang="en-US">Use Root-Squashing on All Exports</title>
<description xml:lang="en-US">If a filesystem is exported using root squashing, requests from root on the client
are considered to be unprivileged (mapped to a user such as nobody). This provides some mild
protection against remote abuse of an NFS server. Root squashing is enabled by default, and
should not be disabled.
<br xmlns="http://www.w3.org/1999/xhtml"/><br xmlns="http://www.w3.org/1999/xhtml"/>
Ensure that no line in <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/exports</xhtml:code> contains the option <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">no_root_squash</xhtml:code>.
</description>
<rationale xml:lang="en-US">If the NFS server allows root access to local file systems from remote hosts, this
access could be used to compromise the system.
</rationale>
</Rule>
<Rule id="xccdf_org.ssgproject.content_rule_restrict_nfs_clients_to_privileged_ports" selected="false" severity="low">
<title xml:lang="en-US">Restrict NFS Clients to Privileged Ports</title>
<description xml:lang="en-US">By default, the server NFS implementation requires that all client requests be made
from ports less than 1024. If your organization has control over machines connected to its
network, and if NFS requests are prohibited at the border firewall, this offers some protection
against malicious requests from unprivileged users. Therefore, the default should not be changed.
<br xmlns="http://www.w3.org/1999/xhtml"/><br xmlns="http://www.w3.org/1999/xhtml"/>
To ensure that the default has not been changed, ensure no line in
<xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/exports</xhtml:code> contains the option <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">insecure</xhtml:code>.
</description>
<rationale xml:lang="en-US">Allowing client requests to be made from ports higher than 1024 could allow a unprivileged
user to initiate an NFS connection. If the unprivileged user account has been compromised, an
attacker could gain access to data on the NFS server.</rationale>
</Rule>
<Rule id="xccdf_org.ssgproject.content_rule_no_insecure_locks_exports" selected="false" severity="medium">
<title xml:lang="en-US">Ensure Insecure File Locking is Not Allowed</title>
<description xml:lang="en-US">By default the NFS server requires secure file-lock requests,
which require credentials from the client in order to lock a file. Most NFS
clients send credentials with file lock requests, however, there are a few
clients that do not send credentials when requesting a file-lock, allowing the
client to only be able to lock world-readable files. To get around this, the
<xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">insecure_locks</xhtml:code> option can be used so these clients can access the
desired export. This poses a security risk by potentially allowing the client
access to data for which it does not have authorization.
Remove any instances of the
<xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">insecure_locks</xhtml:code> option from the file <xhtml:code xmlns:xhtml="http://www.w3.org/1999/xhtml">/etc/exports</xhtml:code>.
</description>
<reference href="http://iase.disa.mil/stigs/cci/Pages/index.aspx">764</reference>
<rationale xml:lang="en-US">Allowing insecure file locking could allow for sensitive data to be
viewed or edited by an unauthorized user.
</rationale>
<check system="http://oval.mitre.org/XMLSchema/oval-definitions-5">
<check-content-ref name="oval:ssg:def:210" href="ssg-fedora-oval.xml"/>
</check>
<check system="ocil-transitional">
<check-export export-name="there is output" value-id="xccdf_org.ssgproject.content_value_conditional_clause"/>
<check-content>
To verify insecure file locking has been disabled, run the following command:
<pre xmlns="http://www.w3.org/1999/xhtml"># grep insecure_locks /etc/exports</pre>
</check-content>
</check>
</Rule>
</Group>
</Group>
</Group>
</Benchmark>
</ds:component>
<ds:component id="scap_org.open-scap_comp_output--ssg-fedora-cpe-oval.xml" timestamp="2015-03-17T12:23:34">
<oval_definitions xmlns="http://oval.mitre.org/XMLSchema/oval-definitions-5" xmlns:oval="http://oval.mitre.org/XMLSchema/oval-common-5" xmlns:ind="http://oval.mitre.org/XMLSchema/oval-definitions-5#independent" xmlns:unix="http://oval.mitre.org/XMLSchema/oval-definitions-5#unix" xmlns:linux="http://oval.mitre.org/XMLSchema/oval-definitions-5#linux" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://oval.mitre.org/XMLSchema/oval-common-5 oval-common-schema.xsd http://oval.mitre.org/XMLSchema/oval-definitions-5 oval-definitions-schema.xsd http://oval.mitre.org/XMLSchema/oval-definitions-5#independent independent-definitions-schema.xsd http://oval.mitre.org/XMLSchema/oval-definitions-5#unix unix-definitions-schema.xsd http://oval.mitre.org/XMLSchema/oval-definitions-5#linux linux-definitions-schema.xsd">
<generator>
<oval:product_name>python</oval:product_name>
<oval:product_version>2.6.6</oval:product_version>
<oval:schema_version>5.10</oval:schema_version>
<oval:timestamp>2011-09-21T13:44:00</oval:timestamp>
</generator>
<definitions><definition class="inventory" id="oval:ssg:def:100" version="1">
<metadata>
<title>Fedora release 19 (Schrödinger's Cat)</title>
<affected family="unix">
<platform>Fedora 19</platform>
</affected>
<reference ref_id="cpe:/o:fedoraproject:fedora:19" source="CPE"/>
<description>The operating system installed on the system is
Fedora release 19 (Schrödinger's Cat)</description>
</metadata>
<criteria>
<criterion comment="Installed operating system is part of the unix family" test_ref="oval:ssg:tst:101"/>
<criterion comment="Fedora release 19 is installed" test_ref="oval:ssg:tst:102"/>
</criteria>
</definition>
<definition class="inventory" id="oval:ssg:def:103" version="1">
<metadata>
<title>Fedora release 20 (Schrödinger's Cat)</title>
<affected family="unix">
<platform>Fedora 20</platform>
</affected>
<reference ref_id="cpe:/o:fedoraproject:fedora:20" source="CPE"/>
<description>The operating system installed on the system is
Fedora release 20 (Schrödinger's Cat)</description>
</metadata>
<criteria>
<criterion comment="Installed operating system is part of the unix family" test_ref="oval:ssg:tst:101"/>
<criterion comment="Fedora release 20 is installed" test_ref="oval:ssg:tst:102"/>
</criteria>
</definition>
<definition class="inventory" id="oval:ssg:def:104" version="1">
<metadata>
<title>Red Hat Enterprise Linux 6</title>
<affected family="unix">
<platform>Red Hat Enterprise Linux 6</platform>
</affected>
<reference ref_id="cpe:/o:redhat:enterprise_linux:6" source="CPE"/>
<description>The operating system installed on the system is
Red Hat Enterprise Linux 6</description>
</metadata>
<criteria>
<criterion comment="Installed operating system is part of the unix family" test_ref="oval:ssg:tst:101"/>
<criteria operator="OR">
<criterion comment="Red Hat Enterprise Linux 6 Workstation is installed" test_ref="oval:ssg:tst:105"/>
<criterion comment="Red Hat Enterprise Linux 6 Server is installed" test_ref="oval:ssg:tst:106"/>
</criteria>
</criteria>
</definition>
<definition class="inventory" id="oval:ssg:def:107" version="1">
<metadata>
<title>Red Hat Enterprise Linux 7</title>
<affected family="unix">
<platform>Red Hat Enterprise Linux 7</platform>
</affected>
<reference ref_id="cpe:/o:redhat:enterprise_linux:7" source="CPE"/>
<description>The operating system installed on the system is
Red Hat Enterprise Linux 7</description>
</metadata>
<criteria>
<criterion comment="Installed operating system is part of the unix family" test_ref="oval:ssg:tst:108"/>
<criteria operator="OR">
<criterion comment="Red Hat Enterprise Linux 7 Workstation is installed" test_ref="oval:ssg:tst:109"/>
<criterion comment="Red Hat Enterprise Linux 7 Server is installed" test_ref="oval:ssg:tst:110"/>
</criteria>
</criteria>
</definition>
</definitions><tests><ind:family_test check="all" check_existence="at_least_one_exists" comment="installed OS part of unix family" id="oval:ssg:tst:101" version="1">
<ind:object object_ref="oval:ssg:obj:111"/>
<ind:state state_ref="oval:ssg:ste:112"/>
</ind:family_test>
<linux:rpminfo_test check="all" check_existence="only_one_exists" comment="fedora-release is version 19" id="oval:ssg:tst:102" version="1">
<linux:object object_ref="oval:ssg:obj:113"/>
<linux:state state_ref="oval:ssg:ste:114"/>
</linux:rpminfo_test>
<linux:rpminfo_test check="all" check_existence="at_least_one_exists" comment="redhat-release-workstation is version 6" id="oval:ssg:tst:105" version="1">
<linux:object object_ref="oval:ssg:obj:115"/>
<linux:state state_ref="oval:ssg:ste:116"/>
</linux:rpminfo_test>
<linux:rpminfo_test check="all" check_existence="at_least_one_exists" comment="redhat-release-server is version 6" id="oval:ssg:tst:106" version="1">
<linux:object object_ref="oval:ssg:obj:117"/>
<linux:state state_ref="oval:ssg:ste:118"/>
</linux:rpminfo_test>
<ind:family_test check="all" check_existence="at_least_one_exists" comment="installed OS part of unix family" id="oval:ssg:tst:108" version="1">
<ind:object object_ref="oval:ssg:obj:119"/>
<ind:state state_ref="oval:ssg:ste:120"/>
</ind:family_test>
<linux:rpminfo_test check="all" check_existence="at_least_one_exists" comment="redhat-release-workstation is version 7" id="oval:ssg:tst:109" version="1">
<linux:object object_ref="oval:ssg:obj:121"/>
<linux:state state_ref="oval:ssg:ste:122"/>
</linux:rpminfo_test>
<linux:rpminfo_test check="all" check_existence="at_least_one_exists" comment="redhat-release-server is version 7" id="oval:ssg:tst:110" version="1">
<linux:object object_ref="oval:ssg:obj:123"/>
<linux:state state_ref="oval:ssg:ste:124"/>
</linux:rpminfo_test>
</tests><objects><ind:family_object id="oval:ssg:obj:111" version="1"/>
<linux:rpminfo_object id="oval:ssg:obj:113" version="1">
<linux:name>fedora-release</linux:name>
</linux:rpminfo_object>
<linux:rpminfo_object id="oval:ssg:obj:115" version="1">
<linux:name>redhat-release-workstation</linux:name>
</linux:rpminfo_object>
<linux:rpminfo_object id="oval:ssg:obj:117" version="1">
<linux:name>redhat-release-server</linux:name>
</linux:rpminfo_object>
<ind:family_object id="oval:ssg:obj:119" version="1"/>
<linux:rpminfo_object id="oval:ssg:obj:121" version="1">
<linux:name>redhat-release-workstation</linux:name>
</linux:rpminfo_object>
<linux:rpminfo_object id="oval:ssg:obj:123" version="1">
<linux:name>redhat-release-server</linux:name>
</linux:rpminfo_object>
</objects><states><ind:family_state id="oval:ssg:ste:112" version="1">
<ind:family>unix</ind:family>
</ind:family_state>
<linux:rpminfo_state id="oval:ssg:ste:114" version="1">
<linux:version operation="pattern match">^19$</linux:version>
</linux:rpminfo_state>
<linux:rpminfo_state id="oval:ssg:ste:116" version="1">
<linux:version operation="pattern match">^6.*$</linux:version>
</linux:rpminfo_state>
<linux:rpminfo_state id="oval:ssg:ste:118" version="1">
<linux:version operation="pattern match">^6.*$</linux:version>
</linux:rpminfo_state>
<ind:family_state id="oval:ssg:ste:120" version="1">
<ind:family>unix</ind:family>
</ind:family_state>
<linux:rpminfo_state id="oval:ssg:ste:122" version="1">
<linux:version operation="pattern match">^7.*$</linux:version>
</linux:rpminfo_state>
<linux:rpminfo_state id="oval:ssg:ste:124" version="1">
<linux:version operation="pattern match">^7.*$</linux:version>
</linux:rpminfo_state>
</states></oval_definitions>
</ds:component>
<ds:component id="scap_org.open-scap_comp_output--ssg-fedora-cpe-dictionary.xml" timestamp="2015-03-17T12:23:34">
<cpe-list xmlns="http://cpe.mitre.org/dictionary/2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://cpe.mitre.org/dictionary/2.0 http://cpe.mitre.org/files/cpe-dictionary_2.1.xsd">
<cpe-item name="cpe:/o:fedoraproject:fedora:19">
<title xml:lang="en-us">Fedora release 19 (Schrödinger's Cat)</title>
<!-- the check references an OVAL file that contains an inventory definition -->
<check system="http://oval.mitre.org/XMLSchema/oval-definitions-5" href="ssg-fedora-cpe-oval.xml">oval:ssg:def:100</check>
</cpe-item>
</cpe-list>
</ds:component>
<ds:component id="scap_org.open-scap_comp_output--ssg-fedora-oval.xml" timestamp="2015-03-17T12:23:34"><oval_definitions xmlns="http://oval.mitre.org/XMLSchema/oval-definitions-5" xmlns:oval="http://oval.mitre.org/XMLSchema/oval-common-5" xmlns:ind="http://oval.mitre.org/XMLSchema/oval-definitions-5#independent" xmlns:unix="http://oval.mitre.org/XMLSchema/oval-definitions-5#unix" xmlns:linux="http://oval.mitre.org/XMLSchema/oval-definitions-5#linux" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://oval.mitre.org/XMLSchema/oval-common-5 oval-common-schema.xsd http://oval.mitre.org/XMLSchema/oval-definitions-5 oval-definitions-schema.xsd http://oval.mitre.org/XMLSchema/oval-definitions-5#independent independent-definitions-schema.xsd http://oval.mitre.org/XMLSchema/oval-definitions-5#unix unix-definitions-schema.xsd http://oval.mitre.org/XMLSchema/oval-definitions-5#linux linux-definitions-schema.xsd">
<generator>
<oval:product_name>python</oval:product_name>
<oval:product_version>2.6.6</oval:product_version>
<oval:schema_version>5.10</oval:schema_version>
<oval:timestamp>2011-09-21T13:44:00</oval:timestamp>
</generator>
<definitions>
<definition class="compliance" id="oval:ssg:def:125" version="1">
<metadata>
<title>Specify a Remote NTP Server for Time Data</title>
<affected family="unix">
<platform>Red Hat Enterprise Linux 6</platform>
<platform>Red Hat Enterprise Linux 7</platform>
<platform>Fedora 20</platform>
</affected>
<description>Multiple NTP Servers for time synchronization should be
specified</description>
<reference source="galford" ref_id="20141107" ref_url="test_attestation"/>
<reference ref_id="ntpd_specify_multiple_servers" source="ssg"/></metadata>
<criteria comment="ntp.conf conditions are met">
<criterion test_ref="oval:ssg:tst:126"/>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:127" version="1">
<metadata>
<title>No nullok Option in /etc/pam.d/system-auth</title>
<affected family="unix">
<platform>Red Hat Enterprise Linux 6</platform>
<platform>Red Hat Enterprise Linux 7</platform>
<platform>Fedora 20</platform>
</affected>
<description>The file /etc/pam.d/system-auth should not contain the nullok option</description>
<reference source="swells" ref_id="20130918" ref_url="test_attestation"/>
<reference ref_id="no_empty_passwords" source="ssg"/></metadata>
<criteria>
<criterion comment="make sure the nullok option is not used in /etc/pam.d/system-auth" test_ref="oval:ssg:tst:128"/>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:129" version="1">
<metadata>
<title>Set Password minclass Requirements</title>
<affected family="unix">
<platform>Red Hat Enterprise Linux 7</platform>
<platform>Fedora 20</platform>
</affected>
<description>The password minclass should meet the minimum requirements</description>
<reference source="galford" ref_id="20141010" ref_url="test_attestation"/>
<reference ref_id="accounts_password_pam_minclass" source="ssg"/></metadata>
<criteria operator="AND" comment="conditions for minclass are satisfied">
<extend_definition comment="pwquality.so exists in system-auth" definition_ref="oval:ssg:def:130"/>
<criterion comment="pwquality.conf" test_ref="oval:ssg:tst:131"/>
</criteria>
</definition>
<definition class="inventory" id="oval:ssg:def:100" version="1">
<metadata>
<title>Fedora release 19 (Schrödinger's Cat)</title>
<affected family="unix">
<platform>Fedora 19</platform>
</affected>
<reference ref_id="cpe:/o:fedoraproject:fedora:19" source="CPE"/>
<description>The operating system installed on the system is
Fedora release 19 (Schrödinger's Cat)</description>
<reference ref_id="installed_OS_is_fedora19" source="ssg"/></metadata>
<criteria>
<criterion comment="Installed operating system is part of the unix family" test_ref="oval:ssg:tst:101"/>
<criterion comment="Fedora release 19 is installed" test_ref="oval:ssg:tst:102"/>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:132" version="1">
<metadata>
<title>Package openssh-server Removed</title>
<affected family="unix">
<platform>Fedora 19</platform>
<platform>Red Hat Enterprise Linux 6</platform>
<platform>Red Hat Enterprise Linux 7</platform>
</affected>
<description>The RPM package openssh-server should be removed.</description>
<reference source="swells" ref_id="20130829" ref_url="test_attestation"/>
<reference ref_id="package_openssh-server_removed" source="ssg"/></metadata>
<criteria>
<criterion comment="package openssh-server is removed" test_ref="oval:ssg:tst:133"/>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:134" version="1">
<metadata>
<title>Package dconf Installed</title>
<affected family="unix">
<platform>Red Hat Enterprise Linux 7</platform>
<platform>Fedora 20</platform>
</affected>
<description>The RPM package dconf should be installed.</description>
<reference source="galford" ref_id="20140424" ref_url="test_attestation"/>
<reference ref_id="package_dconf_installed" source="ssg"/></metadata>
<criteria>
<criterion comment="package dconf is installed" test_ref="oval:ssg:tst:135"/>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:136" version="3">
<metadata>
<title>Set Password Expiration Parameters</title>
<affected family="unix">
<platform>Red Hat Enterprise Linux 6</platform>
<platform>Red Hat Enterprise Linux 7</platform>
<platform>Fedora 20</platform>
</affected>
<description>The maximum password age policy should meet minimum requirements.</description>
<reference source="JL" ref_id="RHEL6_20150130" ref_url="test_attestation"/>
<reference source="JL" ref_id="RHEL7_20150130" ref_url="test_attestation"/>
<reference source="JL" ref_id="FEDORA20_20150130" ref_url="test_attestation"/>
<reference ref_id="accounts_maximum_age_login_defs" source="ssg"/></metadata>
<criteria comment="The value PASS_MAX_DAYS should be set appropriately in /etc/login.defs">
<criterion test_ref="oval:ssg:tst:137"/>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:138" version="1">
<metadata>
<title>Verify that System Executables Have Root Ownership</title>
<affected family="unix">
<platform>Fedora 19</platform>
<platform>Red Hat Enterprise Linux 6</platform>
<platform>Red Hat Enterprise Linux 7</platform>
</affected>
<description>
Checks that /bin, /sbin, /usr/bin, /usr/sbin, /usr/local/bin,
/usr/local/sbin, and objects therein, are owned by root.
</description>
<reference ref_id="file_ownership_binary_dirs" source="ssg"/></metadata>
<criteria operator="AND">
<criterion test_ref="oval:ssg:tst:139"/>
<criterion test_ref="oval:ssg:tst:140"/>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:141" version="1">
<metadata>
<title>Set OpenSSH Idle Timeout Interval</title>
<affected family="unix">
<platform>Red Hat Enterprise Linux 6</platform>
<platform>Red Hat Enterprise Linux 7</platform>
<platform>Fedora 20</platform>
</affected>
<description>The SSH idle timeout interval should be set to an
appropriate value.</description>
<reference source="JL" ref_id="20140414" ref_url="test_attestation"/>
<!-- Fedora 20: <reference source="JL" ref_id="20140224" ref_url="test_attestation" /> -->
<reference ref_id="sshd_set_idle_timeout" source="ssg"/></metadata>
<criteria comment="SSH is not being used or conditions are met" operator="OR">
<extend_definition comment="sshd service is disabled" definition_ref="oval:ssg:def:142"/>
<criterion comment="Check ClientAliveInterval in /etc/ssh/sshd_config" test_ref="oval:ssg:tst:143"/>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:144" version="1">
<metadata>
<title>Enable GNOME3 Login Warning Banner</title>
<affected family="unix">
<platform>Red Hat Enterprise Linux 7</platform>
<platform>Fedora 20</platform>
</affected>
<description>Enable the GNOME3 Login warning banner.</description>
<reference source="galford" ref_id="20140823" ref_url="test_attestation"/>
<reference ref_id="dconf_gnome_banner_enabled" source="ssg"/></metadata>
<criteria operator="OR">
<extend_definition comment="dconf installed" definition_ref="oval:ssg:def:134" negate="true"/>
<criteria comment="Enable GUI banner and prevent user from changing it" operator="AND">
<extend_definition comment="dconf user profile exists" definition_ref="oval:ssg:def:145"/>
<criterion comment="Enable GUI banner" test_ref="oval:ssg:tst:146"/>
<criterion comment="Prevent user from disabling banner" test_ref="oval:ssg:tst:147"/>
</criteria>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:148" version="1">
<metadata>
<title>Verify that Shared Library Files Have Root Ownership</title>
<affected family="unix">
<platform>Fedora 19</platform>
<platform>Red Hat Enterprise Linux 6</platform>
<platform>Red Hat Enterprise Linux 7</platform>
</affected>
<description>
Checks that /lib, /lib64, /usr/lib, /usr/lib64, /lib/modules, and
objects therein, are owned by root.
</description>
<reference ref_id="file_ownership_library_dirs" source="ssg"/></metadata>
<criteria operator="AND">
<criterion test_ref="oval:ssg:tst:149"/>
<criterion test_ref="oval:ssg:tst:150"/>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:151" version="2">
<metadata>
<title>Disable Prelinking</title>
<affected family="unix">
<platform>Red Hat Enterprise Linux 6</platform>
<platform>Fedora 20</platform>
</affected>
<description>The prelinking feature can interfere with the operation of
checksum integrity tools (e.g. AIDE), mitigates the protection provided
by ASLR, and requires additional CPU cycles by software upgrades.
</description>
<reference source="JL" ref_id="20140313" ref_url="test_attestation"/>
<!-- Fedora 20: <reference source="JL" ref_id="20140313" ref_url="test_attestation" /> -->
<reference ref_id="disable_prelink" source="ssg"/></metadata>
<criteria>
<criterion comment="Ensure prelinking is disabled" test_ref="oval:ssg:tst:152"/>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:153" version="2">
<metadata>
<title>Set SHA512 Password Hashing Algorithm in /etc/login.defs</title>
<affected family="unix">
<platform>Red Hat Enterprise Linux 6</platform>
<platform>Red Hat Enterprise Linux 7</platform>
</affected>
<description>The password hashing algorithm should be set correctly in /etc/login.defs.</description>
<reference source="JL" ref_id="RHEL6_20150201" ref_url="test_attestation"/>
<reference source="JL" ref_id="RHEL7_20150201" ref_url="test_attestation"/>
<reference source="JL" ref_id="FEDORA20_20150201" ref_url="test_attestation"/>
<reference ref_id="set_password_hashing_algorithm_logindefs" source="ssg"/></metadata>
<criteria operator="AND">
<criterion test_ref="oval:ssg:tst:154"/>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:155" version="1">
<metadata>
<title>Proper Permissions User Home Directories</title>
<affected family="unix">
<platform>Red Hat Enterprise Linux 6</platform>
<platform>Red Hat Enterprise Linux 7</platform>
<platform>Fedora 20</platform>
</affected>
<description>File permissions should be set correctly for the home directories for all user accounts.</description>
<reference source="JL" ref_id="RHEL6_20141106" ref_url="test_attestation"/>
<reference source="JL" ref_id="RHEL7_20141106" ref_url="test_attestation"/>
<reference source="JL" ref_id="Fedora20_20141106" ref_url="test_attestation"/>
<reference ref_id="file_permissions_home_dirs" source="ssg"/></metadata>
<criteria>
<criterion comment="home directories" test_ref="oval:ssg:tst:156" negate="true"/>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:157" version="3">
<metadata>
<title>Lock out account after failed login attempts</title>
<affected family="unix">
<platform>Red Hat Enterprise Linux 6</platform>
<platform>Red Hat Enterprise Linux 7</platform>
<platform>Fedora 20</platform>
</affected>
<description>The number of allowed failed logins should be set correctly.</description>
<reference source="JL" ref_id="RHEL6_20150122" ref_url="test_attestation"/>
<reference source="JL" ref_id="RHEL7_20150122" ref_url="test_attestation"/>
<reference source="JL" ref_id="FEDORA20_20150122" ref_url="test_attestation"/>
<reference ref_id="accounts_passwords_pam_faillock_deny" source="ssg"/></metadata>
<criteria>
<criterion test_ref="oval:ssg:tst:158" comment="pam_faillock.so preauth silent set in system-auth"/>
<criterion test_ref="oval:ssg:tst:159" comment="pam_faillock.so authfail deny value set in system-auth"/>
<criterion test_ref="oval:ssg:tst:160" comment="pam_faillock.so set in account phase of system-auth"/>
<criterion test_ref="oval:ssg:tst:161" comment="pam_faillock.so preauth silent set in password-auth"/>
<criterion test_ref="oval:ssg:tst:162" comment="pam_faillock.so authfail deny value set in password-auth"/>
<criterion test_ref="oval:ssg:tst:163" comment="pam_faillock.so set in account phase of password-auth"/>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:164" version="2">
<metadata>
<title>SNMP use newer protocols</title>
<affected family="unix">
<platform>Red Hat Enterprise Linux 6</platform>
<platform>Red Hat Enterprise Linux 7</platform>
<platform>Fedora 20</platform>
</affected>
<description>SNMP version 1 and 2c must not be enabled.</description>
<reference source="galford" ref_id="20140813" ref_url="test_attestation"/>
<reference ref_id="snmpd_use_newer_protocol" source="ssg"/></metadata>
<criteria operator="OR">
<extend_definition comment="SMNP installed" definition_ref="oval:ssg:def:165"/>
<criterion comment="SNMP protocols" test_ref="oval:ssg:tst:166"/>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:167" version="1">
<metadata>
<title>Banner for FTP Users</title>
<affected family="unix">
<platform>Red Hat Enterprise Linux 6</platform>
<platform>Red Hat Enterprise Linux 7</platform>
<platform>Fedora 20</platform>
</affected>
<description>To trace malicious activity facilitated by the FTP
service, it must be configured to ensure that all commands sent to
the FTP server are logged using the verbose vsftpd log format.
</description>
<reference source="galford" ref_id="20140812" ref_url="test_attestation"/>
<reference ref_id="ftp_log_transactions" source="ssg"/></metadata>
<criteria comment="FTP is not being used or the conditions are met" operator="OR">
<extend_definition comment="vsftp package is not installed" definition_ref="oval:ssg:def:168" negate="true"/>
<criteria comment="FTP configuration conditions are not set or are met" operator="AND">
<criterion comment="log ftp transactions enable" test_ref="oval:ssg:tst:169"/>
<criterion comment="log ftp transactions format" test_ref="oval:ssg:tst:170"/>
<criterion comment="log ftp transactions protocol" test_ref="oval:ssg:tst:171"/>
</criteria>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:172" version="1">
<metadata>
<title>Implement Blank Screensaver</title>
<affected family="unix">
<platform>Red Hat Enterprise Linux 7</platform>
<platform>Fedora 20</platform>
</affected>
<description>The GNOME3 screensaver should be blank.</description>
<reference source="galford" ref_id="20140824" ref_url="test_attestation"/>
<reference ref_id="dconf_gnome_screensaver_mode_blank" source="ssg"/></metadata>
<criteria operator="OR">
<extend_definition comment="dconf installed" definition_ref="oval:ssg:def:134" negate="true"/>
<criteria comment="Enable blank screensaver and prevent user from changing it" operator="AND">
<extend_definition comment="dconf user profile exists" definition_ref="oval:ssg:def:145"/>
<criterion comment="screensaver is blank" test_ref="oval:ssg:tst:173"/>
<criterion comment="screensaver prevent user from changing mode" test_ref="oval:ssg:tst:174"/>
</criteria>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:175" version="2">
<metadata>
<title>Kernel Runtime Parameter "kernel.exec-shield" Check</title>
<affected family="unix">
<platform>Red Hat Enterprise Linux 7</platform>
<platform>Fedora 20</platform>
</affected>
<description>The kernel runtime parameter "kernel.exec-shield" should not be disabled and set to 1 on 32-bit systems.</description>
<reference source="galford" ref_id="201410" ref_url="test_attestation"/>
<reference ref_id="sysctl_kernel_exec_shield" source="ssg"/></metadata>
<criteria operator="OR">
<criteria operator="AND" comment="system is RHEL6">
<extend_definition comment="RHEL6 installed" definition_ref="oval:ssg:def:104"/>
<criterion comment="kernel runtime parameter kernel.exec-shield set to 1" test_ref="oval:ssg:tst:176"/>
<criterion comment="kernel /etc/sysctl.conf parameter kernel.exec-shield set to 1" test_ref="oval:ssg:tst:177"/>
</criteria>
<criteria operator="AND">
<extend_definition comment="32-bit system" definition_ref="oval:ssg:def:178"/>
<criterion comment="kernel runtime parameter kernel.exec-shield set to 1" test_ref="oval:ssg:tst:176"/>
<criterion comment="kernel /etc/sysctl.conf parameter kernel.exec-shield set to 1" test_ref="oval:ssg:tst:177"/>
</criteria>
<criteria operator="AND">
<extend_definition comment="64-bit system" definition_ref="oval:ssg:def:179"/>
<criterion comment="NX is supported and is not disabled" test_ref="oval:ssg:tst:180"/>
</criteria>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:181" version="1">
<metadata>
<title>Package ntp Installed</title>
<affected family="unix">
<platform>Fedora 19</platform>
<platform>Red Hat Enterprise Linux 6</platform>
<platform>Red Hat Enterprise Linux 7</platform>
</affected>
<description>The RPM package ntp should be installed.</description>
<reference source="swells" ref_id="20130829" ref_url="test_attestation"/>
<reference ref_id="package_ntp_installed" source="ssg"/></metadata>
<criteria>
<criterion comment="package ntp is installed" test_ref="oval:ssg:tst:182"/>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:165" version="1">
<metadata>
<title>Package net-snmp Removed</title>
<affected family="unix">
<platform>Red Hat Enterprise Linux 6</platform>
<platform>Red Hat Enterprise Linux 7</platform>
<platform>Fedora 20</platform>
</affected>
<description>The RPM package net-snmp should be removed.</description>
<reference source="swells" ref_id="20130829" ref_url="test_attestation"/>
<reference ref_id="package_net-snmp_removed" source="ssg"/></metadata>
<criteria>
<criterion comment="package net-snmp is removed" test_ref="oval:ssg:tst:183"/>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:179" version="1">
<!-- Note that this does not meet requirements for class=inventory as
that only tests for patches per 5.10.1 Revision 1 -->
<metadata>
<title>Test for x86_64 Architecture</title>
<affected family="unix">
<platform>Red Hat Enterprise Linux 6</platform>
<platform>Red Hat Enterprise Linux 7</platform>
</affected>
<description>Generic test for x86_64 architecture to be used by other tests</description>
<reference source="MED" ref_id="20130819" ref_url="test_attestation"/>
<reference ref_id="system_info_architecture_x86_64" source="ssg"/></metadata>
<criteria>
<criterion comment="Generic test for x86_64 architecture" test_ref="oval:ssg:tst:184"/>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:185" version="1">
<metadata>
<title>Set Password retry Requirements</title>
<affected family="unix">
<platform>Red Hat Enterprise Linux 6</platform>
<platform>Red Hat Enterprise Linux 7</platform>
<platform>Fedora 20</platform>
</affected>
<description>The password retry should meet minimum
requirements</description>
<reference source="swells" ref_id="20140925" ref_url="test_attestation"/>
<reference ref_id="accounts_password_pam_retry" source="ssg"/></metadata>
<criteria operator="OR" comment="Conditions for retry are satisfied">
<criteria operator="AND" comment="system is RHEL6 with pam_cracklib configured">
<extend_definition comment="RHEL6 installed" definition_ref="oval:ssg:def:104"/>
<criterion comment="rhel6 pam_cracklib" test_ref="oval:ssg:tst:186"/>
</criteria>
<criteria operator="AND" comment="system is RHEL7 with pam_pwquality configured">
<extend_definition comment="RHEL7 installed" definition_ref="oval:ssg:def:107"/>
<criterion comment="rhel7 pam_pwquality" test_ref="oval:ssg:tst:187"/>
</criteria>
<criteria operator="AND" comment="system is Fedora with pam_pwquality configured">
<extend_definition comment="Fedora installed" definition_ref="oval:ssg:def:100"/>
<criterion comment="Fedora pam_pwquality" test_ref="oval:ssg:tst:187"/>
</criteria>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:188" version="1">
<metadata>
<title>Package Antivirus Installed</title>
<affected family="unix">
<platform>Red Hat Enterprise Linux 6</platform>
<platform>Red Hat Enterprise Linux 7</platform>
<platform>Fedora 20</platform>
</affected>
<description>Antivirus software should be installed.</description>
<reference source="galford" ref_id="20140813" ref_url="test_attestation"/>
<reference ref_id="install_antivirus" source="ssg"/></metadata>
<criteria comment="Antivirus is not being used or conditions are met">
<criterion comment="Linuxshield AntiVirus package is installed" test_ref="oval:ssg:tst:189"/>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:190" version="1">
<metadata>
<title>Set Password minlen Requirements</title>
<affected family="unix">
<platform>Red Hat Enterprise Linux 7</platform>
<platform>Fedora 20</platform>
</affected>
<description>The password minlen should meet minimum requirements</description>
<reference source="galford" ref_id="20141010" ref_url="test_attestation"/>
<reference ref_id="accounts_password_pam_minlen" source="ssg"/></metadata>
<criteria operator="AND" comment="system uses pam_pwquality configured">
<extend_definition comment="pwquality.so exists in system-auth" definition_ref="oval:ssg:def:130"/>
<criterion comment="pam_pwquality" test_ref="oval:ssg:tst:191"/>
</criteria>
</definition>
<definition class="inventory" id="oval:ssg:def:103" version="1">
<metadata>
<title>Fedora release 20 (Schrödinger's Cat)</title>
<affected family="unix">
<platform>Fedora 20</platform>
</affected>
<reference ref_id="cpe:/o:fedoraproject:fedora:20" source="CPE"/>
<description>The operating system installed on the system is
Fedora release 20 (Schrödinger's Cat)</description>
<reference ref_id="installed_OS_is_fedora20" source="ssg"/></metadata>
<criteria>
<criterion comment="Installed operating system is part of the unix family" test_ref="oval:ssg:tst:101"/>
<criterion comment="Fedora release 20 is installed" test_ref="oval:ssg:tst:102"/>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:192" version="1">
<metadata>
<title>File grub.cfg Permissions</title>
<affected family="unix">
<platform>Red Hat Enterprise Linux 7</platform>
<platform>Fedora 20</platform>
</affected>
<description>File permissions for grub.cfg should be set to 0600 (or stronger). By default, this file is located at /boot/grub2/grub.cfg or, for EFI systems, at /boot/efi/EFI/redhat/grub.cfg</description>
<reference source="galford" ref_id="20140909" ref_url="test_attestation"/>
<reference ref_id="file_permissions_grub2_cfg" source="ssg"/></metadata>
<criteria operator="OR">
<criterion test_ref="oval:ssg:tst:193"/>
<criterion test_ref="oval:ssg:tst:194"/>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:195" version="1">
<metadata>
<title>Ensure gpgcheck Enabled For All Yum Package Repositories</title>
<affected family="unix">
<platform>Red Hat Enterprise Linux 6</platform>
<platform>Red Hat Enterprise Linux 7</platform>
<platform>Fedora 20</platform>
</affected>
<description>Ensure all yum repositories utilize signature checking.</description>
<reference source="MED" ref_id="20130807" ref_url="test_attestation"/>
<!-- rhel7 <reference source="SDW" ref_id="20131223" ref_url="test_attestation" /> -->
<reference ref_id="ensure_gpgcheck_never_disabled" source="ssg"/></metadata>
<criteria comment="ensure all yum repositories utilize signiature checking" operator="AND">
<criterion comment="verify no gpgpcheck=0 present in /etc/yum.repos.d files" test_ref="oval:ssg:tst:196"/>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:197" version="1">
<metadata>
<title>Enable GUI Warning Banner</title>
<affected family="unix">
<platform>Red Hat Enterprise Linux 7</platform>
<platform>Fedora 20</platform>
</affected>
<description>Enable the GUI warning banner.</description>
<reference source="galford" ref_id="20140902" ref_url="test_attestation"/>
<reference ref_id="dconf_gnome_login_banner_text" source="ssg"/></metadata>
<criteria operator="OR">
<extend_definition comment="dconf installed" definition_ref="oval:ssg:def:134" negate="true"/>
<criteria comment="Enable GUI banner and prevent user from changing it" operator="AND">
<extend_definition comment="dconf user profile exists" definition_ref="oval:ssg:def:145"/>
<criterion comment="Prevent user from changing banner" test_ref="oval:ssg:tst:198"/>
<criterion comment="Login banner is correctly set" test_ref="oval:ssg:tst:199"/>
</criteria>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:200" version="1">
<metadata>
<title>Verify No netrc Files Exist</title>
<affected family="unix">
<platform>Red Hat Enterprise Linux 6</platform>
<platform>Red Hat Enterprise Linux 7</platform>
<platform>Fedora 20</platform>
</affected>
<description>The .netrc files contain login information used to auto-login into FTP servers and reside in the user's home directory. Any .netrc files should be removed.</description>
<reference source="galford" ref_id="20141114" ref_url="test_attestation"/>
<reference ref_id="no_netrc_files" source="ssg"/></metadata>
<criteria>
<criterion test_ref="oval:ssg:tst:201" negate="true"/>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:178" version="1">
<!-- Note that this does not meet requirements for class=inventory as
that only tests for patches per 5.10.1 Revision 1 -->
<metadata>
<title>Test for x86 Architecture</title>
<affected family="unix">
<platform>Red Hat Enterprise Linux 6</platform>
<platform>Red Hat Enterprise Linux 7</platform>
</affected>
<description>Generic test for x86 architecture to be used by other tests</description>
<reference source="MED" ref_id="20130819" ref_url="test_attestation"/>
<reference ref_id="system_info_architecture_x86" source="ssg"/></metadata>
<criteria>
<criterion comment="Generic test for x86 architecture" test_ref="oval:ssg:tst:202"/>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:203" version="1">
<metadata>
<title>Specify a Remote NTP Server for Time Data</title>
<affected family="unix">
<platform>Red Hat Enterprise Linux 6</platform>
<platform>Red Hat Enterprise Linux 7</platform>
<platform>Fedora 20</platform>
</affected>
<description>A remote NTP Server for time synchronization should be
specified (and dependencies are met)</description>
<reference source="galford" ref_id="20141111" ref_url="test_attestation"/>
<reference ref_id="ntpd_specify_remote_server" source="ssg"/></metadata>
<criteria comment="ntp.conf conditions are met">
<criterion test_ref="oval:ssg:tst:204"/>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:205" version="1">
<metadata>
<title>Set ClientAliveCountMax for User Logins</title>
<affected family="unix">
<platform>Red Hat Enterprise Linux 6</platform>
<platform>Red Hat Enterprise Linux 7</platform>
<platform>Fedora 20</platform>
</affected>
<description>The SSH ClientAliveCountMax should be set to an appropriate
value (and dependencies are met)</description>
<reference source="JL" ref_id="20140414" ref_url="test_attestation"/>
<reference ref_id="sshd_set_keepalive" source="ssg"/></metadata>
<criteria comment="SSH is not being used or conditions are met" operator="OR">
<extend_definition comment="sshd service is disabled" definition_ref="oval:ssg:def:142"/>
<criterion comment="Check ClientAliveCountMax in /etc/ssh/sshd_config" test_ref="oval:ssg:tst:206"/>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:207" version="1">
<metadata>
<title>System Accounts Do Not Run a Shell</title>
<affected family="unix">
<platform>Red Hat Enterprise Linux 6</platform>
<platform>Red Hat Enterprise Linux 7</platform>
<platform>Fedora 20</platform>
</affected>
<description>The root account is the only system account that should have a login shell.</description>
<reference source="swells" ref_id="20130918" ref_url="test_attestation"/>
<reference ref_id="no_shelllogin_for_systemaccounts" source="ssg"/></metadata>
<criteria>
<criterion comment="tests for the presence of login shells (not /sbin/nologin) for system accounts in /etc/passwd file" test_ref="oval:ssg:tst:208"/>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:168" version="1">
<metadata>
<title>Package vsftpd Installed</title>
<affected family="unix">
<platform>Red Hat Enterprise Linux 6</platform>
<platform>Red Hat Enterprise Linux 7</platform>
</affected>
<description>The RPM package vsftpd should be installed.</description>
<reference source="JL" ref_id="20140522" ref_url="test_attestation"/>
<reference ref_id="package_vsftpd_installed" source="ssg"/></metadata>
<criteria>
<criterion comment="package vsftpd is installed" test_ref="oval:ssg:tst:209"/>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:210" version="1">
<metadata>
<title>Ensure insecure_locks is disabled</title>
<affected family="unix">
<platform>Red Hat Enterprise Linux 6</platform>
<platform>Red Hat Enterprise Linux 7</platform>
<platform>Fedora 20</platform>
</affected>
<description>Allowing insecure file locking could allow for sensitive
data to be viewed or edited by an unauthorized user.</description>
<reference source="galford" ref_id="20140813" ref_url="test_attestation"/>
<reference ref_id="no_insecure_locks_exports" source="ssg"/></metadata>
<criteria>
<criterion comment="Check for insecure NFS locks in /etc/exports" test_ref="oval:ssg:tst:211"/>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:212" version="2">
<metadata>
<title>SNMP default communities disabled</title>
<affected family="unix">
<platform>Red Hat Enterprise Linux 6</platform>
<platform>Red Hat Enterprise Linux 7</platform>
<platform>Fedora 20</platform>
</affected>
<description>SNMP default communities must be removed.</description>
<reference source="galford" ref_id="20140813" ref_url="test_attestation"/>
<reference ref_id="snmpd_not_default_password" source="ssg"/></metadata>
<criteria operator="OR">
<extend_definition comment="SMNP installed" definition_ref="oval:ssg:def:165"/>
<criterion comment="SNMP communities" test_ref="oval:ssg:tst:213"/>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:214" version="2">
<metadata>
<title>Set Password ucredit Requirements</title>
<affected family="unix">
<platform>Red Hat Enterprise Linux 7</platform>
<platform>Fedora 20</platform>
</affected>
<description>The password ucredit should meet minimum requirements</description>
<reference source="galford" ref_id="20141010" ref_url="test_attestation"/>
<reference ref_id="accounts_password_pam_ucredit" source="ssg"/></metadata>
<criteria operator="AND" comment="conditions for ucredit are satisfied">
<extend_definition comment="pwquality.so exists in system-auth" definition_ref="oval:ssg:def:130"/>
<criterion comment="pwquality.conf" test_ref="oval:ssg:tst:215"/>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:130" version="1">
<metadata>
<title>Check pam_pwquality Existence in system-auth</title>
<affected family="unix">
<platform>Red Hat Enterprise Linux 6</platform>
</affected>
<description>Check that pam_pwquality.so exists in system-auth</description>
<reference source="galford" ref_id="20141010" ref_url="test_attestation"/>
<reference ref_id="accounts_password_pam_pwquality" source="ssg"/></metadata>
<criteria>
<criterion comment="Conditions for pam_pwquality are satisfied" test_ref="oval:ssg:tst:216"/>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:217" version="1">
<metadata>
<title>Disable GNOME3 Automounting</title>
<affected family="unix">
<platform>Red Hat Enterprise Linux 7</platform>
<platform>Fedora 20</platform>
</affected>
<description>The system's default desktop environment, GNOME3, will mount
devices and removable media (such as DVDs, CDs and USB flash drives)
whenever they are inserted into the system. Disable automount and autorun
within GNOME3.</description>
<reference source="galford" ref_id="20140824" ref_url="test_attestation"/>
<reference ref_id="dconf_gnome_disable_automount" source="ssg"/></metadata>
<criteria operator="OR">
<extend_definition comment="dconf installed" definition_ref="oval:ssg:def:134" negate="true"/>
<criteria comment="Disable GNOME3 automount/autorun and prevent user from changing it" operator="AND">
<extend_definition comment="dconf user profile exists" definition_ref="oval:ssg:def:145"/>
<criterion comment="Disable automount in GNOME3" test_ref="oval:ssg:tst:218"/>
<criterion comment="Disable automount-open in GNOME3" test_ref="oval:ssg:tst:219"/>
<criterion comment="Disable autorun in GNOME3" test_ref="oval:ssg:tst:220"/>
<criterion comment="Prevent user from changing automount setting" test_ref="oval:ssg:tst:221"/>
<criterion comment="Prevent user from changing automount-open setting" test_ref="oval:ssg:tst:222"/>
<criterion comment="Prevent user from changing autorun setting" test_ref="oval:ssg:tst:223"/>
</criteria>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:142" version="1">
<metadata>
<title>Service sshd Disabled</title>
<affected family="unix">
<platform>Fedora 19</platform>
</affected>
<description>
The sshd service should be disabled.
</description>
<reference ref_id="service_sshd_disabled" source="ssg"/></metadata>
<criteria comment="package openssh-server removed or service sshd is not configured to start" operator="OR">
<extend_definition comment="openssh-server removed" definition_ref="oval:ssg:def:132"/>
<criterion comment="sshd disabled in multi-user.target" test_ref="oval:ssg:tst:224"/>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:225" version="1">
<metadata>
<title>Limit Password Reuse</title>
<affected family="unix">
<platform>Red Hat Enterprise Linux 6</platform>
<platform>Red Hat Enterprise Linux 7</platform>
</affected>
<description>The passwords to remember should be set correctly.</description>
<reference source="SDW" ref_id="20131025" ref_url="test_attestation"/>
<reference ref_id="accounts_password_pam_unix_remember" source="ssg"/></metadata>
<criteria>
<criterion comment="remember parameter is set to 0" test_ref="oval:ssg:tst:226"/>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:227" version="1">
<metadata>
<title>Disable Empty Passwords</title>
<affected family="unix">
<platform>Red Hat Enterprise Linux 6</platform>
<platform>Red Hat Enterprise Linux 7</platform>
<platform>Fedora 20</platform>
</affected>
<description>Remote connections from accounts with empty passwords should
be disabled (and dependencies are met)</description>
<reference source="JL" ref_id="20140414" ref_url="test_attestation"/>
<reference ref_id="sshd_disable_empty_passwords" source="ssg"/></metadata>
<criteria comment="SSH is not being used or conditions are met" operator="OR">
<extend_definition comment="sshd service is disabled" definition_ref="oval:ssg:def:142"/>
<criterion comment="Check PermitEmptyPasswords in /etc/ssh/sshd_config" negate="true" test_ref="oval:ssg:tst:228"/>
</criteria>
</definition>
<definition class="inventory" id="oval:ssg:def:104" version="1">
<metadata>
<title>Red Hat Enterprise Linux 6</title>
<affected family="unix">
<platform>Red Hat Enterprise Linux 6</platform>
</affected>
<reference ref_id="cpe:/o:redhat:enterprise_linux:6" source="CPE"/>
<description>The operating system installed on the system is
Red Hat Enterprise Linux 6</description>
<reference ref_id="installed_OS_is_rhel6" source="ssg"/></metadata>
<criteria>
<criterion comment="Installed operating system is part of the unix family" test_ref="oval:ssg:tst:101"/>
<criteria operator="OR">
<criterion comment="Red Hat Enterprise Linux 6 Workstation is installed" test_ref="oval:ssg:tst:105"/>
<criterion comment="Red Hat Enterprise Linux 6 Server is installed" test_ref="oval:ssg:tst:106"/>
</criteria>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:229" version="2">
<metadata>
<title>Set Password ocredit Requirements</title>
<affected family="unix">
<platform>Red Hat Enterprise Linux 7</platform>
<platform>Fedora 20</platform>
</affected>
<description>The password ocredit should meet minimum requirements</description>
<reference source="galford" ref_id="20141010" ref_url="test_attestation"/>
<reference ref_id="accounts_password_pam_ocredit" source="ssg"/></metadata>
<criteria operator="AND" comment="conditions for ocredit are satisfied">
<extend_definition comment="pwquality.so exists in system-auth" definition_ref="oval:ssg:def:130"/>
<criterion comment="pwquality.conf" test_ref="oval:ssg:tst:230"/>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:231" version="3">
<metadata>
<title>Set Password Expiration Parameters</title>
<affected family="unix">
<platform>Red Hat Enterprise Linux 6</platform>
<platform>Red Hat Enterprise Linux 7</platform>
<platform>Fedora 20</platform>
</affected>
<description>The password expiration warning age should be set appropriately.</description>
<reference source="JL" ref_id="RHEL6_20150201" ref_url="test_attestation"/>
<reference source="JL" ref_id="RHEL7_20150201" ref_url="test_attestation"/>
<reference source="JL" ref_id="FEDORA20_20150201" ref_url="test_attestation"/>
<reference ref_id="accounts_password_warn_age_login_defs" source="ssg"/></metadata>
<criteria>
<criterion test_ref="oval:ssg:tst:232"/>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:233" version="1">
<metadata>
<title>Verify that System Executables Have Restrictive Permissions</title>
<affected family="unix">
<platform>Fedora 19</platform>
<platform>Red Hat Enterprise Linux 6</platform>
<platform>Red Hat Enterprise Linux 7</platform>
</affected>
<description>
Checks that binary files under /bin, /sbin, /usr/bin, /usr/sbin,
/usr/local/bin, and /usr/local/sbin, are not group-writable or world-writable.
</description>
<reference ref_id="file_permissions_binary_dirs" source="ssg"/></metadata>
<criteria operator="AND">
<criterion test_ref="oval:ssg:tst:234"/>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:235" version="1">
<metadata>
<title>Set Password maxrepeat Requirements</title>
<affected family="unix">
<platform>Red Hat Enterprise Linux 7</platform>
<platform>Fedora 20</platform>
</affected>
<description>The password maxrepeat should meet minimum
requirements using pam_pwquality</description>
<reference source="galford" ref_id="20141006" ref_url="test_attestation"/>
<reference ref_id="accounts_password_pam_maxrepeat" source="ssg"/></metadata>
<criteria operator="AND" comment="conditions for maxrepeat are satisfied">
<extend_definition comment="pwquality.so exists in system-auth" definition_ref="oval:ssg:def:130"/>
<criterion comment="pwquality.conf" test_ref="oval:ssg:tst:236"/>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:237" version="1">
<metadata>
<title>File grub.cfg Owned By root User</title>
<affected family="unix">
<platform>Red Hat Enterprise Linux 7</platform>
<platform>Fedora 20</platform>
</affected>
<description>The grub.cfg file should be owned by the root user. By default, this file is located at /boot/grub2/grub.cfg or, for EFI systems, at /boot/efi/EFI/redhat/grub.cfg</description>
<reference source="galford" ref_id="20140909" ref_url="test_attestation"/>
<reference ref_id="file_user_owner_grub2_cfg" source="ssg"/></metadata>
<criteria operator="OR">
<criterion test_ref="oval:ssg:tst:238"/>
<criterion test_ref="oval:ssg:tst:239"/>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:240" version="1">
<metadata>
<title>Verify that Shared Library Files Have Restrictive Permissions</title>
<affected family="unix">
<platform>Fedora 19</platform>
<platform>Red Hat Enterprise Linux 6</platform>
<platform>Red Hat Enterprise Linux 7</platform>
</affected>
<description>
Checks that /lib, /lib64, /usr/lib, /usr/lib64, /lib/modules, and
objects therein, are not group-writable or world-writable.
</description>
<reference ref_id="file_permissions_library_dirs" source="ssg"/></metadata>
<criteria operator="AND">
<criterion test_ref="oval:ssg:tst:241"/>
<criterion test_ref="oval:ssg:tst:242"/>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:243" version="1">
<metadata>
<title>Disable root Login via SSH</title>
<affected family="unix">
<platform>Red Hat Enterprise Linux 6</platform>
<platform>Red Hat Enterprise Linux 7</platform>
<platform>Fedora 20</platform>
</affected>
<description>Root login via SSH should be disabled (and dependencies are
met)</description>
<reference source="JL" ref_id="20140414" ref_url="test_attestation"/>
<reference ref_id="sshd_disable_root_login" source="ssg"/></metadata>
<criteria comment="SSH is not being used or conditions are met" operator="OR">
<extend_definition comment="sshd service is disabled" definition_ref="oval:ssg:def:142"/>
<criterion comment="Check PermitRootLogin in /etc/ssh/sshd_config" negate="true" test_ref="oval:ssg:tst:244"/>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:245" version="1">
<metadata>
<title>Restrict Serial Port Root Logins</title>
<affected family="unix">
<platform>Red Hat Enterprise Linux 6</platform>
<platform>Red Hat Enterprise Linux 7</platform>
<platform>Fedora 20</platform>
</affected>
<description>Preventing direct root login to serial port interfaces helps
ensure accountability for actions taken on the system using the root
account.</description>
<reference source="galford" ref_id="20141114" ref_url="test_attestation"/>
<reference ref_id="restrict_serial_port_logins" source="ssg"/></metadata>
<criteria>
<criterion comment="serial ports /etc/securetty" test_ref="oval:ssg:tst:246" negate="true"/>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:247" version="2">
<metadata>
<title>Set Password difok Requirements</title>
<affected family="unix">
<platform>Red Hat Enterprise Linux 7</platform>
<platform>Fedora 20</platform>
</affected>
<description>The password difok should meet minimum requirements</description>
<reference source="galford" ref_id="20141010" ref_url="test_attestation"/>
<reference ref_id="accounts_password_pam_difok" source="ssg"/></metadata>
<criteria operator="AND" comment="conditions for difok are satisfied">
<extend_definition comment="pwquality.so exists in system-auth" definition_ref="oval:ssg:def:130"/>
<criterion comment="pwquality.conf" test_ref="oval:ssg:tst:248"/>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:249" version="1">
<metadata>
<title>Ensure Yum gpgcheck Globally Activated</title>
<affected family="unix">
<platform>Red Hat Enterprise Linux 6</platform>
<platform>Red Hat Enterprise Linux 7</platform>
<platform>Fedora 20</platform>
</affected>
<description>The gpgcheck option should be used to ensure that checking
of an RPM package's signature always occurs prior to its
installation.</description>
<reference source="MED" ref_id="20130807" ref_url="test_attestation"/>
<!-- rhel7: <reference source="SDW" ref_id="20131223" ref_url="test_attestation" /> -->
<reference ref_id="ensure_gpgcheck_globally_activated" source="ssg"/></metadata>
<criteria>
<criterion comment="check value of gpgcheck in /etc/yum.conf" test_ref="oval:ssg:tst:250"/>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:251" version="3">
<metadata>
<title>Set Password Expiration Parameters</title>
<affected family="unix">
<platform>Red Hat Enterprise Linux 6</platform>
<platform>Red Hat Enterprise Linux 7</platform>
<platform>Fedora 20</platform>
</affected>
<description>The password minimum length should be set appropriately.</description>
<reference source="JL" ref_id="RHEL6_20150201" ref_url="test_attestation"/>
<reference source="JL" ref_id="RHEL7_20150201" ref_url="test_attestation"/>
<reference source="JL" ref_id="FEDORA20_20150201" ref_url="test_attestation"/>
<reference ref_id="accounts_password_minlen_login_defs" source="ssg"/></metadata>
<criteria operator="AND">
<criterion test_ref="oval:ssg:tst:252"/>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:253" version="2">
<metadata>
<title>System Login Banner Compliance</title>
<affected family="unix">
<platform>Red Hat Enterprise Linux 6</platform>
<platform>Red Hat Enterprise Linux 7</platform>
</affected>
<description>The system login banner text should be set correctly.</description>
<reference source="MED" ref_id="20130819" ref_url="test_attestation"/>
<reference ref_id="banner_etc_issue" source="ssg"/></metadata>
<criteria>
<criterion comment="/etc/issue is set appropriately" test_ref="oval:ssg:tst:254"/>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:255" version="1">
<metadata>
<title>Disable All GNOME3 Thumbnailers</title>
<affected family="unix">
<platform>Red Hat Enterprise Linux 7</platform>
<platform>Fedora 20</platform>
</affected>
<description>The system's default desktop environment, GNOME3, uses a
number of different thumbnailer programs to generate thumbnails for any
new or modified content in an opened folder. Disable the execution of
these thumbnail applications within GNOME3.</description>
<reference source="galford" ref_id="20140824" ref_url="test_attestation"/>
<reference ref_id="dconf_gnome_disable_thumbnailers" source="ssg"/></metadata>
<criteria operator="OR">
<extend_definition comment="dconf installed" definition_ref="oval:ssg:def:134" negate="true"/>
<criteria comment="Disable Gnome3 Thumbnailers and prevent user from enabling" operator="AND">
<extend_definition comment="dconf user profile exists" definition_ref="oval:ssg:def:145"/>
<criterion comment="Disable thumbnailers in GNOME3" test_ref="oval:ssg:tst:256"/>
<criterion comment="prevent user from changing idle delay" test_ref="oval:ssg:tst:257"/>
</criteria>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:145" version="1">
<metadata>
<title>Implement Local DB for DConf User Profile</title>
<affected family="unix">
<platform>Red Hat Enterprise Linux 7</platform>
<platform>Fedora 20</platform>
</affected>
<description>The DConf User profile should have the local DB configured.</description>
<reference source="galford" ref_id="20140824" ref_url="test_attestation"/>
<reference ref_id="enable_dconf_user_profile" source="ssg"/></metadata>
<criteria>
<criterion comment="dconf user profile exists" test_ref="oval:ssg:tst:258"/>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:259" version="2">
<metadata>
<title>Kernel Runtime Parameter IPv6 Check</title>
<affected family="unix">
<platform>Red Hat Enterprise Linux 7</platform>
<platform>Fedora 20</platform>
</affected>
<description>Disables IPv6 for all network interfaces.</description>
<reference source="galford" ref_id="20141015" ref_url="test_attestation"/>
<reference ref_id="sysctl_kernel_ipv6_disable" source="ssg"/></metadata>
<criteria operator="AND">
<criterion comment="Disable IPv6 runtime check" test_ref="oval:ssg:tst:260"/>
<criterion comment="Disable IPv6 in sysctl.d conf file" test_ref="oval:ssg:tst:261"/>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:262" version="2">
<metadata>
<title>Set Password lcredit Requirements</title>
<affected family="unix">
<platform>Red Hat Enterprise Linux 7</platform>
<platform>Fedora 20</platform>
</affected>
<description>The password lcredit should meet minimum requirements</description>
<reference source="swells" ref_id="20140926" ref_url="test_attestation"/>
<reference ref_id="accounts_password_pam_lcredit" source="ssg"/></metadata>
<criteria operator="AND" comment="conditions for lcredit are satisfied">
<extend_definition comment="pwquality.so exists in system-auth" definition_ref="oval:ssg:def:130"/>
<criterion comment="pwquality.conf" test_ref="oval:ssg:tst:263"/>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:264" version="1">
<metadata>
<title>Set Boot Loader Password</title>
<affected family="unix">
<platform>Red Hat Enterprise Linux 7</platform>
<platform>Fedora 20</platform>
</affected>
<description>The grub2 boot loader should have password protection enabled.</description>
<reference source="galford" ref_id="20140909" ref_url="test_attestation"/>
<reference ref_id="bootloader_password" source="ssg"/></metadata>
<criteria operator="AND">
<criterion comment="make sure a password is defined in /etc/grub2.cfg" test_ref="oval:ssg:tst:265"/>
<criterion comment="make sure a superuser is defined in /etc/grub2.cfg" test_ref="oval:ssg:tst:266"/>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:267" version="1">
<metadata>
<title>All Password Hashes Shadowed</title>
<affected family="unix">
<platform>Red Hat Enterprise Linux 6</platform>
<platform>Red Hat Enterprise Linux 7</platform>
<platform>Fedora 20</platform>
</affected>
<description>All password hashes should be shadowed.</description>
<reference source="swells" ref_id="20130918" ref_url="test_attestation"/>
<reference ref_id="accounts_password_all_shadowed" source="ssg"/></metadata>
<criteria>
<criterion comment="password hashes are shadowed" test_ref="oval:ssg:tst:268"/>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:269" version="1">
<metadata>
<title>Enable GNOME3 Screensaver Idle Activation</title>
<affected family="unix">
<platform>Red Hat Enterprise Linux 7</platform>
<platform>Fedora 20</platform>
</affected>
<description>Idle activation of the screen saver should be enabled.</description>
<reference source="galford" ref_id="20140824" ref_url="test_attestation"/>
<reference ref_id="dconf_gnome_screensaver_idle_activation_enabled" source="ssg"/></metadata>
<criteria operator="OR">
<extend_definition comment="dconf installed" definition_ref="oval:ssg:def:134" negate="true"/>
<criteria comment="check screensaver idle activation and prevent user from changing it" operator="AND">
<extend_definition comment="dconf user profile exists" definition_ref="oval:ssg:def:145"/>
<criterion comment="idle activation has been configured" test_ref="oval:ssg:tst:270"/>
<criterion comment="prevent user from changing idle delay" test_ref="oval:ssg:tst:271"/>
</criteria>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:272" version="1">
<metadata>
<title>Service ntpd Enabled</title>
<affected family="unix">
<platform>Fedora 19</platform>
</affected>
<description>
The ntpd service should be enabled.
</description>
<reference ref_id="service_ntpd_enabled" source="ssg"/></metadata>
<criteria comment="package ntp installed and service ntpd is configured to start" operator="AND">
<extend_definition comment="ntp installed" definition_ref="oval:ssg:def:181"/>
<criterion comment="ntpd multi-user.target" test_ref="oval:ssg:tst:273"/>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:274" version="2">
<metadata>
<title>Write permissions are disabled for group and other in all
directories in Root's Path</title>
<affected family="unix">
<platform>Red Hat Enterprise Linux 6</platform>
<platform>Red Hat Enterprise Linux 7</platform>
<platform>Fedora 20</platform>
</affected>
<description>Check each directory in root's path and make use it does
not grant write permission to group and other</description>
<reference source="JL" ref_id="RHEL6_20141119" ref_url="test_attestation"/>
<reference source="JL" ref_id="RHEL7_20141119" ref_url="test_attestation"/>
<reference source="JL" ref_id="FEDORA20_20141119" ref_url="test_attestation"/>
<reference ref_id="accounts_root_path_dirs_no_write" source="ssg"/></metadata>
<criteria comment="Check that write permission to group and other in root's path is denied">
<criterion comment="Check for write permission to group and other in root's path" test_ref="oval:ssg:tst:275"/>
</criteria>
</definition>
<definition class="inventory" id="oval:ssg:def:107" version="1">
<metadata>
<title>Red Hat Enterprise Linux 7</title>
<affected family="unix">
<platform>Red Hat Enterprise Linux 7</platform>
</affected>
<reference ref_id="cpe:/o:redhat:enterprise_linux:7" source="CPE"/>
<description>The operating system installed on the system is
Red Hat Enterprise Linux 7</description>
<reference ref_id="installed_OS_is_rhel7" source="ssg"/></metadata>
<criteria>
<criterion comment="Installed operating system is part of the unix family" test_ref="oval:ssg:tst:108"/>
<criteria operator="OR">
<criterion comment="Red Hat Enterprise Linux 7 Workstation is installed" test_ref="oval:ssg:tst:109"/>
<criterion comment="Red Hat Enterprise Linux 7 Server is installed" test_ref="oval:ssg:tst:110"/>
</criteria>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:276" version="1">
<metadata>
<title>UID 0 Belongs Only To Root</title>
<affected family="unix">
<platform>Red Hat Enterprise Linux 6</platform>
<platform>Red Hat Enterprise Linux 7</platform>
<platform>Fedora 20</platform>
</affected>
<description>Only the root account should be assigned a user id of 0.</description>
<reference source="MED" ref_id="20130807" ref_url="test_attestation"/>
<!-- Fedora 20: <reference source="JL" ref_id="20140303" ref_url="test_attestation" /> -->
<reference ref_id="accounts_no_uid_except_zero" source="ssg"/></metadata>
<criteria>
<criterion comment="tests that there are no accounts with UID 0 except root in the /etc/passwd file" test_ref="oval:ssg:tst:277"/>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:278" version="1">
<metadata>
<title>File grub.cfg Owned By root Group </title>
<affected family="unix">
<platform>Red Hat Enterprise Linux 7</platform>
<platform>Fedora 20</platform>
</affected>
<description>The grub.cfg file should be owned by the root group. By default, this file is located at /boot/grub2/grub.cfg or, for EFI systems, at /boot/efi/EFI/redhat/grub.cfg</description>
<reference source="galford" ref_id="20140909" ref_url="test_attestation"/>
<reference ref_id="file_group_owner_grub2_cfg" source="ssg"/></metadata>
<criteria operator="OR">
<criterion test_ref="oval:ssg:tst:279"/>
<criterion test_ref="oval:ssg:tst:280"/>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:281" version="1">
<metadata>
<title>Restrict Virtual Console Root Logins</title>
<affected family="unix">
<platform>Red Hat Enterprise Linux 6</platform>
<platform>Red Hat Enterprise Linux 7</platform>
<platform>Fedora 20</platform>
</affected>
<description>Preventing direct root login to virtual console devices
helps ensure accountability for actions taken on the system using the
root account.</description>
<reference source="galford" ref_id="20141114" ref_url="test_attestation"/>
<reference ref_id="securetty_root_login_console_only" source="ssg"/></metadata>
<criteria>
<criterion comment="virtual consoles /etc/securetty" test_ref="oval:ssg:tst:282"/>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:283" version="3">
<metadata>
<title>Set Password Expiration Parameters</title>
<affected family="unix">
<platform>Red Hat Enterprise Linux 6</platform>
<platform>Red Hat Enterprise Linux 7</platform>
<platform>Fedora 20</platform>
</affected>
<description>The minimum password age policy should be set appropriately.</description>
<reference source="JL" ref_id="RHEL6_20150201" ref_url="test_attestation"/>
<reference source="JL" ref_id="RHEL7_20150201" ref_url="test_attestation"/>
<reference source="JL" ref_id="FEDORA20_20150201" ref_url="test_attestation"/>
<reference ref_id="accounts_minimum_age_login_defs" source="ssg"/></metadata>
<criteria comment="The value of PASS_MIN_DAYS should be set appropriately in /etc/login.defs">
<criterion test_ref="oval:ssg:tst:284"/>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:285" version="1">
<metadata>
<title>Set Password dcredit Requirements</title>
<affected family="unix">
<platform>Red Hat Enterprise Linux 7</platform>
<platform>Fedora 20</platform>
</affected>
<description>The password dcredit should meet minimum requirements</description>
<reference source="galford" ref_id="20141010" ref_url="test_attestation"/>
<reference ref_id="accounts_password_pam_dcredit" source="ssg"/></metadata>
<criteria operator="AND" comment="conditions for dcredit are satisfied">
<extend_definition comment="pwquality.so exists in system-auth" definition_ref="oval:ssg:def:130"/>
<criterion comment="pwquality.conf" test_ref="oval:ssg:tst:286"/>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:287" version="1">
<metadata>
<title>Enable GNOME3 Screensaver Lock After Idle Period</title>
<affected family="unix">
<platform>Red Hat Enterprise Linux 7</platform>
<platform>Fedora 20</platform>
</affected>
<description>Idle activation of the screen lock should be enabled.</description>
<reference source="galford" ref_id="20140824" ref_url="test_attestation"/>
<reference ref_id="dconf_gnome_screensaver_lock_enabled" source="ssg"/></metadata>
<criteria operator="OR">
<extend_definition comment="dconf installed" definition_ref="oval:ssg:def:134" negate="true"/>
<criteria comment="Enable screensaver lock and prevent user from changing it" operator="AND">
<extend_definition comment="dconf user profile exists" definition_ref="oval:ssg:def:145"/>
<criterion comment="screensaver lock is enabled" test_ref="oval:ssg:tst:288"/>
<criterion comment="screensaver lock prevent user from changing" test_ref="oval:ssg:tst:289"/>
<criterion comment="screensaver lock delay is set correctly" test_ref="oval:ssg:tst:290"/>
<criterion comment="prevent user from changing screensaver lock delay" test_ref="oval:ssg:tst:291"/>
<criterion comment="screensaver lock delay is set correctly" test_ref="oval:ssg:tst:290"/>
<criterion comment="prevent user from changing screensaver lock delay" test_ref="oval:ssg:tst:291"/>
</criteria>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:292" version="1">
<metadata>
<title>Banner for FTP Users</title>
<affected family="unix">
<platform>Red Hat Enterprise Linux 6</platform>
<platform>Red Hat Enterprise Linux 7</platform>
<platform>Fedora 20</platform>
</affected>
<description>This setting will cause the system greeting banner to be
used for FTP connections as well.</description>
<reference source="galford" ref_id="20140812" ref_url="test_attestation"/>
<reference ref_id="ftp_present_banner" source="ssg"/></metadata>
<criteria operator="OR">
<extend_definition comment="vsftpd package is not installed" negate="true" definition_ref="oval:ssg:def:168"/>
<criterion comment="Banner for FTP Users" test_ref="oval:ssg:tst:293"/>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:294" version="1">
<metadata>
<title>Configure the GNOME3 GUI Screen locking</title>
<affected family="unix">
<platform>Red Hat Enterprise Linux 7</platform>
<platform>Fedora 20</platform>
</affected>
<description>The allowed period of inactivity before the screensaver is activated.</description>
<reference source="galford" ref_id="20140824" ref_url="test_attestation"/>
<reference ref_id="dconf_gnome_screensaver_idle_delay" source="ssg"/></metadata>
<criteria operator="OR">
<extend_definition comment="dconf installed" definition_ref="oval:ssg:def:134" negate="true"/>
<criteria comment="check screensaver idle delay and prevent user from changing it" operator="AND">
<extend_definition comment="dconf user profile exists" definition_ref="oval:ssg:def:145"/>
<criterion comment="idle delay has been configured" test_ref="oval:ssg:tst:295"/>
<criterion comment="prevent user from changing idle delay" test_ref="oval:ssg:tst:296"/>
<criterion comment="idle delay is set correctly" test_ref="oval:ssg:tst:297"/>
</criteria>
</criteria>
</definition>
<definition class="compliance" id="oval:ssg:def:298" version="1">
<metadata>
<title>Require Authentication for Single-User Mode</title>
<affected family="unix">
<platform>Red Hat Enterprise Linux 7</platform>
<platform>Fedora 20</platform>
</affected>
<description>The requirement for a password to boot into single-user mode
should be configured correctly.</description>
<reference source="galford" ref_id="20140926" ref_url="test_attestation"/>
<reference ref_id="require_singleuser_auth" source="ssg"/></metadata>
<criteria operator="AND">
<criterion comment="Conditions are satisfied" test_ref="oval:ssg:tst:299"/>
<criterion test_ref="oval:ssg:tst:300"/>
<criterion test_ref="oval:ssg:tst:301" negate="true"/>
<criterion test_ref="oval:ssg:tst:302" negate="true"/>
</criteria>
</definition>
</definitions>
<tests>
<ind:textfilecontent54_test check="all" check_existence="all_exist" comment="Ensure at least one NTP server is set" id="oval:ssg:tst:126" version="1">
<ind:object object_ref="oval:ssg:obj:303"/>
</ind:textfilecontent54_test>
<ind:textfilecontent54_test check="all" check_existence="none_exist" comment="make sure nullok is not used in /etc/pam.d/system-auth" id="oval:ssg:tst:128" version="1">
<ind:object object_ref="oval:ssg:obj:304"/>
</ind:textfilecontent54_test>
<ind:textfilecontent54_test check="all" comment="check the configuration of /etc/security/pwquality.conf" id="oval:ssg:tst:131" version="1">
<ind:object object_ref="oval:ssg:obj:305"/>
<ind:state state_ref="oval:ssg:ste:306"/>
</ind:textfilecontent54_test>
<ind:family_test check="all" check_existence="at_least_one_exists" comment="installed OS part of unix family" id="oval:ssg:tst:101" version="1">
<ind:object object_ref="oval:ssg:obj:111"/>
<ind:state state_ref="oval:ssg:ste:112"/>
</ind:family_test>
<linux:rpminfo_test check="all" check_existence="only_one_exists" comment="fedora-release is version 19" id="oval:ssg:tst:102" version="1">
<linux:object object_ref="oval:ssg:obj:113"/>
<linux:state state_ref="oval:ssg:ste:114"/>
</linux:rpminfo_test>
<linux:rpminfo_test check="all" check_existence="none_exist" id="oval:ssg:tst:133" version="1" comment="package openssh-server is removed">
<linux:object object_ref="oval:ssg:obj:307"/>
</linux:rpminfo_test>
<linux:rpminfo_test check="all" check_existence="all_exist" id="oval:ssg:tst:135" version="1" comment="package dconf is installed">
<linux:object object_ref="oval:ssg:obj:308"/>
</linux:rpminfo_test>
<ind:variable_test id="oval:ssg:tst:137" check="all" comment="The value of PASS_MAX_DAYS should be set appropriately in /etc/login.defs" version="1">
<ind:object object_ref="oval:ssg:obj:309"/>
<ind:state state_ref="oval:ssg:ste:310"/>
</ind:variable_test>
<unix:file_test check="all" check_existence="none_exist" comment="binary directories uid root" id="oval:ssg:tst:139" version="1">
<unix:object object_ref="oval:ssg:obj:311"/>
</unix:file_test>
<unix:file_test check="all" check_existence="none_exist" comment="binary files uid root" id="oval:ssg:tst:140" version="1">
<unix:object object_ref="oval:ssg:obj:312"/>
</unix:file_test>
<ind:textfilecontent54_test check="all" check_existence="all_exist" comment="timeout is configured" id="oval:ssg:tst:143" version="1">
<ind:object object_ref="oval:ssg:obj:313"/>
<ind:state state_ref="oval:ssg:ste:314"/>
<ind:state state_ref="oval:ssg:ste:315"/>
</ind:textfilecontent54_test>
<ind:textfilecontent54_test check="all" check_existence="all_exist" comment="GUI banner is enabled" id="oval:ssg:tst:146" version="1">
<ind:object object_ref="oval:ssg:obj:316"/>
</ind:textfilecontent54_test>
<ind:textfilecontent54_test check="all" check_existence="all_exist" comment="GUI banner cannot be changed by user" id="oval:ssg:tst:147" version="1">
<ind:object object_ref="oval:ssg:obj:317"/>
</ind:textfilecontent54_test>
<unix:file_test check="all" check_existence="none_exist" comment="library directories uid root" id="oval:ssg:tst:149" version="1">
<unix:object object_ref="oval:ssg:obj:318"/>
</unix:file_test>
<unix:file_test check="all" check_existence="none_exist" comment="library files uid root" id="oval:ssg:tst:150" version="1">
<unix:object object_ref="oval:ssg:obj:319"/>
</unix:file_test>
<ind:textfilecontent54_test check="all" check_existence="all_exist" comment="Tests whether prelinking is disabled" id="oval:ssg:tst:152" version="1">
<ind:object object_ref="oval:ssg:obj:320"/>
</ind:textfilecontent54_test>
<ind:variable_test id="oval:ssg:tst:154" check="all" comment="The value of ENCRYPT_METHOD should be set appropriately in /etc/login.defs" version="1">
<ind:object object_ref="oval:ssg:obj:321"/>
<ind:state state_ref="oval:ssg:ste:322"/>
</ind:variable_test>
<unix:file_test check="all" check_existence="at_least_one_exists" comment="home directories" id="oval:ssg:tst:156" version="1">
<unix:object object_ref="oval:ssg:obj:323"/>
<unix:state state_ref="oval:ssg:ste:324"/>
</unix:file_test>
<ind:textfilecontent54_test id="oval:ssg:tst:158" check="all" check_existence="all_exist" comment="Check pam_faillock.so preauth silent present in /etc/pam.d/system-auth" version="1">
<ind:object object_ref="oval:ssg:obj:325"/>
<ind:state state_ref="oval:ssg:ste:326"/>
</ind:textfilecontent54_test>
<ind:textfilecontent54_test id="oval:ssg:tst:159" check="all" check_existence="all_exist" comment="Check maximum failed login attempts allowed in /etc/pam.d/system-auth (authfail)" version="1">
<ind:object object_ref="oval:ssg:obj:327"/>
<ind:state state_ref="oval:ssg:ste:326"/>
</ind:textfilecontent54_test>
<ind:textfilecontent54_test id="oval:ssg:tst:160" check="all" check_existence="all_exist" comment="Check if pam_faillock_so is called in account phase of /etc/pam.d/system-auth" version="1">
<ind:object object_ref="oval:ssg:obj:328"/>
</ind:textfilecontent54_test>
<ind:textfilecontent54_test id="oval:ssg:tst:161" check="all" check_existence="all_exist" comment="Check pam_faillock.so preauth silent present in /etc/pam.d/password-auth" version="1">
<ind:object object_ref="oval:ssg:obj:329"/>
<ind:state state_ref="oval:ssg:ste:326"/>
</ind:textfilecontent54_test>
<ind:textfilecontent54_test id="oval:ssg:tst:162" check="all" check_existence="all_exist" comment="Check maximum failed login attempts allowed in /etc/pam.d/password-auth (authfail)" version="1">
<ind:object object_ref="oval:ssg:obj:330"/>
<ind:state state_ref="oval:ssg:ste:326"/>
</ind:textfilecontent54_test>
<ind:textfilecontent54_test id="oval:ssg:tst:163" check="all" check_existence="all_exist" comment="Check if pam_faillock_so is called in account phase of /etc/pam.d/password-auth" version="1">
<ind:object object_ref="oval:ssg:obj:331"/>
</ind:textfilecontent54_test>
<ind:textfilecontent54_test check="all" check_existence="none_exist" comment="Check snmpd configuration" id="oval:ssg:tst:166" version="1">
<ind:object object_ref="oval:ssg:obj:332"/>
</ind:textfilecontent54_test>
<ind:textfilecontent54_test check="all" check_existence="all_exist" comment="log ftp transactions" id="oval:ssg:tst:169" version="1">
<ind:object object_ref="oval:ssg:obj:333"/>
</ind:textfilecontent54_test>
<ind:textfilecontent54_test check="all" check_existence="all_exist" comment="log ftp transactions" id="oval:ssg:tst:170" version="1">
<ind:object object_ref="oval:ssg:obj:334"/>
</ind:textfilecontent54_test>
<ind:textfilecontent54_test check="all" check_existence="all_exist" comment="log ftp transactions" id="oval:ssg:tst:171" version="1">
<ind:object object_ref="oval:ssg:obj:335"/>
</ind:textfilecontent54_test>
<ind:textfilecontent54_test check="all" check_existence="all_exist" comment="screensaver mode is blank" id="oval:ssg:tst:173" version="1">
<ind:object object_ref="oval:ssg:obj:336"/>
</ind:textfilecontent54_test>
<ind:textfilecontent54_test check="all" check_existence="all_exist" comment="blank screensaver cannot be changed by user" id="oval:ssg:tst:174" version="1">
<ind:object object_ref="oval:ssg:obj:337"/>
</ind:textfilecontent54_test>
<unix:sysctl_test check="all" check_existence="all_exist" comment="kernel runtime parameter kernel.exec-shield set to 1" id="oval:ssg:tst:176" version="1">
<unix:object object_ref="oval:ssg:obj:338"/>
<unix:state state_ref="oval:ssg:ste:339"/>
</unix:sysctl_test>
<ind:textfilecontent54_test check="all" check_existence="all_exist" comment="kernel.exec-shield static configuration" id="oval:ssg:tst:177" version="1">
<ind:object object_ref="oval:ssg:obj:340"/>
</ind:textfilecontent54_test>
<ind:textfilecontent54_test check="all" check_existence="none_exist" comment="NX is disabled" id="oval:ssg:tst:180" version="1">
<ind:object object_ref="oval:ssg:obj:341"/>
</ind:textfilecontent54_test>
<linux:rpminfo_test check="all" check_existence="all_exist" id="oval:ssg:tst:182" version="1" comment="package ntp is installed">
<linux:object object_ref="oval:ssg:obj:342"/>
</linux:rpminfo_test>
<linux:rpminfo_test check="all" check_existence="none_exist" id="oval:ssg:tst:183" version="1" comment="package net-snmp is removed">
<linux:object object_ref="oval:ssg:obj:343"/>
</linux:rpminfo_test>
<unix:uname_test check="all" comment="64 bit architecture" id="oval:ssg:tst:184" version="1">
<unix:object object_ref="oval:ssg:obj:344"/>
<unix:state state_ref="oval:ssg:ste:345"/>
</unix:uname_test>
<ind:textfilecontent54_test check="all" comment="check the configuration of /etc/pam.d/system-auth" id="oval:ssg:tst:186" version="1">
<ind:object object_ref="oval:ssg:obj:346"/>
<ind:state state_ref="oval:ssg:ste:347"/>
</ind:textfilecontent54_test>
<ind:textfilecontent54_test check="all" comment="check the configuration of /etc/pam.d/system-auth" id="oval:ssg:tst:187" version="1">
<ind:object object_ref="oval:ssg:obj:348"/>
<ind:state state_ref="oval:ssg:ste:347"/>
</ind:textfilecontent54_test>
<linux:rpminfo_test check="all" check_existence="all_exist" id="oval:ssg:tst:189" version="1" comment="AntiVirus package is installed">
<linux:object object_ref="oval:ssg:obj:349"/>
</linux:rpminfo_test>
<ind:textfilecontent54_test check="all" comment="check the configuration of /etc/security/pwquality.conf" id="oval:ssg:tst:191" version="1">
<ind:object object_ref="oval:ssg:obj:350"/>
<ind:state state_ref="oval:ssg:ste:351"/>
</ind:textfilecontent54_test>
<unix:file_test check="all" check_existence="all_exist" comment="Testing file permissions" id="oval:ssg:tst:193" version="1">
<unix:object object_ref="oval:ssg:obj:352"/>
<unix:state state_ref="oval:ssg:ste:353"/>
</unix:file_test>
<unix:file_test check="all" check_existence="all_exist" comment="/boot/efi/EFI/redhat/grub.cfg owned by root" id="oval:ssg:tst:194" version="1">
<unix:object object_ref="oval:ssg:obj:354"/>
<unix:state state_ref="oval:ssg:ste:353"/>
</unix:file_test>
<ind:textfilecontent54_test check="all" check_existence="none_exist" comment="check for existence of gpgcheck=0 in /etc/yum.repos.d/ files" id="oval:ssg:tst:196" version="1">
<ind:object object_ref="oval:ssg:obj:355"/>
</ind:textfilecontent54_test>
<ind:textfilecontent54_test check="all" check_existence="all_exist" comment="GUI banner cannot be changed by user" id="oval:ssg:tst:198" version="1">
<ind:object object_ref="oval:ssg:obj:356"/>
</ind:textfilecontent54_test>
<ind:textfilecontent54_test check="all" check_existence="all_exist" comment="login banner text is correctly set" id="oval:ssg:tst:199" version="1">
<ind:object object_ref="oval:ssg:obj:357"/>
<ind:state state_ref="oval:ssg:ste:358"/>
</ind:textfilecontent54_test>
<unix:file_test check="all" check_existence="at_least_one_exists" comment="look for .netrc in /home" id="oval:ssg:tst:201" version="1">
<unix:object object_ref="oval:ssg:obj:359"/>
</unix:file_test>
<unix:uname_test check="all" comment="32 bit architecture" id="oval:ssg:tst:202" version="1">
<unix:object object_ref="oval:ssg:obj:360"/>
<unix:state state_ref="oval:ssg:ste:361"/>
</unix:uname_test>
<ind:textfilecontent54_test check="all" check_existence="at_least_one_exists" comment="Ensure at least one NTP server is set" id="oval:ssg:tst:204" version="1">
<ind:object object_ref="oval:ssg:obj:362"/>
</ind:textfilecontent54_test>
<ind:textfilecontent54_test check="all" check_existence="all_exist" comment="Tests the value of the ClientAliveCountMax setting in the /etc/ssh/sshd_config file" id="oval:ssg:tst:206" version="1">
<ind:object object_ref="oval:ssg:obj:363"/>
<ind:state state_ref="oval:ssg:ste:364"/>
</ind:textfilecontent54_test>
<ind:textfilecontent54_test check="all" check_existence="none_exist" comment="tests for the presence of login shells (not /sbin/nologin) for system accounts in /etc/passwd file" id="oval:ssg:tst:208" version="1">
<ind:object object_ref="oval:ssg:obj:365"/>
</ind:textfilecontent54_test>
<linux:rpminfo_test check="all" check_existence="all_exist" id="oval:ssg:tst:209" version="1" comment="package vsftpd is installed">
<linux:object object_ref="oval:ssg:obj:366"/>
</linux:rpminfo_test>
<ind:textfilecontent54_test check="all" check_existence="none_exist" comment="Tests the value of the insecure locks in /etc/exports" id="oval:ssg:tst:211" version="1">
<ind:object object_ref="oval:ssg:obj:367"/>
</ind:textfilecontent54_test>
<ind:textfilecontent54_test check="all" check_existence="none_exist" comment="Check snmpd configuration" id="oval:ssg:tst:213" version="1">
<ind:object object_ref="oval:ssg:obj:368"/>
</ind:textfilecontent54_test>
<ind:textfilecontent54_test check="all" comment="check the configuration of /etc/security/pwquality.conf" id="oval:ssg:tst:215" version="1">
<ind:object object_ref="oval:ssg:obj:369"/>
<ind:state state_ref="oval:ssg:ste:370"/>
</ind:textfilecontent54_test>
<ind:textfilecontent54_test check="all" comment="check the configuration of /etc/pam.d/system-auth" id="oval:ssg:tst:216" version="1">
<ind:object object_ref="oval:ssg:obj:371"/>
</ind:textfilecontent54_test>
<ind:textfilecontent54_test check="all" check_existence="all_exist" comment="Disable automount in GNOME3" id="oval:ssg:tst:218" version="1">
<ind:object object_ref="oval:ssg:obj:372"/>
</ind:textfilecontent54_test>
<ind:textfilecontent54_test check="all" check_existence="all_exist" comment="Prevent user from changing automount setting" id="oval:ssg:tst:221" version="1">
<ind:object object_ref="oval:ssg:obj:373"/>
</ind:textfilecontent54_test>
<ind:textfilecontent54_test check="all" check_existence="all_exist" comment="Disable automount-open in GNOME" id="oval:ssg:tst:219" version="1">
<ind:object object_ref="oval:ssg:obj:374"/>
</ind:textfilecontent54_test>
<ind:textfilecontent54_test check="all" check_existence="all_exist" comment="Prevent user from changing automount-open setting" id="oval:ssg:tst:222" version="1">
<ind:object object_ref="oval:ssg:obj:375"/>
</ind:textfilecontent54_test>
<ind:textfilecontent54_test check="all" check_existence="all_exist" comment="Disable autorun in GNOME" id="oval:ssg:tst:220" version="1">
<ind:object object_ref="oval:ssg:obj:376"/>
</ind:textfilecontent54_test>
<ind:textfilecontent54_test check="all" check_existence="all_exist" comment="Prevent user from changing autorun setting" id="oval:ssg:tst:223" version="1">
<ind:object object_ref="oval:ssg:obj:377"/>
</ind:textfilecontent54_test>
<unix:file_test check="all" check_existence="none_exist" comment="look for sshd.service in /etc/systemd/system/multi-user.target.wants" id="oval:ssg:tst:224" version="1">
<unix:object object_ref="oval:ssg:obj:378"/>
</unix:file_test>
<ind:textfilecontent54_test check="all" check_existence="all_exist" comment="remember is set in /etc/pam.d/system-auth" id="oval:ssg:tst:226" version="1">
<ind:object object_ref="oval:ssg:obj:379"/>
<ind:state state_ref="oval:ssg:ste:380"/>
</ind:textfilecontent54_test>
<ind:textfilecontent54_test check="all" check_existence="none_exist" comment="Tests the value of the PermitEmptyPasswords[\s]*(<:nocomment:>*) setting in the /etc/ssh/sshd_config file" id="oval:ssg:tst:228" version="1">
<ind:object object_ref="oval:ssg:obj:381"/>
</ind:textfilecontent54_test>
<linux:rpminfo_test check="all" check_existence="at_least_one_exists" comment="redhat-release-workstation is version 6" id="oval:ssg:tst:105" version="1">
<linux:object object_ref="oval:ssg:obj:115"/>
<linux:state state_ref="oval:ssg:ste:116"/>
</linux:rpminfo_test>
<linux:rpminfo_test check="all" check_existence="at_least_one_exists" comment="redhat-release-server is version 6" id="oval:ssg:tst:106" version="1">
<linux:object object_ref="oval:ssg:obj:117"/>
<linux:state state_ref="oval:ssg:ste:118"/>
</linux:rpminfo_test>
<ind:textfilecontent54_test check="all" comment="check the configuration of /etc/security/pwquality.conf" id="oval:ssg:tst:230" version="1">
<ind:object object_ref="oval:ssg:obj:382"/>
<ind:state state_ref="oval:ssg:ste:383"/>
</ind:textfilecontent54_test>
<ind:variable_test id="oval:ssg:tst:232" check="all" comment="The value of PASS_WARN_AGE should be set appropriately in /etc/login.defs" version="1">
<ind:object object_ref="oval:ssg:obj:384"/>
<ind:state state_ref="oval:ssg:ste:385"/>
</ind:variable_test>
<unix:file_test check="all" check_existence="none_exist" comment="binary files go-w" id="oval:ssg:tst:234" version="1">
<unix:object object_ref="oval:ssg:obj:386"/>
</unix:file_test>
<ind:textfilecontent54_test check="all" comment="check the configuration of /etc/security/pwquality.conf" id="oval:ssg:tst:236" version="1">
<ind:object object_ref="oval:ssg:obj:387"/>
<ind:state state_ref="oval:ssg:ste:388"/>
</ind:textfilecontent54_test>
<unix:file_test check="all" check_existence="all_exist" comment="/boot/grub2/grub.cfg owned by root" id="oval:ssg:tst:238" version="1">
<unix:object object_ref="oval:ssg:obj:389"/>
<unix:state state_ref="oval:ssg:ste:390"/>
</unix:file_test>
<unix:file_test check="all" check_existence="all_exist" comment="/boot/efi/EFI/redhat/grub.cfg owned by root" id="oval:ssg:tst:239" version="1">
<unix:object object_ref="oval:ssg:obj:391"/>
<unix:state state_ref="oval:ssg:ste:390"/>
</unix:file_test>
<unix:file_test check="all" check_existence="none_exist" comment="library directories go-w" id="oval:ssg:tst:241" version="1">
<unix:object object_ref="oval:ssg:obj:392"/>
</unix:file_test>
<unix:file_test check="all" check_existence="none_exist" comment="library files go-w" id="oval:ssg:tst:242" version="1">
<unix:object object_ref="oval:ssg:obj:393"/>
</unix:file_test>
<ind:textfilecontent54_test check="all" check_existence="none_exist" comment="Tests the value of the PermitRootLogin[\s]*(<:nocomment:>*) setting in the /etc/ssh/sshd_config file" id="oval:ssg:tst:244" version="1">
<ind:object object_ref="oval:ssg:obj:394"/>
</ind:textfilecontent54_test>
<ind:textfilecontent54_test check="all" check_existence="all_exist" comment="serial ports /etc/securetty" id="oval:ssg:tst:246" version="1">
<ind:object object_ref="oval:ssg:obj:395"/>
</ind:textfilecontent54_test>
<ind:textfilecontent54_test check="all" comment="check the configuration of /etc/security/pwquality.conf" id="oval:ssg:tst:248" version="1">
<ind:object object_ref="oval:ssg:obj:396"/>
<ind:state state_ref="oval:ssg:ste:397"/>
</ind:textfilecontent54_test>
<ind:textfilecontent54_test check="all" check_existence="all_exist" comment="check value of gpgcheck in /etc/yum.conf" id="oval:ssg:tst:250" version="1">
<ind:object object_ref="oval:ssg:obj:398"/>
</ind:textfilecontent54_test>
<ind:variable_test id="oval:ssg:tst:252" check="all" comment="The value of PASS_MIN_LEN should be set appropriately in /etc/login.defs" version="1">
<ind:object object_ref="oval:ssg:obj:399"/>
<ind:state state_ref="oval:ssg:ste:400"/>
</ind:variable_test>
<ind:textfilecontent54_test check="all" check_existence="all_exist" comment="correct banner in /etc/issue" id="oval:ssg:tst:254" version="1">
<ind:object object_ref="oval:ssg:obj:401"/>
</ind:textfilecontent54_test>
<ind:textfilecontent54_test check="all" check_existence="all_exist" comment="Disable thumbnailers in GNOME3" id="oval:ssg:tst:256" version="1">
<ind:object object_ref="oval:ssg:obj:402"/>
</ind:textfilecontent54_test>
<ind:textfilecontent54_test check="all" check_existence="all_exist" comment="user cannot enable thumbnailers " id="oval:ssg:tst:257" version="1">
<ind:object object_ref="oval:ssg:obj:403"/>
</ind:textfilecontent54_test>
<ind:textfilecontent54_test check="all" check_existence="all_exist" comment="dconf user profile exists" id="oval:ssg:tst:258" version="1">
<ind:object object_ref="oval:ssg:obj:404"/>
</ind:textfilecontent54_test>
<unix:sysctl_test check="all" check_existence="all_exist" comment="Disable IPv6 runtime check" id="oval:ssg:tst:260" version="1">
<unix:object object_ref="oval:ssg:obj:405"/>
<unix:state state_ref="oval:ssg:ste:406"/>
</unix:sysctl_test>
<ind:textfilecontent54_test check="all" check_existence="all_exist" comment="Disable IPv6 in sysctl.d conf file" id="oval:ssg:tst:261" version="1">
<ind:object object_ref="oval:ssg:obj:407"/>
</ind:textfilecontent54_test>
<ind:textfilecontent54_test check="all" comment="check the configuration of /etc/security/pwquality.conf" id="oval:ssg:tst:263" version="1">
<ind:object object_ref="oval:ssg:obj:408"/>
<ind:state state_ref="oval:ssg:ste:409"/>
</ind:textfilecontent54_test>
<ind:textfilecontent54_test check="all" check_existence="all_exist" comment="superuser is defined in /etc/grub2.cfg files. Superuser is not root, admin, or administrator" id="oval:ssg:tst:266" version="1">
<ind:object object_ref="oval:ssg:obj:410"/>
</ind:textfilecontent54_test>
<ind:textfilecontent54_test check="all" check_existence="all_exist" comment="make sure a password is defined in /etc/grub2.cfg" id="oval:ssg:tst:265" version="1">
<ind:object object_ref="oval:ssg:obj:411"/>
</ind:textfilecontent54_test>
<unix:password_test check="all" comment="password hashes are shadowed" id="oval:ssg:tst:268" version="1">
<unix:object object_ref="oval:ssg:obj:412"/>
<unix:state state_ref="oval:ssg:ste:413"/>
</unix:password_test>
<ind:textfilecontent54_test check="all" check_existence="all_exist" comment="idle delay is configured" id="oval:ssg:tst:270" version="1">
<ind:object object_ref="oval:ssg:obj:414"/>
</ind:textfilecontent54_test>
<ind:textfilecontent54_test check="all" check_existence="all_exist" comment="user cannot change idle_activation_enabled" id="oval:ssg:tst:271" version="1">
<ind:object object_ref="oval:ssg:obj:415"/>
</ind:textfilecontent54_test>
<unix:file_test check="all" check_existence="at_least_one_exists" comment="look for ntpd.service in /etc/systemd/system/multi-user.target.wants" id="oval:ssg:tst:273" version="1">
<unix:object object_ref="oval:ssg:obj:416"/>
</unix:file_test>
<unix:file_test check="all" check_existence="none_exist" comment="Check if there aren't directories in root's path having write permission set for group or other" id="oval:ssg:tst:275" version="1">
<unix:object object_ref="oval:ssg:obj:417"/>
</unix:file_test>
<ind:family_test check="all" check_existence="at_least_one_exists" comment="installed OS part of unix family" id="oval:ssg:tst:108" version="1">
<ind:object object_ref="oval:ssg:obj:119"/>
<ind:state state_ref="oval:ssg:ste:120"/>
</ind:family_test>
<linux:rpminfo_test check="all" check_existence="at_least_one_exists" comment="redhat-release-workstation is version 7" id="oval:ssg:tst:109" version="1">
<linux:object object_ref="oval:ssg:obj:121"/>
<linux:state state_ref="oval:ssg:ste:122"/>
</linux:rpminfo_test>
<linux:rpminfo_test check="all" check_existence="at_least_one_exists" comment="redhat-release-server is version 7" id="oval:ssg:tst:110" version="1">
<linux:object object_ref="oval:ssg:obj:123"/>
<linux:state state_ref="oval:ssg:ste:124"/>
</linux:rpminfo_test>
<ind:textfilecontent54_test check="all" check_existence="none_exist" comment="test that there are no accounts with UID 0 except root in the /etc/passwd file" id="oval:ssg:tst:277" version="1">
<ind:object object_ref="oval:ssg:obj:418"/>
</ind:textfilecontent54_test>
<unix:file_test check="all" check_existence="all_exist" comment="/boot/grub2/grub.cfg owned by root" id="oval:ssg:tst:279" version="1">
<unix:object object_ref="oval:ssg:obj:419"/>
<unix:state state_ref="oval:ssg:ste:420"/>
</unix:file_test>
<unix:file_test check="all" check_existence="all_exist" comment="/boot/efi/EFI/redhat/grub.cfg owned by root" id="oval:ssg:tst:280" version="1">
<unix:object object_ref="oval:ssg:obj:421"/>
<unix:state state_ref="oval:ssg:ste:420"/>
</unix:file_test>
<ind:textfilecontent54_test check="all" check_existence="none_exist" comment="virtual consoles /etc/securetty" id="oval:ssg:tst:282" version="1">
<ind:object object_ref="oval:ssg:obj:422"/>
</ind:textfilecontent54_test>
<ind:variable_test id="oval:ssg:tst:284" check="all" comment="The value of PASS_MIN_DAYS should be set appropriately in /etc/login.defs" version="1">
<ind:object object_ref="oval:ssg:obj:423"/>
<ind:state state_ref="oval:ssg:ste:424"/>
</ind:variable_test>
<ind:textfilecontent54_test check="all" comment="check the configuration of /etc/security/pwquality.conf" id="oval:ssg:tst:286" version="1">
<ind:object object_ref="oval:ssg:obj:425"/>
<ind:state state_ref="oval:ssg:ste:426"/>
</ind:textfilecontent54_test>
<ind:textfilecontent54_test check="all" check_existence="all_exist" comment="screensaver lock is enabled" id="oval:ssg:tst:288" version="1">
<ind:object object_ref="oval:ssg:obj:427"/>
</ind:textfilecontent54_test>
<ind:textfilecontent54_test check="all" check_existence="all_exist" comment="screensaver lock cannot be changed by user" id="oval:ssg:tst:289" version="1">
<ind:object object_ref="oval:ssg:obj:428"/>
</ind:textfilecontent54_test>
<ind:textfilecontent54_test check="all" check_existence="all_exist" comment="screensaver lock is set correctly" id="oval:ssg:tst:290" version="1">
<ind:object object_ref="oval:ssg:obj:429"/>
</ind:textfilecontent54_test>
<ind:textfilecontent54_test check="all" check_existence="all_exist" comment="screensaver lock delay cannot be changed by user" id="oval:ssg:tst:291" version="1">
<ind:object object_ref="oval:ssg:obj:430"/>
</ind:textfilecontent54_test>
<ind:textfilecontent54_test check="all" check_existence="all_exist" comment="Banner for FTP Users" id="oval:ssg:tst:293" version="1">
<ind:object object_ref="oval:ssg:obj:431"/>
</ind:textfilecontent54_test>
<ind:textfilecontent54_test check="all" check_existence="all_exist" comment="screensaver idle delay is configured" id="oval:ssg:tst:295" version="1">
<ind:object object_ref="oval:ssg:obj:432"/>
</ind:textfilecontent54_test>
<ind:textfilecontent54_test check="all" check_existence="all_exist" comment="user cannot change screensaver idle delay" id="oval:ssg:tst:296" version="1">
<ind:object object_ref="oval:ssg:obj:433"/>
</ind:textfilecontent54_test>
<ind:textfilecontent54_test check="all" check_existence="all_exist" comment="screensaver idle delay setting is correct" id="oval:ssg:tst:297" version="1">
<ind:object object_ref="oval:ssg:obj:434"/>
<ind:state state_ref="oval:ssg:ste:435"/>
</ind:textfilecontent54_test>
<ind:textfilecontent54_test check="all" check_existence="all_exist" comment="Tests that /sbin/sulogin was not removed from the default systemd rescue.service to ensure that a password must be entered to access single user mode" id="oval:ssg:tst:299" version="1">
<ind:object object_ref="oval:ssg:obj:436"/>
</ind:textfilecontent54_test>
<ind:textfilecontent54_test check="all" check_existence="all_exist" comment="Tests that the systemd rescue.service is in the runlevel1.target" id="oval:ssg:tst:300" version="1">
<ind:object object_ref="oval:ssg:obj:437"/>
</ind:textfilecontent54_test>
<unix:file_test check="all" check_existence="at_least_one_exists" comment="look for rescue.service in /etc/systemd/system" id="oval:ssg:tst:302" version="1">
<unix:object object_ref="oval:ssg:obj:438"/>
</unix:file_test>
<unix:file_test check="all" check_existence="at_least_one_exists" comment="look for runlevel1.target in /etc/systemd/system" id="oval:ssg:tst:301" version="1">
<unix:object object_ref="oval:ssg:obj:439"/>
</unix:file_test>
</tests>
<objects>
<ind:textfilecontent54_object comment="Ensure more than one NTP server is set" id="oval:ssg:obj:303" version="1">
<ind:filepath>/etc/ntp.conf</ind:filepath>
<ind:pattern operation="pattern match">^([\s]*server[\s]+.+$){2,}$</ind:pattern>
<ind:instance datatype="int">1</ind:instance>
</ind:textfilecontent54_object>
<ind:textfilecontent54_object id="oval:ssg:obj:304" version="1">
<ind:filepath>/etc/pam.d/system-auth</ind:filepath>
<ind:pattern operation="pattern match">\s*nullok\s*</ind:pattern>
<ind:instance datatype="int">1</ind:instance>
</ind:textfilecontent54_object>
<ind:textfilecontent54_object id="oval:ssg:obj:305" version="1">
<ind:filepath>/etc/security/pwquality.conf</ind:filepath>
<ind:pattern operation="pattern match">^minclass[\s]*=[\s]*(-?\d+)(?:[\s]|$)</ind:pattern>
<ind:instance datatype="int" operation="less than or equal">1</ind:instance>
</ind:textfilecontent54_object>
<ind:family_object id="oval:ssg:obj:111" version="1"/>
<linux:rpminfo_object id="oval:ssg:obj:113" version="1">
<linux:name>fedora-release</linux:name>
</linux:rpminfo_object>
<linux:rpminfo_object id="oval:ssg:obj:307" version="1">
<linux:name>openssh-server</linux:name>
</linux:rpminfo_object>
<linux:rpminfo_object id="oval:ssg:obj:308" version="1">
<linux:name>dconf</linux:name>
</linux:rpminfo_object>
<ind:textfilecontent54_object id="oval:ssg:obj:440" version="1">
<!-- Read whole /etc/login.defs as single line so we can retrieve last PASS_MAX_DAYS directive occurrence -->
<ind:behaviors singleline="true"/>
<ind:filepath>/etc/login.defs</ind:filepath>
<!-- Retrieve last (uncommented) occurrence of PASS_MAX_DAYS directive -->
<ind:pattern operation="pattern match">.*\n[^#]*(PASS_MAX_DAYS\s+\d+)\s*\n</ind:pattern>
<ind:instance datatype="int" operation="greater than or equal">1</ind:instance>
</ind:textfilecontent54_object>
<ind:variable_object id="oval:ssg:obj:309" version="1">
<ind:var_ref>oval:ssg:var:441</ind:var_ref>
</ind:variable_object>
<unix:file_object comment="binary directories" id="oval:ssg:obj:311" version="1">
<!-- Check that /bin, /sbin, /usr/sbin, /usr/sbin, /usr/local/bin, and
/usr/local/sbin directories belong to user with uid 0 (root) -->
<unix:path operation="pattern match">^\/(|s)bin|^\/usr\/(|local\/)(|s)bin</unix:path>
<unix:filename xsi:nil="true"/>
<filter action="include">oval:ssg:ste:442</filter>
</unix:file_object>
<unix:file_object comment="binary files" id="oval:ssg:obj:312" version="1">
<!-- Check that files within /bin, /sbin, /usr/bin, /usr/sbin, /usr/local/bin, and
/usr/local/sbin directories belong to user with uid 0 (root) -->
<unix:path operation="pattern match">^\/(|s)bin|^\/usr\/(|local\/)(|s)bin</unix:path>
<unix:filename operation="pattern match">^.*$</unix:filename>
<filter action="include">oval:ssg:ste:442</filter>
</unix:file_object>
<ind:textfilecontent54_object id="oval:ssg:obj:313" version="2">
<ind:filepath>/etc/ssh/sshd_config</ind:filepath>
<ind:pattern operation="pattern match">^[\s]*(?i)ClientAliveInterval[\s]+(\d+)[\s]*(?:|(?:#.*))?$</ind:pattern>
<ind:instance datatype="int">1</ind:instance>
</ind:textfilecontent54_object>
<ind:textfilecontent54_object id="oval:ssg:obj:316" version="1">
<ind:path>/etc/dconf/db/gdm.d/</ind:path>
<ind:filename operation="pattern match">^.*$</ind:filename>
<ind:pattern operation="pattern match">^\[org/gnome/login-screen]([^\n]*\n+)+?banner-message-enable=true$</ind:pattern>
<ind:instance datatype="int">1</ind:instance>
</ind:textfilecontent54_object>
<ind:textfilecontent54_object id="oval:ssg:obj:317" version="1">
<ind:path>/etc/dconf/db/gdm.d/locks/</ind:path>
<ind:filename operation="pattern match">^.*$</ind:filename>
<ind:pattern operation="pattern match">^/org/gnome/login-screen/banner-message-enable$</ind:pattern>
<ind:instance datatype="int">1</ind:instance>
</ind:textfilecontent54_object>
<unix:file_object comment="library directories" id="oval:ssg:obj:318" version="1">
<!-- Check that /lib, /lib64, /usr/lib, and /usr/lib64 directories belong to user with uid 0 (root) -->
<unix:path operation="pattern match">^\/lib(|64)\/|^\/usr\/lib(|64)\/</unix:path>
<unix:filename xsi:nil="true"/>
<filter action="include">oval:ssg:ste:443</filter>
</unix:file_object>
<unix:file_object comment="library files" id="oval:ssg:obj:319" version="1">
<!-- Check that files within /lib, /lib64, /usr/lib, and /usr/lib64 directories belong to user with uid 0 (root) -->
<unix:path operation="pattern match">^\/lib(|64)\/|^\/usr\/lib(|64)\/</unix:path>
<unix:filename operation="pattern match">^.*$</unix:filename>
<filter action="include">oval:ssg:ste:443</filter>
</unix:file_object>
<ind:textfilecontent54_object id="oval:ssg:obj:320" version="2">
<ind:filepath>/etc/sysconfig/prelink</ind:filepath>
<ind:pattern operation="pattern match">^[\s]*PRELINKING=no[\s]*</ind:pattern>
<ind:instance datatype="int">1</ind:instance>
</ind:textfilecontent54_object>
<ind:textfilecontent54_object id="oval:ssg:obj:444" version="1">
<!-- Read whole /etc/login.defs as single line so we can retrieve last ENCRYPT_METHOD directive occurrence -->
<ind:behaviors singleline="true"/>
<ind:filepath>/etc/login.defs</ind:filepath>
<!-- Retrieve last (uncommented) occurrence of ENCRYPT_METHOD directive -->
<ind:pattern operation="pattern match">.*\n[^#]*(ENCRYPT_METHOD\s+\w+)\s*\n</ind:pattern>
<ind:instance datatype="int" operation="greater than or equal">1</ind:instance>
</ind:textfilecontent54_object>
<ind:variable_object id="oval:ssg:obj:321" version="1">
<ind:var_ref>oval:ssg:var:445</ind:var_ref>
</ind:variable_object>
<unix:file_object comment="home directories" id="oval:ssg:obj:323" version="2">
<unix:behaviors recurse="directories" recurse_direction="down" max_depth="1" recurse_file_system="all"/>
<unix:path operation="equals">/home</unix:path>
<unix:filename xsi:nil="true"/>
<filter action="exclude">oval:ssg:ste:446</filter>
<filter action="include">oval:ssg:ste:324</filter>
</unix:file_object>
<ind:textfilecontent54_object id="oval:ssg:obj:325" version="1">
<!-- Read whole /etc/pam.d/system-auth content as single line so we can verify existing order of PAM modules -->
<ind:behaviors singleline="true"/>
<ind:filepath>/etc/pam.d/system-auth</ind:filepath>
<!-- Since order of PAM modules matters ensure pam_faillock.so preauth silent in auth section is listed before
pam_unix.so module in auth section -->
<ind:pattern operation="pattern match">[\n][\s]*auth[\s]+required[\s]+pam_faillock\.so[\s]+preauth[\s]+silent[\s]+deny=([0-9]+)[\s]*[\n][\s]*auth[\s]+sufficient[\s]+pam_unix\.so[^\n]*[\n]</ind:pattern>
<!-- Check only the first instance -->
<ind:instance datatype="int" operation="equals">1</ind:instance>
</ind:textfilecontent54_object>
<ind:textfilecontent54_object id="oval:ssg:obj:327" version="1">
<!-- Read whole /etc/pam.d/system-auth content as single line so we can verify existing order of PAM modules -->
<ind:behaviors singleline="true"/>
<ind:filepath>/etc/pam.d/system-auth</ind:filepath>
<!-- Since order of PAM modules matters ensure pam_faillock.so in auth section is listed right after pam_unix.so auth row -->
<ind:pattern operation="pattern match">[\n][\s]*auth[\s]+sufficient[\s]+pam_unix\.so[^\n]+[\n][\s]*auth[\s]+\[default=die\][\s]+pam_faillock\.so[\s]+authfail[\s]+deny=([0-9]+)[^\n]*[\n]</ind:pattern>
<!-- Check only the first instance -->
<ind:instance datatype="int" operation="equals">1</ind:instance>
</ind:textfilecontent54_object>
<ind:textfilecontent54_object id="oval:ssg:obj:328" version="1">
<!-- Read whole /etc/pam.d/system-auth content as single line so we can verify existing order of PAM modules -->
<ind:behaviors singleline="true"/>
<ind:filepath>/etc/pam.d/system-auth</ind:filepath>
<!-- Since order of PAM modules matters ensure pam_faillock.so in account section is listed right before pam_unix.so account row -->
<ind:pattern operation="pattern match">[\n][\s]*account[\s]+required[\s]+pam_faillock\.so[^\n]*[\n][\s]*account[\s]+required[\s]+pam_unix\.so[^\n]*[\n]</ind:pattern>
<!-- Check only the first instance -->
<ind:instance datatype="int" operation="equals">1</ind:instance>
</ind:textfilecontent54_object>
<ind:textfilecontent54_object id="oval:ssg:obj:329" version="1">
<!-- Read whole /etc/pam.d/password-auth content as single line so we can verify existing order of PAM modules -->
<ind:behaviors singleline="true"/>
<ind:filepath>/etc/pam.d/password-auth</ind:filepath>
<!-- Since order of PAM modules matters ensure pam_faillock.so preauth silent in auth section is listed before
pam_unix.so module in auth section -->
<ind:pattern operation="pattern match">[\n][\s]*auth[\s]+required[\s]+pam_faillock\.so[\s]+preauth[\s]+silent[\s]+deny=([0-9]+)[\s]*[\n][\s]*auth[\s]+sufficient[\s]+pam_unix\.so[^\n]*[\n]</ind:pattern>
<!-- Check only the first instance -->
<ind:instance datatype="int" operation="equals">1</ind:instance>
</ind:textfilecontent54_object>
<ind:textfilecontent54_object id="oval:ssg:obj:330" version="1">
<!-- Read whole /etc/pam.d/system-auth content as single line so we can verify existing order of PAM modules -->
<ind:behaviors singleline="true"/>
<ind:filepath>/etc/pam.d/password-auth</ind:filepath>
<!-- Since order of PAM modules matters ensure pam_faillock.so in auth section is listed right after pam_unix.so auth row -->
<ind:pattern operation="pattern match">[\n][\s]*auth[\s]+sufficient[\s]+pam_unix\.so[^\n]+[\n][\s]*auth[\s]+\[default=die\][\s]+pam_faillock\.so[\s]+authfail[\s]+deny=([0-9]+)[^\n]*[\n]</ind:pattern>
<!-- Check only the first instance -->
<ind:instance datatype="int" operation="equals">1</ind:instance>
</ind:textfilecontent54_object>
<ind:textfilecontent54_object id="oval:ssg:obj:331" version="1">
<!-- Read whole /etc/pam.d/system-auth content as single line so we can verify existing order of PAM modules -->
<ind:behaviors singleline="true"/>
<ind:filepath>/etc/pam.d/password-auth</ind:filepath>
<!-- Since order of PAM modules matters ensure pam_faillock.so in account section is listed right before pam_unix.so account row -->
<ind:pattern operation="pattern match">[\n][\s]*account[\s]+required[\s]+pam_faillock\.so[^\n]*[\n][\s]*account[\s]+required[\s]+pam_unix\.so[^\n]*[\n]</ind:pattern>
<!-- Check only the first instance -->
<ind:instance datatype="int" operation="equals">1</ind:instance>
</ind:textfilecontent54_object>
<ind:textfilecontent54_object id="oval:ssg:obj:332" version="1">
<ind:filepath>/etc/snmp/snmpd.conf</ind:filepath>
<ind:pattern operation="pattern match">^[\s]*(com2se|rocommunity|rwcommunity)</ind:pattern>
<ind:instance datatype="int">1</ind:instance>
</ind:textfilecontent54_object>
<ind:textfilecontent54_object comment="log ftp transactions" id="oval:ssg:obj:333" version="1">
<ind:filepath>/etc/vsftpd/vsftpd.conf</ind:filepath>
<ind:pattern operation="pattern match">^[\s]*xferlog_enable[\s]*=[\s]*YES$</ind:pattern>
<ind:instance datatype="int" operation="greater than or equal">1</ind:instance>
</ind:textfilecontent54_object>
<ind:textfilecontent54_object comment="log ftp transactions" id="oval:ssg:obj:334" version="1">
<ind:filepath>/etc/vsftpd/vsftpd.conf</ind:filepath>
<ind:pattern operation="pattern match">^[\s]*xferlog_std_format[\s]*=[\s]*NO$</ind:pattern>
<ind:instance datatype="int" operation="greater than or equal">1</ind:instance>
</ind:textfilecontent54_object>
<ind:textfilecontent54_object comment="log ftp transactions" id="oval:ssg:obj:335" version="1">
<ind:filepath>/etc/vsftpd/vsftpd.conf</ind:filepath>
<ind:pattern operation="pattern match">^[\s]*log_ftp_protocol[\s]*=[\s]*YES$</ind:pattern>
<ind:instance datatype="int" operation="greater than or equal">1</ind:instance>
</ind:textfilecontent54_object>
<ind:textfilecontent54_object id="oval:ssg:obj:336" version="1">
<ind:path>/etc/dconf/db/local.d/</ind:path>
<ind:filename operation="pattern match">^.*$</ind:filename>
<ind:pattern operation="pattern match">^\[org/gnome/desktop/screensaver]([^\n]*\n+)+?picture-uri=\'\'$</ind:pattern>
<ind:instance datatype="int">1</ind:instance>
</ind:textfilecontent54_object>
<ind:textfilecontent54_object id="oval:ssg:obj:337" version="1">
<ind:path>/etc/dconf/db/local.d/locks/</ind:path>
<ind:filename operation="pattern match">^.*$</ind:filename>
<ind:pattern operation="pattern match">^/org/gnome/desktop/screensaver/picture-uri$</ind:pattern>
<ind:instance datatype="int">1</ind:instance>
</ind:textfilecontent54_object>
<ind:textfilecontent54_object id="oval:ssg:obj:340" version="1">
<ind:filepath>/etc/sysctl.conf</ind:filepath>
<ind:pattern operation="pattern match">^[\s]*kernel.exec-shield[\s]*=[\s]*1[\s]*$</ind:pattern>
<ind:instance datatype="int">1</ind:instance>
</ind:textfilecontent54_object>
<unix:sysctl_object id="oval:ssg:obj:338" version="1">
<unix:name>kernel.exec-shield</unix:name>
</unix:sysctl_object>
<ind:textfilecontent54_object id="oval:ssg:obj:341" version="1">
<ind:filepath>/boot/grub2/grub.cfg</ind:filepath>
<ind:pattern operation="pattern match">[\s]*noexec[\s]*=[\s]*off</ind:pattern>
<ind:instance datatype="int">1</ind:instance>
</ind:textfilecontent54_object>
<linux:rpminfo_object id="oval:ssg:obj:342" version="1">
<linux:name>ntp</linux:name>
</linux:rpminfo_object>
<linux:rpminfo_object id="oval:ssg:obj:343" version="1">
<linux:name>net-snmp</linux:name>
</linux:rpminfo_object>
<unix:uname_object comment="64 bit architecture" id="oval:ssg:obj:344" version="1"/>
<ind:textfilecontent54_object id="oval:ssg:obj:346" version="1">
<ind:filepath>/etc/pam.d/system-auth</ind:filepath>
<ind:pattern operation="pattern match">^\s*password\s+(?:(?:required)|(?:requisite))\s+pam_cracklib\.so.*retry=([0-9]*).*$</ind:pattern>
<ind:instance datatype="int">1</ind:instance>
</ind:textfilecontent54_object>
<ind:textfilecontent54_object id="oval:ssg:obj:348" version="1">
<ind:filepath>/etc/pam.d/system-auth</ind:filepath>
<ind:pattern operation="pattern match">^\s*password\s+(?:(?:required)|(?:requisite))\s+pam_pwquality\.so.*retry=([0-9]*).*$</ind:pattern>
<ind:instance datatype="int">1</ind:instance>
</ind:textfilecontent54_object>
<linux:rpminfo_object id="oval:ssg:obj:349" version="1">
<linux:name>McAfeeVSEForLinux</linux:name>
</linux:rpminfo_object>
<ind:textfilecontent54_object id="oval:ssg:obj:350" version="1">
<ind:filepath>/etc/security/pwquality.conf</ind:filepath>
<ind:pattern operation="pattern match">^minlen[\s]*=[\s]*(-?\d+)(?:[\s]|$)</ind:pattern>
<ind:instance datatype="int" operation="greater than or equal">1</ind:instance>
</ind:textfilecontent54_object>
<unix:file_object comment="/boot/grub2/grub.cfg" id="oval:ssg:obj:352" version="1">
<unix:filepath>/boot/grub2/grub.cfg</unix:filepath>
</unix:file_object>
<unix:file_object comment="/boot/efi/EFI/redhat/grub.cfg" id="oval:ssg:obj:354" version="1">
<unix:filepath>/boot/efi/EFI/redhat/grub.cfg</unix:filepath>
</unix:file_object>
<ind:textfilecontent54_object id="oval:ssg:obj:355" version="1">
<ind:path>/etc/yum.repos.d</ind:path>
<ind:filename operation="pattern match">.*</ind:filename>
<ind:pattern operation="pattern match">^\s*gpgcheck\s*=\s*0\s*$</ind:pattern>
<ind:instance datatype="int">1</ind:instance>
</ind:textfilecontent54_object>
<ind:textfilecontent54_object id="oval:ssg:obj:356" version="1">
<ind:path>/etc/dconf/db/gdm.d/locks/</ind:path>
<ind:filename operation="pattern match">^.*$</ind:filename>
<ind:pattern operation="pattern match">^/org/gnome/login-screen/banner-message-text$</ind:pattern>
<ind:instance datatype="int">1</ind:instance>
</ind:textfilecontent54_object>
<ind:textfilecontent54_object id="oval:ssg:obj:357" version="1">
<ind:path>/etc/dconf/db/gdm.d/</ind:path>
<ind:filename operation="pattern match">^.*$</ind:filename>
<ind:pattern operation="pattern match">^banner-message-text=[\s']*([^']*)</ind:pattern>
<ind:instance datatype="int">1</ind:instance>
</ind:textfilecontent54_object>
<unix:file_object comment="look for .netrc in /home" id="oval:ssg:obj:359" version="1">
<unix:behaviors recurse="directories" recurse_direction="down" max_depth="1" recurse_file_system="all"/>
<unix:path operation="equals">/home</unix:path>
<unix:filename operation="pattern match">^\.netrc$</unix:filename>
</unix:file_object>
<unix:uname_object comment="32 bit architecture" id="oval:ssg:obj:360" version="1"/>
<ind:textfilecontent54_object comment="Ensure at least one NTP server is set" id="oval:ssg:obj:362" version="1">
<ind:filepath>/etc/ntp.conf</ind:filepath>
<ind:pattern operation="pattern match">^[\s]*server[\s]+.+$</ind:pattern>
<ind:instance datatype="int">1</ind:instance>
</ind:textfilecontent54_object>
<ind:textfilecontent54_object id="oval:ssg:obj:363" version="2">
<ind:filepath>/etc/ssh/sshd_config</ind:filepath>
<ind:pattern operation="pattern match">^[\s]*(?i)ClientAliveCountMax[\s]+([\d]+)[\s]*(?:|(?:#.*))?$</ind:pattern>
<ind:instance datatype="int">1</ind:instance>
</ind:textfilecontent54_object>
<ind:textfilecontent54_object id="oval:ssg:obj:365" version="1">
<ind:filepath>/etc/passwd</ind:filepath>
<ind:pattern operation="pattern match">^(?!root).*:x:0*([0-9]{1,2}|[1-4][0-9]{2}):[\d]*:[^:]*:[^:]*:(?!\/sbin\/nologin|\/bin\/sync|\/sbin\/shutdown|\/sbin\/halt).*$</ind:pattern>
<ind:instance datatype="int">1</ind:instance>
</ind:textfilecontent54_object>
<linux:rpminfo_object id="oval:ssg:obj:366" version="1">
<linux:name>vsftpd</linux:name>
</linux:rpminfo_object>
<ind:textfilecontent54_object id="oval:ssg:obj:367" version="2">
<ind:filepath>/etc/exports</ind:filepath>
<ind:pattern operation="pattern match">^(.*?(\binsecure_locks\b)[^$]*)$</ind:pattern>
<ind:instance datatype="int">1</ind:instance>
</ind:textfilecontent54_object>
<ind:textfilecontent54_object id="oval:ssg:obj:368" version="1">
<ind:filepath>/etc/snmp/snmpd.conf</ind:filepath>
<ind:pattern operation="pattern match">^[\s]*(com2se|rocommunity|rwcommunity|createUser).*(public|private)</ind:pattern>
<ind:instance datatype="int">1</ind:instance>
</ind:textfilecontent54_object>
<ind:textfilecontent54_object id="oval:ssg:obj:369" version="1">
<ind:filepath>/etc/security/pwquality.conf</ind:filepath>
<ind:pattern operation="pattern match">^ucredit[s\]*=[\s]*(-?\d+)(?:[\s]|$)</ind:pattern>
<ind:instance datatype="int" operation="less than or equal">1</ind:instance>
</ind:textfilecontent54_object>
<ind:textfilecontent54_object id="oval:ssg:obj:371" version="1">
<ind:filepath>/etc/pam.d/system-auth</ind:filepath>
<ind:pattern operation="pattern match">^\s*password\s+(?:(?:required)|(?:requisite))\s+pam_pwquality\.so.*$</ind:pattern>
<ind:instance datatype="int">1</ind:instance>
</ind:textfilecontent54_object>
<ind:textfilecontent54_object id="oval:ssg:obj:372" version="1">
<ind:path>/etc/dconf/db/local.d/</ind:path>
<ind:filename operation="pattern match">^.*$</ind:filename>
<ind:pattern operation="pattern match">^\[org/gnome/desktop/media-handling]([^\n]*\n+)+?automount=false$</ind:pattern>
<ind:instance datatype="int">1</ind:instance>
</ind:textfilecontent54_object>
<ind:textfilecontent54_object id="oval:ssg:obj:373" version="1">
<ind:path>/etc/dconf/db/local.d/locks/</ind:path>
<ind:filename operation="pattern match">^.*$</ind:filename>
<ind:pattern operation="pattern match">^/org/gnome/desktop/media-handling/automount$</ind:pattern>
<ind:instance datatype="int">1</ind:instance>
</ind:textfilecontent54_object>
<ind:textfilecontent54_object id="oval:ssg:obj:374" version="1">
<ind:path>/etc/dconf/db/local.d/</ind:path>
<ind:filename operation="pattern match">^.*$</ind:filename>
<ind:pattern operation="pattern match">^\[org/gnome/desktop/media-handling]([^\n]*\n+)+?automount-open=false$</ind:pattern>
<ind:instance datatype="int">1</ind:instance>
</ind:textfilecontent54_object>
<ind:textfilecontent54_object id="oval:ssg:obj:375" version="1">
<ind:path>/etc/dconf/db/local.d/locks/</ind:path>
<ind:filename operation="pattern match">^.*$</ind:filename>
<ind:pattern operation="pattern match">^/org/gnome/desktop/media-handling/automount-open$</ind:pattern>
<ind:instance datatype="int">1</ind:instance>
</ind:textfilecontent54_object>
<ind:textfilecontent54_object id="oval:ssg:obj:376" version="1">
<ind:path>/etc/dconf/db/local.d/</ind:path>
<ind:filename operation="pattern match">^.*$</ind:filename>
<ind:pattern operation="pattern match">^\[org/gnome/desktop/media-handling]([^\n]*\n+)+?autorun-never=true$</ind:pattern>
<ind:instance datatype="int">1</ind:instance>
</ind:textfilecontent54_object>
<ind:textfilecontent54_object id="oval:ssg:obj:377" version="1">
<ind:path>/etc/dconf/db/local.d/locks/</ind:path>
<ind:filename operation="pattern match">^.*$</ind:filename>
<ind:pattern operation="pattern match">^/org/gnome/desktop/media-handling/autorun-never$</ind:pattern>
<ind:instance datatype="int">1</ind:instance>
</ind:textfilecontent54_object>
<unix:file_object comment="look for sshd.service in /etc/systemd/system/multi-user.target.wants" id="oval:ssg:obj:378" version="1">
<unix:filepath>/etc/systemd/system/multi-user.target.wants/sshd.service</unix:filepath>
<filter action="include">oval:ssg:ste:447</filter>
</unix:file_object>
<ind:textfilecontent54_object id="oval:ssg:obj:379" version="1">
<ind:filepath>/etc/pam.d/system-auth</ind:filepath>
<ind:pattern operation="pattern match">^\s*password\s+(?:(?:sufficient)|(?:required))\s+pam_unix\.so.*remember=([0-9]*).*$</ind:pattern>
<ind:instance datatype="int">1</ind:instance>
</ind:textfilecontent54_object>
<ind:textfilecontent54_object id="oval:ssg:obj:381" version="2">
<ind:filepath>/etc/ssh/sshd_config</ind:filepath>
<ind:pattern operation="pattern match">^[\s]*(?i)PermitEmptyPasswords(?-i)[\s]+no[\s]*(?:|(?:#.*))?$</ind:pattern>
<ind:instance datatype="int">1</ind:instance>
</ind:textfilecontent54_object>
<linux:rpminfo_object id="oval:ssg:obj:115" version="1">
<linux:name>redhat-release-workstation</linux:name>
</linux:rpminfo_object>
<linux:rpminfo_object id="oval:ssg:obj:117" version="1">
<linux:name>redhat-release-server</linux:name>
</linux:rpminfo_object>
<ind:textfilecontent54_object id="oval:ssg:obj:382" version="1">
<ind:filepath>/etc/security/pwquality.conf</ind:filepath>
<ind:pattern operation="pattern match">^ocredit[\s]*=[\s]*(-?\d+)(?:[\s]|$)</ind:pattern>
<ind:instance datatype="int" operation="less than or equal">1</ind:instance>
</ind:textfilecontent54_object>
<ind:textfilecontent54_object id="oval:ssg:obj:448" version="1">
<!-- Read whole /etc/login.defs as single line so we can retrieve last PASS_WARN_AGE directive occurrence -->
<ind:behaviors singleline="true"/>
<ind:filepath>/etc/login.defs</ind:filepath>
<!-- Retrieve last (uncommented) occurrence of PASS_WARN_AGE directive -->
<ind:pattern operation="pattern match">.*\n[^#]*(PASS_WARN_AGE\s+\d+)\s*\n</ind:pattern>
<ind:instance datatype="int" operation="greater than or equal">1</ind:instance>
</ind:textfilecontent54_object>
<ind:variable_object id="oval:ssg:obj:384" version="1">
<ind:var_ref>oval:ssg:var:449</ind:var_ref>
</ind:variable_object>
<unix:file_object comment="binary files" id="oval:ssg:obj:386" version="1">
<!-- Check that binary files under /bin, /sbin, /usr/bin, /usr/sbin, /usr/local/bin,
and /usr/local/sbin directories have safe permissions (go-w) -->
<unix:path operation="pattern match">^\/(|s)bin|^\/usr\/(|local\/)(|s)bin</unix:path>
<unix:filename operation="pattern match">^.*$</unix:filename>
<filter action="include">oval:ssg:ste:450</filter>
<filter action="exclude">oval:ssg:ste:451</filter>
</unix:file_object>
<ind:textfilecontent54_object id="oval:ssg:obj:387" version="1">
<ind:filepath>/etc/security/pwquality.conf</ind:filepath>
<ind:pattern operation="pattern match">^maxrepeat[\s]*=[\s]*(-?\d+)(?:[\s]|$)</ind:pattern>
<ind:instance datatype="int" operation="less than or equal">1</ind:instance>
</ind:textfilecontent54_object>
<unix:file_object comment="/boot/grub2/grub.cfg" id="oval:ssg:obj:389" version="1">
<unix:filepath>/boot/grub2/grub.cfg</unix:filepath>
</unix:file_object>
<unix:file_object comment="/boot/efi/EFI/redhat/grub.cfg" id="oval:ssg:obj:391" version="1">
<unix:filepath>/boot/efi/EFI/redhat/grub.cfg</unix:filepath>
</unix:file_object>
<unix:file_object comment="library directories" id="oval:ssg:obj:392" version="1">
<!-- Check that /lib, /lib64, /usr/lib, /usr/lib64 directories have safe permissions (go-w) -->
<unix:path operation="pattern match">^\/lib(|64)|^\/usr\/lib(|64)</unix:path>
<unix:filename xsi:nil="true"/>
<filter action="include">oval:ssg:ste:452</filter>
<filter action="exclude">oval:ssg:ste:453</filter>
</unix:file_object>
<unix:file_object comment="library files" id="oval:ssg:obj:393" version="1">
<!-- Check the files within /lib, /lib64, /usr/lib, /usr/lib64 directories have safe permissions (go-w) -->
<unix:path operation="pattern match">^\/lib(|64)|^\/usr\/lib(|64)</unix:path>
<unix:filename operation="pattern match">^.*$</unix:filename>
<filter action="include">oval:ssg:ste:452</filter>
<filter action="exclude">oval:ssg:ste:453</filter>
</unix:file_object>
<ind:textfilecontent54_object id="oval:ssg:obj:394" version="2">
<ind:filepath>/etc/ssh/sshd_config</ind:filepath>
<ind:pattern operation="pattern match">^[\s]*(?i)PermitRootLogin(?-i)[\s]+no[\s]*(?:|(?:#.*))?$</ind:pattern>
<ind:instance datatype="int">1</ind:instance>
</ind:textfilecontent54_object>
<ind:textfilecontent54_object comment="serial ports /etc/securetty" id="oval:ssg:obj:395" version="1">
<ind:filepath>/etc/securetty</ind:filepath>
<ind:pattern operation="pattern match">^ttyS[0-9]+$</ind:pattern>
<ind:instance datatype="int" operation="greater than or equal">1</ind:instance>
</ind:textfilecontent54_object>
<ind:textfilecontent54_object id="oval:ssg:obj:396" version="1">
<ind:filepath>/etc/security/pwquality.conf</ind:filepath>
<ind:pattern operation="pattern match">^difok[\s]*=[\s]*(\d+)(?:[\s]|$)</ind:pattern>
<ind:instance datatype="int" operation="greater than or equal">1</ind:instance>
</ind:textfilecontent54_object>
<ind:textfilecontent54_object id="oval:ssg:obj:398" comment="gpgcheck set in /etc/yum.conf" version="1">
<ind:filepath>/etc/yum.conf</ind:filepath>
<ind:pattern operation="pattern match">^\s*gpgcheck\s*=\s*1\s*$</ind:pattern>
<ind:instance datatype="int" operation="equals">1</ind:instance>
</ind:textfilecontent54_object>
<ind:textfilecontent54_object id="oval:ssg:obj:454" version="1">
<!-- Read whole /etc/login.defs as single line so we can retrieve last PASS_MIN_LEN directive occurrence -->
<ind:behaviors singleline="true"/>
<ind:filepath>/etc/login.defs</ind:filepath>
<!-- Retrieve last (uncommented) occurrence of PASS_MIN_LEN directive -->
<ind:pattern operation="pattern match">.*\n[^#]*(PASS_MIN_LEN\s+\d+)\s*\n</ind:pattern>
<ind:instance datatype="int" operation="greater than or equal">1</ind:instance>
</ind:textfilecontent54_object>
<ind:variable_object id="oval:ssg:obj:399" version="1">
<ind:var_ref>oval:ssg:var:455</ind:var_ref>
</ind:variable_object>
<ind:textfilecontent54_object id="oval:ssg:obj:401" version="1">
<ind:filepath>/etc/issue</ind:filepath>
<ind:pattern var_ref="oval:ssg:var:456" operation="pattern match"/>
<ind:instance datatype="int" operation="greater than or equal">1</ind:instance>
</ind:textfilecontent54_object>
<ind:textfilecontent54_object id="oval:ssg:obj:402" version="1">
<ind:path>/etc/dconf/db/local.d/</ind:path>
<ind:filename operation="pattern match">^.*$</ind:filename>
<ind:pattern operation="pattern match">^\[org/gnome/desktop/thumbnailers]([^\n]*\n+)+?disable-all=true$</ind:pattern>
<ind:instance datatype="int">1</ind:instance>
</ind:textfilecontent54_object>
<ind:textfilecontent54_object id="oval:ssg:obj:403" version="1">
<ind:path>/etc/dconf/db/local.d/locks/</ind:path>
<ind:filename operation="pattern match">^.*$</ind:filename>
<ind:pattern operation="pattern match">^/org/gnome/desktop/thumbnailers/disable-all$</ind:pattern>
<ind:instance datatype="int">1</ind:instance>
</ind:textfilecontent54_object>
<ind:textfilecontent54_object id="oval:ssg:obj:404" version="2">
<ind:filepath>/etc/dconf/profile/user</ind:filepath>
<ind:pattern operation="pattern match">^user-db:user\nsystem-db:local$</ind:pattern>
<ind:instance datatype="int">1</ind:instance>
</ind:textfilecontent54_object>
<ind:textfilecontent54_object id="oval:ssg:obj:407" version="1">
<ind:filepath>/etc/sysctl.d/ipv6.conf</ind:filepath>
<ind:pattern operation="pattern match">^[\s]*net.ipv6.conf.all.disable_ipv6[\s]*=[\s]*1[\s]*$</ind:pattern>
<ind:instance datatype="int">1</ind:instance>
</ind:textfilecontent54_object>
<unix:sysctl_object id="oval:ssg:obj:405" version="1">
<unix:name>net.ipv6.conf.all.disable_ipv6</unix:name>
</unix:sysctl_object>
<ind:textfilecontent54_object id="oval:ssg:obj:408" version="1">
<ind:filepath>/etc/security/pwquality.conf</ind:filepath>
<ind:pattern operation="pattern match">^lcredit[\s]*=[\s]*(-?\d+)(?:[\s]|$)</ind:pattern>
<ind:instance datatype="int" operation="less than or equal">1</ind:instance>
</ind:textfilecontent54_object>
<ind:textfilecontent54_object id="oval:ssg:obj:410" version="1">
<ind:filepath>/etc/grub2.cfg</ind:filepath>
<ind:pattern operation="pattern match">^[\s]*set[\s]+superusers=\"(?i)(?!root|admin|administrator)(?-i).*\"$</ind:pattern>
<ind:instance datatype="int">1</ind:instance>
</ind:textfilecontent54_object>
<ind:textfilecontent54_object id="oval:ssg:obj:411" version="1">
<ind:filepath>/etc/grub2.cfg</ind:filepath>
<ind:pattern operation="pattern match">^[\s]*password_pbkdf2[\s]+.*[\s]+grub\.pbkdf2\.sha512.*$</ind:pattern>
<ind:instance datatype="int">1</ind:instance>
</ind:textfilecontent54_object>
<unix:password_object id="oval:ssg:obj:412" version="1">
<unix:username operation="pattern match">.*</unix:username>
</unix:password_object>
<ind:textfilecontent54_object id="oval:ssg:obj:414" version="1">
<ind:path>/etc/dconf/db/local.d/</ind:path>
<ind:filename operation="pattern match">^.*$</ind:filename>
<ind:pattern operation="pattern match">^\[org/gnome/desktop/screensaver]([^\n]*\n+)+?idle-activation-enabled=true$</ind:pattern>
<ind:instance datatype="int">1</ind:instance>
</ind:textfilecontent54_object>
<ind:textfilecontent54_object id="oval:ssg:obj:415" version="1">
<ind:path>/etc/dconf/db/local.d/locks/</ind:path>
<ind:filename operation="pattern match">^.*$</ind:filename>
<ind:pattern operation="pattern match">^/org/gnome/desktop/screensaver/idle-activation-enabled$</ind:pattern>
<ind:instance datatype="int">1</ind:instance>
</ind:textfilecontent54_object>
<unix:file_object comment="look for ntpd.service in /etc/systemd/system/multi-user.target.wants" id="oval:ssg:obj:416" version="1">
<unix:filepath>/etc/systemd/system/multi-user.target.wants/ntpd.service</unix:filepath>
<filter action="include">oval:ssg:ste:447</filter>
</unix:file_object>
<ind:environmentvariable58_object id="oval:ssg:obj:457" version="1">
<ind:pid xsi:nil="true" datatype="int"/>
<ind:name>PATH</ind:name>
</ind:environmentvariable58_object>
<unix:file_object comment="root's path directories with wrong group / other write permissions" id="oval:ssg:obj:417" version="1">
<unix:path var_ref="oval:ssg:var:458" var_check="at least one"/>
<unix:filename xsi:nil="true"/>
<filter action="include">oval:ssg:ste:459</filter>
<filter action="exclude">oval:ssg:ste:460</filter>
</unix:file_object>
<ind:family_object id="oval:ssg:obj:119" version="1"/>
<linux:rpminfo_object id="oval:ssg:obj:121" version="1">
<linux:name>redhat-release-workstation</linux:name>
</linux:rpminfo_object>
<linux:rpminfo_object id="oval:ssg:obj:123" version="1">
<linux:name>redhat-release-server</linux:name>
</linux:rpminfo_object>
<ind:textfilecontent54_object id="oval:ssg:obj:418" version="1">
<ind:filepath>/etc/passwd</ind:filepath>
<ind:pattern operation="pattern match">^(?!root:)[^:]*:[^:]*:0</ind:pattern>
<ind:instance datatype="int">1</ind:instance>
</ind:textfilecontent54_object>
<unix:file_object comment="/boot/grub2/grub.cfg" id="oval:ssg:obj:419" version="1">
<unix:filepath>/boot/grub2/grub.cfg</unix:filepath>
</unix:file_object>
<unix:file_object comment="/boot/efi/EFI/redhat/grub.cfg" id="oval:ssg:obj:421" version="1">
<unix:filepath>/boot/efi/EFI/redhat/grub.cfg</unix:filepath>
</unix:file_object>
<ind:textfilecontent54_object comment="virtual consoles /etc/securetty" id="oval:ssg:obj:422" version="1">
<ind:filepath>/etc/securetty</ind:filepath>
<ind:pattern operation="pattern match">^vc/[0-9]+$</ind:pattern>
<ind:instance datatype="int" operation="greater than or equal">1</ind:instance>
</ind:textfilecontent54_object>
<ind:textfilecontent54_object id="oval:ssg:obj:461" version="1">
<!-- Read whole /etc/login.defs as single line so we can retrieve last PASS_MIN_DAYS directive occurrence -->
<ind:behaviors singleline="true"/>
<ind:filepath>/etc/login.defs</ind:filepath>
<!-- Retrieve last (uncommented) occurrence of PASS_MIN_DAYS directive -->
<ind:pattern operation="pattern match">.*\n[^#]*(PASS_MIN_DAYS\s+\d+)\s*\n</ind:pattern>
<ind:instance datatype="int" operation="greater than or equal">1</ind:instance>
</ind:textfilecontent54_object>
<ind:variable_object id="oval:ssg:obj:423" version="1">
<ind:var_ref>oval:ssg:var:462</ind:var_ref>
</ind:variable_object>
<ind:textfilecontent54_object id="oval:ssg:obj:425" version="1">
<ind:filepath>/etc/security/pwquality.conf</ind:filepath>
<ind:pattern operation="pattern match">^dcredit[\s]*=[\s]*(-?\d+)(?:[\s]|$)</ind:pattern>
<ind:instance datatype="int" operation="less than or equal">1</ind:instance>
</ind:textfilecontent54_object>
<ind:textfilecontent54_object id="oval:ssg:obj:427" version="1">
<ind:path>/etc/dconf/db/local.d/</ind:path>
<ind:filename operation="pattern match">^.*$</ind:filename>
<ind:pattern operation="pattern match">^\[org/gnome/desktop/screensaver]([^\n]*\n+)+?lock-enabled=true$</ind:pattern>
<ind:instance datatype="int">1</ind:instance>
</ind:textfilecontent54_object>
<ind:textfilecontent54_object id="oval:ssg:obj:428" version="1">
<ind:path>/etc/dconf/db/local.d/locks/</ind:path>
<ind:filename operation="pattern match">^.*$</ind:filename>
<ind:pattern operation="pattern match">^/org/gnome/desktop/screensaver/lock-enabled$</ind:pattern>
<ind:instance datatype="int">1</ind:instance>
</ind:textfilecontent54_object>
<ind:textfilecontent54_object id="oval:ssg:obj:429" version="1">
<ind:path>/etc/dconf/db/local.d/</ind:path>
<ind:filename operation="pattern match">^.*$</ind:filename>
<ind:pattern operation="pattern match">^\[org/gnome/desktop/screensaver]([^\n]*\n+)+?lock-delay=0$</ind:pattern>
<ind:instance datatype="int">1</ind:instance>
</ind:textfilecontent54_object>
<ind:textfilecontent54_object id="oval:ssg:obj:430" version="1">
<ind:path>/etc/dconf/db/local.d/locks/</ind:path>
<ind:filename operation="pattern match">^.*$</ind:filename>
<ind:pattern operation="pattern match">^/org/gnome/desktop/screensaver/lock-delay$</ind:pattern>
<ind:instance datatype="int">1</ind:instance>
</ind:textfilecontent54_object>
<ind:textfilecontent54_object comment="Banner for FTP Users" id="oval:ssg:obj:431" version="1">
<ind:filepath>/etc/vsftpd/vsftpd.conf</ind:filepath>
<ind:pattern operation="pattern match">^[\s]*banner_file[\s]*=[\s]*/etc/issue*$</ind:pattern>
<ind:instance datatype="int" operation="greater than or equal">1</ind:instance>
</ind:textfilecontent54_object>
<ind:textfilecontent54_object id="oval:ssg:obj:432" version="1">
<ind:path>/etc/dconf/db/local.d/</ind:path>
<ind:filename operation="pattern match">^.*$</ind:filename>
<ind:pattern operation="pattern match">^\[org/gnome/desktop/session]([^\n]*\n+)+?idle-delay=[0-9]*$</ind:pattern>
<ind:instance datatype="int">1</ind:instance>
</ind:textfilecontent54_object>
<ind:textfilecontent54_object id="oval:ssg:obj:433" version="1">
<ind:path>/etc/dconf/db/local.d/locks/</ind:path>
<ind:filename operation="pattern match">^.*$</ind:filename>
<ind:pattern operation="pattern match">^/org/gnome/desktop/session/idle-delay$</ind:pattern>
<ind:instance datatype="int">1</ind:instance>
</ind:textfilecontent54_object>
<ind:textfilecontent54_object id="oval:ssg:obj:434" version="1">
<ind:path>/etc/dconf/db/local.d/</ind:path>
<ind:filename operation="pattern match">^.*$</ind:filename>
<ind:pattern operation="pattern match">^idle-delay[\s=]*([^=\s]*)</ind:pattern>
<ind:instance datatype="int">1</ind:instance>
</ind:textfilecontent54_object>
<ind:textfilecontent54_object id="oval:ssg:obj:436" version="1">
<ind:filepath>/usr/lib/systemd/system/rescue.service</ind:filepath>
<ind:pattern operation="pattern match">^ExecStart=\-.*/sbin/sulogin</ind:pattern>
<ind:instance datatype="int">1</ind:instance>
</ind:textfilecontent54_object>
<ind:textfilecontent54_object id="oval:ssg:obj:437" version="1">
<ind:filepath>/usr/lib/systemd/system/runlevel1.target</ind:filepath>
<ind:pattern operation="pattern match">^Requires=.*rescue.service</ind:pattern>
<ind:instance datatype="int">1</ind:instance>
</ind:textfilecontent54_object>
<unix:file_object comment="look for rescue.service in /etc/systemd/system" id="oval:ssg:obj:438" version="1">
<unix:behaviors recurse="directories" recurse_direction="down" recurse_file_system="all"/>
<unix:path operation="equals">/etc/systemd/system</unix:path>
<unix:filename operation="pattern match">^rescue.service$</unix:filename>
</unix:file_object>
<unix:file_object comment="look for runlevel1.target in /etc/systemd/system" id="oval:ssg:obj:439" version="1">
<unix:behaviors recurse="directories" recurse_direction="down" recurse_file_system="all"/>
<unix:path operation="equals">/etc/systemd/system</unix:path>
<unix:filename operation="pattern match">^runlevel1.target$</unix:filename>
</unix:file_object>
</objects>
<states>
<ind:textfilecontent54_state id="oval:ssg:ste:306" version="1">
<ind:instance datatype="int">1</ind:instance>
<ind:subexpression datatype="int" operation="greater than or equal" var_ref="oval:ssg:var:463"/>
</ind:textfilecontent54_state>
<ind:family_state id="oval:ssg:ste:112" version="1">
<ind:family>unix</ind:family>
</ind:family_state>
<linux:rpminfo_state id="oval:ssg:ste:114" version="1">
<linux:version operation="pattern match">^19$</linux:version>
</linux:rpminfo_state>
<ind:variable_state id="oval:ssg:ste:310" version="1">
<ind:value operation="less than or equal" var_ref="oval:ssg:var:464" datatype="int" var_check="at least one"/>
</ind:variable_state>
<unix:file_state id="oval:ssg:ste:442" version="1" operator="OR">
<unix:user_id datatype="int" operation="not equal">0</unix:user_id>
</unix:file_state>
<ind:textfilecontent54_state comment="upper bound of ClientAliveInterval in seconds" id="oval:ssg:ste:314" version="1">
<ind:subexpression datatype="int" operation="less than or equal" var_check="all" var_ref="oval:ssg:var:465"/>
</ind:textfilecontent54_state>
<ind:textfilecontent54_state comment="lower bound of ClientAliveInterval in seconds" id="oval:ssg:ste:315" version="1">
<ind:subexpression datatype="int" operation="greater than">0</ind:subexpression>
</ind:textfilecontent54_state>
<unix:file_state id="oval:ssg:ste:443" version="1">
<unix:user_id datatype="int" operation="not equal">0</unix:user_id>
</unix:file_state>
<ind:variable_state id="oval:ssg:ste:322" version="1">
<ind:value operation="equals" datatype="string">SHA512</ind:value>
</ind:variable_state>
<unix:file_state id="oval:ssg:ste:446" version="1">
<!-- Exclude /home directory itself from the check. Check /home/* directories only. -->
<unix:path operation="equals">/home</unix:path>
</unix:file_state>
<unix:file_state id="oval:ssg:ste:324" version="1" operator="OR">
<unix:suid datatype="boolean">true</unix:suid>
<unix:sgid datatype="boolean">true</unix:sgid>
<unix:sticky datatype="boolean">true</unix:sticky>
<unix:gwrite datatype="boolean">true</unix:gwrite>
<unix:oread datatype="boolean">true</unix:oread>
<unix:owrite datatype="boolean">true</unix:owrite>
<unix:oexec datatype="boolean">true</unix:oexec>
</unix:file_state>
<ind:textfilecontent54_state id="oval:ssg:ste:326" version="1">
<ind:subexpression datatype="int" operation="less than or equal" var_ref="oval:ssg:var:466"/>
</ind:textfilecontent54_state>
<unix:sysctl_state id="oval:ssg:ste:339" version="1">
<unix:value datatype="int" operation="equals">1</unix:value>
</unix:sysctl_state>
<unix:uname_state comment="64 bit architecture" id="oval:ssg:ste:345" version="1">
<unix:processor_type operation="equals">x86_64</unix:processor_type>
</unix:uname_state>
<ind:textfilecontent54_state id="oval:ssg:ste:347" version="1">
<ind:subexpression datatype="int" operation="less than or equal" var_ref="oval:ssg:var:467"/>
</ind:textfilecontent54_state>
<ind:textfilecontent54_state id="oval:ssg:ste:351" version="1">
<ind:instance datatype="int">1</ind:instance>
<ind:subexpression datatype="int" operation="greater than or equal" var_ref="oval:ssg:var:468"/>
</ind:textfilecontent54_state>
<unix:file_state id="oval:ssg:ste:353" version="1">
<unix:uexec datatype="boolean">false</unix:uexec>
<unix:gread datatype="boolean">false</unix:gread>
<unix:gwrite datatype="boolean">false</unix:gwrite>
<unix:gexec datatype="boolean">false</unix:gexec>
<unix:oread datatype="boolean">false</unix:oread>
<unix:owrite datatype="boolean">false</unix:owrite>
<unix:oexec datatype="boolean">false</unix:oexec>
</unix:file_state>
<ind:textfilecontent54_state id="oval:ssg:ste:358" version="1">
<ind:subexpression datatype="string" operation="pattern match" var_ref="oval:ssg:var:456"/>
</ind:textfilecontent54_state>
<unix:uname_state comment="32 bit architecture" id="oval:ssg:ste:361" version="1">
<unix:processor_type operation="equals">i686</unix:processor_type>
</unix:uname_state>
<ind:textfilecontent54_state id="oval:ssg:ste:364" version="1">
<ind:subexpression datatype="int" operation="equals">0</ind:subexpression>
</ind:textfilecontent54_state>
<ind:textfilecontent54_state id="oval:ssg:ste:370" version="1">
<ind:instance datatype="int">1</ind:instance>
<ind:subexpression datatype="int" operation="less than or equal" var_ref="oval:ssg:var:469"/>
</ind:textfilecontent54_state>
<unix:file_state id="oval:ssg:ste:447" version="1">
<unix:type operation="equals">symbolic link</unix:type>
</unix:file_state>
<ind:textfilecontent54_state id="oval:ssg:ste:380" version="1">
<ind:subexpression datatype="int" operation="greater than or equal" var_ref="oval:ssg:var:470"/>
</ind:textfilecontent54_state>
<linux:rpminfo_state id="oval:ssg:ste:116" version="1">
<linux:version operation="pattern match">^6.*$</linux:version>
</linux:rpminfo_state>
<linux:rpminfo_state id="oval:ssg:ste:118" version="1">
<linux:version operation="pattern match">^6.*$</linux:version>
</linux:rpminfo_state>
<ind:textfilecontent54_state id="oval:ssg:ste:383" version="1">
<ind:instance datatype="int">1</ind:instance>
<ind:subexpression datatype="int" operation="less than or equal" var_ref="oval:ssg:var:471"/>
</ind:textfilecontent54_state>
<ind:variable_state id="oval:ssg:ste:385" version="1">
<ind:value operation="greater than or equal" var_ref="oval:ssg:var:472" datatype="int" var_check="at least one"/>
</ind:variable_state>
<unix:file_state id="oval:ssg:ste:450" version="1" operator="OR">
<unix:gwrite datatype="boolean">true</unix:gwrite>
<unix:owrite datatype="boolean">true</unix:owrite>
</unix:file_state>
<unix:file_state id="oval:ssg:ste:451" version="1">
<unix:type operation="equals">symbolic link</unix:type>
</unix:file_state>
<ind:textfilecontent54_state id="oval:ssg:ste:388" version="1">
<ind:subexpression datatype="int" operation="less than or equal" var_ref="oval:ssg:var:473"/>
</ind:textfilecontent54_state>
<unix:file_state id="oval:ssg:ste:390" version="1">
<unix:user_id datatype="int">0</unix:user_id>
</unix:file_state>
<unix:file_state id="oval:ssg:ste:452" version="1" operator="OR">
<unix:gwrite datatype="boolean">true</unix:gwrite>
<unix:owrite datatype="boolean">true</unix:owrite>
</unix:file_state>
<unix:file_state id="oval:ssg:ste:453" version="1">
<unix:type operation="equals">symbolic link</unix:type>
</unix:file_state>
<ind:textfilecontent54_state id="oval:ssg:ste:397" version="1">
<ind:instance datatype="int">1</ind:instance>
<ind:subexpression datatype="int" operation="greater than or equal" var_ref="oval:ssg:var:474"/>
</ind:textfilecontent54_state>
<ind:variable_state id="oval:ssg:ste:400" version="1">
<ind:value operation="greater than or equal" var_ref="oval:ssg:var:475" datatype="int" var_check="at least one"/>
</ind:variable_state>
<unix:sysctl_state id="oval:ssg:ste:406" version="1">
<unix:value datatype="int" operation="equals">1</unix:value>
</unix:sysctl_state>
<ind:textfilecontent54_state id="oval:ssg:ste:409" version="1">
<ind:instance datatype="int">1</ind:instance>
<ind:subexpression datatype="int" operation="less than or equal" var_ref="oval:ssg:var:476"/>
</ind:textfilecontent54_state>
<unix:password_state id="oval:ssg:ste:413" version="1">
<unix:password>x</unix:password>
</unix:password_state>
<unix:file_state comment="group or other has write privilege" id="oval:ssg:ste:459" version="1" operator="OR">
<unix:gwrite datatype="boolean">true</unix:gwrite>
<unix:owrite datatype="boolean">true</unix:owrite>
</unix:file_state>
<unix:file_state comment="symbolic link" id="oval:ssg:ste:460" version="1">
<unix:type operation="equals">symbolic link</unix:type>
</unix:file_state>
<ind:family_state id="oval:ssg:ste:120" version="1">
<ind:family>unix</ind:family>
</ind:family_state>
<linux:rpminfo_state id="oval:ssg:ste:122" version="1">
<linux:version operation="pattern match">^7.*$</linux:version>
</linux:rpminfo_state>
<linux:rpminfo_state id="oval:ssg:ste:124" version="1">
<linux:version operation="pattern match">^7.*$</linux:version>
</linux:rpminfo_state>
<unix:file_state id="oval:ssg:ste:420" version="1">
<unix:group_id datatype="int">0</unix:group_id>
</unix:file_state>
<ind:variable_state id="oval:ssg:ste:424" version="1">
<ind:value operation="greater than or equal" var_ref="oval:ssg:var:477" datatype="int" var_check="at least one"/>
</ind:variable_state>
<ind:textfilecontent54_state id="oval:ssg:ste:426" version="1">
<ind:instance datatype="int">1</ind:instance>
<ind:subexpression datatype="int" operation="less than or equal" var_ref="oval:ssg:var:478"/>
</ind:textfilecontent54_state>
<ind:textfilecontent54_state id="oval:ssg:ste:435" version="1">
<ind:subexpression operation="equals" var_check="all" var_ref="oval:ssg:var:479"/>
</ind:textfilecontent54_state>
</states>
<variables>
<external_variable comment="External variable for pam_cracklib minclass" datatype="int" id="oval:ssg:var:463" version="1"/>
<local_variable id="oval:ssg:var:441" datatype="int" comment="The value of last PASS_MAX_DAYS directive in /etc/login.defs" version="1">
<regex_capture pattern="PASS_MAX_DAYS\s+(\d+)">
<object_component item_field="subexpression" object_ref="oval:ssg:obj:440"/>
</regex_capture>
</local_variable>
<external_variable comment="Maximum password age" datatype="int" id="oval:ssg:var:464" version="1"/>
<external_variable comment="timeout value" datatype="int" id="oval:ssg:var:465" version="1"/>
<local_variable id="oval:ssg:var:445" datatype="string" comment="The value of last ENCRYPT_METHOD directive in /etc/login.defs" version="1">
<regex_capture pattern="ENCRYPT_METHOD\s+(\w+)">
<object_component item_field="subexpression" object_ref="oval:ssg:obj:444"/>
</regex_capture>
</local_variable>
<external_variable id="oval:ssg:var:466" datatype="int" comment="number of failed login attempts allowed" version="1"/>
<external_variable comment="External variable for pam_cracklib retry" datatype="int" id="oval:ssg:var:467" version="1"/>
<external_variable comment="External variable for pam_cracklib minlen" datatype="int" id="oval:ssg:var:468" version="1"/>
<external_variable comment="external variable for GDM login banner text" datatype="string" id="oval:ssg:var:456" version="1"/>
<external_variable comment="External variable for pam_cracklib ucredit" datatype="int" id="oval:ssg:var:469" version="1"/>
<external_variable comment="number of passwords that should be remembered" datatype="int" id="oval:ssg:var:470" version="1"/>
<external_variable comment="External variable for pam_cracklib ocredit" datatype="int" id="oval:ssg:var:471" version="1"/>
<local_variable id="oval:ssg:var:449" datatype="int" comment="The value of last PASS_WARN_AGE directive in /etc/login.defs" version="1">
<regex_capture pattern="PASS_WARN_AGE\s+(\d+)">
<object_component item_field="subexpression" object_ref="oval:ssg:obj:448"/>
</regex_capture>
</local_variable>
<external_variable comment="password expiration warning age in days" datatype="int" id="oval:ssg:var:472" version="1"/>
<external_variable comment="External variable for pam_cracklib maxrepeat" datatype="int" id="oval:ssg:var:473" version="1"/>
<external_variable comment="External variable for pam_cracklib difok" datatype="int" id="oval:ssg:var:474" version="1"/>
<local_variable id="oval:ssg:var:455" datatype="int" comment="The value of last PASS_MIN_LEN directive in /etc/login.defs" version="1">
<regex_capture pattern="PASS_MIN_LEN\s+(\d+)">
<object_component item_field="subexpression" object_ref="oval:ssg:obj:454"/>
</regex_capture>
</local_variable>
<external_variable comment="Password minimum length" datatype="int" id="oval:ssg:var:475" version="1"/>
<external_variable comment="External variable for pam_cracklib lcredit" datatype="int" id="oval:ssg:var:476" version="1"/>
<local_variable comment="Split the PATH on the : delimiter" datatype="string" id="oval:ssg:var:458" version="1">
<split delimiter=":">
<object_component item_field="value" object_ref="oval:ssg:obj:457"/>
</split>
</local_variable>
<local_variable id="oval:ssg:var:462" datatype="int" comment="The value of last PASS_MIN_DAYS directive in /etc/login.defs" version="1">
<regex_capture pattern="PASS_MIN_DAYS\s+(\d+)">
<object_component item_field="subexpression" object_ref="oval:ssg:obj:461"/>
</regex_capture>
</local_variable>
<external_variable comment="Minimum password age in days" datatype="int" id="oval:ssg:var:477" version="1"/>
<external_variable comment="External variable for pam_cracklib dcredit" datatype="int" id="oval:ssg:var:478" version="1"/>
<external_variable comment="inactivity timeout variable" datatype="string" id="oval:ssg:var:479" version="1"/>
</variables>
</oval_definitions></ds:component></ds:data-stream-collection>
xccdf_org.ssgproject.content_profile_commonfalse