diff --git a/BUILDING.rst b/BUILDING.rst index 8328eb352..a87e8bfc1 100644 --- a/BUILDING.rst +++ b/BUILDING.rst @@ -14,7 +14,6 @@ This document contains instructions for: THE BUILD SCRIPT WILL MAKE CHANGES TO THE SYSTEM THAT MAY BE INCOMPATIBLE WITH OTHER SOFTWARE - Building on Windows =================== @@ -46,15 +45,15 @@ Building on CentOS 7 is the easiest way to get a working package for all Linux d In most cases, building on the distribution that is targeted, e.g. building on Ubuntu 20.04 to deploy on Ubuntu 20.04, will work, but the resulting package will not be as portable. -To start, clone the repository in your directory:: +To start, clone the repository in your directory: - cd ~ - git clone https://github.com/NagiosEnterprises/ncpa + cd ~ + git clone https://github.com/NagiosEnterprises/ncpa<<<<<<< HEAD Now run the setup scripts to install the requirements:: - cd ncpa/build - ./build.sh + cd ncpa/build + ./build.sh Follow the prompts to setup the system. When running the build.sh script it will setup the system and build the ncpa binary. @@ -63,23 +62,19 @@ the system and build the ncpa binary. **Install on the target Linux server** -------------------------------- - Copy the resulting ~/ncpa/build/ncpa-3.x.x-x.x86_64.rpm or ncpa_3.x.x-x_amd64.deb to the desired server and install using the appropriate package system: +Copy the resulting ~/ncpa/build/ncpa-3.x.x-x.x86_64.rpm or ncpa_3.x.x-x_amd64.deb to the desired server and install using the appropriate package system: - On CentOS/RHEL/Oracle/Amazon/Rocky:: + On CentOs/RHEL:: - yum install ./ncpa-3.x.x-1.x86_64.rpm + yum install ./ncpa-3.x.x-1.elx.x86_64.rpm - On Ubuntu 16+/Debian 9+:: + On Ubuntu/Debian:: apt install ./ncpa_3.0.0-1._amd64.deb - On Ubuntu 14/Debian 8 (not supported, but may work):: - - dpkg --force-depends -i ./ncpa_3.0.0-1._amd64.deb - On OpenSuSE/SLES:: - zypper install ./ncpa-3.x.x-1.x86_64.rpm + zypper install ./ncpa_3.0.0-1.x86_64.deb Building on MacOS diff --git a/README.rst b/README.rst index 008314e2e..2b94adddc 100644 --- a/README.rst +++ b/README.rst @@ -6,14 +6,20 @@ NCPA The *Nagios Cross-Platform Agent*; a single monitoring agent that installs on all major operating systems. NCPA allows both active checks via check_ncpa.py and passive checks via NRDP. NCPA comes with a built-in web GUI, documentation, websocket graphing, and is secured with SSL by default. +NCPA 3 Beta +--------- +The NCPA 3 beta has been released! You can download the beta via the source code in the `dev-v3-beta-01 branch `_ or by visiting the `downloads page `_ for installable packages. + Downloads --------- Current versions: -+---------+-------------+-------------------------------------------------------+ -| Current | **3.0.0** | `Downloads `_ | -+---------+-------------+-------------------------------------------------------+ ++---------+-------------+------------------------------------------------------------+ +| Current | **2.4.1** | `Downloads `_ | ++---------+-------------+------------------------------------------------------------+ +| Beta | **3.0.0** | `Downloads `_ | ++---------+-------------+------------------------------------------------------------+ `Older Versions `_ @@ -78,3 +84,4 @@ While we recommend using the pre-built version above, sometimes you may find the +------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------+ | `Building for Windows `_ | `Building for Linux `_ | `Building for Mac OS X `_ | +------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------+ + diff --git a/agent/listener/server.py b/agent/listener/server.py index 5f286b8e6..cd5618136 100755 --- a/agent/listener/server.py +++ b/agent/listener/server.py @@ -23,6 +23,7 @@ # Set whether or not a request is internal or not import socket +from hmac import compare_digest __VERSION__ = ncpa.__VERSION__ __STARTED__ = datetime.datetime.now() @@ -162,6 +163,26 @@ def is_network(ip): logging.debug(e) return False +# Securely compares strings - byte string or unicode +# Comparison is done via compare_digest() to prevent timing attacks +# If both items evaluate to false, they match. This makes it easier to handle +# empty strings or variables which may have "NoneType" +def secure_compare(item1, item2): + is_match = False + + # Convert to unicode, if necessary, both items must have the same encoding + if item1 and not isinstance(item1, unicode): + item1 = item1.decode('utf-8') + if item2 and not isinstance(item2, unicode): + item2 = item2.decode('utf-8') + + if item1 and item2 and compare_digest(item1, item2): + is_match = True + elif not item1 and not item2: + is_match = True + + return is_match + # ------------------------------ # Authentication Wrappers @@ -280,16 +301,17 @@ def requires_token_or_auth(f): def token_auth_decoration(*args, **kwargs): ncpa_token = listener.config['iconfig'].get('api', 'community_string') token = request.values.get('token', None) + token_valid = secure_compare(token, ncpa_token) # This is an internal call, we don't check if __INTERNAL__ is True: pass - elif session.get('logged', False) or token == ncpa_token: + elif session.get('logged', False) or token_valid: pass elif token is None: session['redirect'] = request.url return redirect(url_for('login')) - elif token != ncpa_token: + elif not token_valid: return error(msg='Incorrect credentials given.') return f(*args, **kwargs) @@ -369,6 +391,9 @@ def login(): url = session.get('redirect', None) token = request.values.get('token', None) + token_valid = secure_compare(token, ncpa_token) + token_is_admin = secure_compare(token, admin_password) + template_args = { 'hide_page_links': True, 'message': message, 'url': url, @@ -378,9 +403,9 @@ def login(): session['message'] = None # Do actual authentication check - if token == ncpa_token and not admin_auth_only: + if not admin_auth_only and token_valid: session['logged'] = True - elif token == admin_password and admin_password is not None: + elif admin_password is not None and token_is_admin: session['logged'] = True session['admin_logged'] = True @@ -394,10 +419,10 @@ def login(): # Display error messages depending on what was given if token is not None: if not admin_auth_only: - if token != ncpa_token or token != admin_password: + if not token_valid and not token_is_admin: template_args['error'] = 'Invalid token or password.' else: - if token == ncpa_token: + if token_valid: template_args['error'] = 'Admin authentication only.' else: template_args['error'] = 'Invalid password.' @@ -414,15 +439,16 @@ def admin_login(): # Admin password admin_password = get_config_value('listener', 'admin_password', None) + password = request.values.get('password', None) + password_valid = secure_compare(password, admin_password) message = session.get('message', None) - password = request.values.get('password', None) template_args = { 'hide_page_links': False, 'message': message } session['message'] = None - if password == admin_password and admin_password is not None: + if admin_password is not None and password_valid: session['admin_logged'] = True return redirect(url_for('admin')) elif password is not None: diff --git a/build/build.sh b/build/build.sh index 9cf1f43ee..77e75b35c 100755 --- a/build/build.sh +++ b/build/build.sh @@ -190,6 +190,27 @@ if command -v git > /dev/null; then echo "GIT_HASH_FILE: $GIT_HASH_FILE" fi +# Add file with current GIT hash to build +GIT_LONG="Not built under GIT" +GIT_HASH_FILE="NoGIT.githash" + +if command -v git > /dev/null; then + GIT_LONG=$(git rev-parse HEAD) + GIT_SHORT=$(git rev-parse --short HEAD) + GIT_UNCOMMITTED=$(git status --untracked-files=no --porcelain) + echo "GIT_UNCOMMITTED: $GIT_UNCOMMITTED" + if [ "$GIT_UNCOMMITTED" ]; then + GIT_LONG="$GIT_LONG++ compiled with uncommitted changes" + GIT_SHORT="$GIT_SHORT++" + fi + GIT_HASH_FILE="git-$GIT_SHORT.githash" + echo "GIT_LONG: $GIT_LONG" + echo "GIT_SHORT: $GIT_SHORT" + echo "GIT_HASH_FILE: $GIT_HASH_FILE" +fi +# ls $AGENT_DIR/*.githash >/dev/null && rm $AGENT_DIR/*.githash +# echo $GIT_LONG > "$AGENT_DIR/$GIT_HASH_FILE" + ( echo -e "\nBuilding NCPA binaries..." cd $AGENT_DIR diff --git a/build/linux/el9-ncpa.spec b/build/linux/el9-ncpa.spec new file mode 100644 index 000000000..32fe9f412 --- /dev/null +++ b/build/linux/el9-ncpa.spec @@ -0,0 +1,192 @@ +Name: ncpa +Version: __VERSION__ +Release: 1%{?dist} +Vendor: Nagios Enterprises, LLC +Summary: A cross-platform active and passive monitoring agent +BuildRoot: __BUILDROOT__/BUILDROOT/ +Prefix: /usr/local +Group: Network/Monitoring +License: Nagios Community Software License Version 1.3 +URL: https://www.nagios.org/ncpa/help.php +Source: ncpa-%{version}.tar.gz +AutoReqProv: no + +%description +The Nagios Cross-Platform Agent is used with Nagios XI and Nagios Core to run active +and/or passive checks on any operating system. Installs with zero requirements using a +bundled version of Python. + +%global debug_package %{nil} +%global _build_id_links alldebug + +%prep +%setup -q + +%build +%define _python_bytecompile_errors_terminate_build 0 + +%install +rm -rf %{buildroot} +mkdir -p %{buildroot}/usr/local +cp -rf $RPM_BUILD_DIR/ncpa-%{version} %{buildroot}/usr/local/ncpa +mkdir -p %{buildroot}/usr/local/ncpa/var/run +mkdir -p %{buildroot}/etc/init.d +chown -R nagios:nagios %{buildroot}/usr/local/ncpa +install -m 755 $RPM_BUILD_DIR/ncpa-%{version}/build_resources/listener_init %{buildroot}/etc/init.d/ncpa_listener +install -m 755 $RPM_BUILD_DIR/ncpa-%{version}/build_resources/passive_init %{buildroot}/etc/init.d/ncpa_passive + +mkdir -p %{buildroot}/usr/lib/systemd/system +install -m 640 $RPM_BUILD_DIR/ncpa-%{version}/build_resources/ncpa_listener.service %{buildroot}/usr/lib/systemd/system/ncpa_listener.service +install -m 640 $RPM_BUILD_DIR/ncpa-%{version}/build_resources/ncpa_passive.service %{buildroot}/usr/lib/systemd/system/ncpa_passive.service + +%clean +rm -rf %{buildroot} + +%pre +if command -v systemctl > /dev/null +then + systemctl stop ncpa_listener &> /dev/null || true + systemctl stop ncpa_passive &> /dev/null || true +else + service ncpa_listener stop &> /dev/null || true + service ncpa_passive stop &> /dev/null || true +fi + +if ! getent group nagios > /dev/null +then + groupadd -r nagios +fi + +if ! getent passwd nagios > /dev/null +then + useradd -r -g nagios nagios +else + %if 0%{?suse_version} && 0%{?suse_version} < 1210 + usermod -A nagios nagios + %else + usermod -a -G nagios nagios + %endif +fi + +%post +if command -v chkconfig > /dev/null +then + chkconfig --level 3,5 --add ncpa_listener &> /dev/null + chkconfig --level 3,5 --add ncpa_passive &> /dev/null +elif command -v systemctl > /dev/null +then + systemctl enable ncpa_listener.service &> /dev/null + systemctl enable ncpa_passive.service &> /dev/null +elif command -v update-rc.d > /dev/null +then + update-rc.d ncpa_listener defaults &> /dev/null + update-rc.d ncpa_passive defaults &> /dev/null +fi + +if [ -z $RPM_INSTALL_PREFIX ] +then + RPM_INSTALL_PREFIX="/usr/local" +fi + +# Set the directory inside the init scripts +dir=$RPM_INSTALL_PREFIX/ncpa +sed -i "s|_BASEDIR_|BASEDIR=\x22$dir\x22|" /etc/init.d/ncpa_listener +sed -i "s|_BASEDIR_|BASEDIR=\x22$dir\x22|" /etc/init.d/ncpa_passive + +# Remove empty cert and key files +if [ -f $RPM_INSTALL_PREFIX/ncpa/ncpa.crt ] +then + rm $RPM_INSTALL_PREFIX/ncpa/ncpa.crt +fi + +if [ -f $RPM_INSTALL_PREFIX/ncpa/ncpa.key ] +then + rm $RPM_INSTALL_PREFIX/ncpa/ncpa.key +fi + +if command -v systemctl > /dev/null +then + systemctl daemon-reload + systemctl start ncpa_listener + systemctl start ncpa_passive +else + service ncpa_listener start + service ncpa_passive start +fi + +%preun +# Only stop on actual uninstall not upgrades +if [ "$1" != "1" ] +then + if command -v systemctl > /dev/null + then + systemctl stop ncpa_listener + systemctl stop ncpa_passive + else + service ncpa_listener stop + service ncpa_passive stop + fi +fi + +%postun +# Only do systemctl daemon-reload after uninstall +if [ "$1" == "0" ] +then + if command -v systemctl > /dev/null + then + systemctl daemon-reload + fi +fi + +%posttrans +if [ -z $RPM_INSTALL_PREFIX ] +then + RPM_INSTALL_PREFIX="/usr/local" +fi + +# Only run on upgrades (restart fixes db removal issue) +if [ ! -f "$RPM_INSTALL_PREFIX/ncpa/var/ncpa.db" ] +then + if command -v systemctl > /dev/null + then + systemctl restart ncpa_listener + systemctl restart ncpa_passive + else + service ncpa_listener restart + service ncpa_passive restart + fi +fi + +%files +%defattr(0755,root,root,0755) +%dir /usr/local/ncpa +/usr/local/ncpa/ncpa_listener +/usr/local/ncpa/ncpa_passive +/etc/init.d/ncpa_listener +/etc/init.d/ncpa_passive + +%defattr(0755,root,root,0755) +/usr/local/ncpa/*.so* + +%defattr(0644,root,root,0755) +/usr/local/ncpa/*.py +/usr/local/ncpa/*.zip +/usr/local/ncpa/*.githash +/usr/local/ncpa/build_resources +/usr/local/ncpa/listener +/usr/local/ncpa/plugins + +%defattr(0664,root,nagios,0775) +%dir /usr/local/ncpa/etc +%dir /usr/local/ncpa/etc/ncpa.cfg.d +/usr/local/ncpa/var + +%defattr(0640,root,nagios,0755) +%config(noreplace) /usr/local/ncpa/etc/ncpa.cfg +%config(noreplace) /usr/local/ncpa/etc/ncpa.cfg.d/example.cfg +/usr/local/ncpa/etc/ncpa.cfg.sample +/usr/local/ncpa/etc/ncpa.cfg.d/README.txt + +%defattr(0640,root,nagios,0755) +/usr/lib/systemd/system/ncpa_listener.service +/usr/lib/systemd/system/ncpa_passive.service diff --git a/build/linux/suse-ncpa.spec b/build/linux/suse-ncpa.spec new file mode 100644 index 000000000..8f01137e0 --- /dev/null +++ b/build/linux/suse-ncpa.spec @@ -0,0 +1,183 @@ +Name: ncpa +Version: __VERSION__ +Release: sle15 +Vendor: Nagios Enterprises, LLC +Summary: A cross-platform active and passive monitoring agent +BuildRoot: __BUILDROOT__/BUILDROOT/ +Prefix: /usr/local +Group: Network/Monitoring +License: Nagios Community Software License Version 1.3 +URL: https://www.nagios.org/ncpa/help.php +Source: ncpa-%{version}.tar.gz + +Requires: insserv-compat + +AutoReqProv: no + +%description +The Nagios Cross-Platform Agent is used with Nagios XI and Nagios Core to run active +and/or passive checks on any operating system. Installs with zero requirements using a +bundled version of Python. + +%global debug_package %{nil} +%global _build_id_links alldebug + +%prep +%setup -q + +%build +%define _python_bytecompile_errors_terminate_build 0 + +%install +rm -rf %{buildroot} +mkdir -p %{buildroot}/usr/local +cp -rf $RPM_BUILD_DIR/ncpa-%{version} %{buildroot}/usr/local/ncpa +mkdir -p %{buildroot}/usr/local/ncpa/var/run +mkdir -p %{buildroot}/etc/init.d +chown -R nagios:nagios %{buildroot}/usr/local/ncpa +install -m 755 $RPM_BUILD_DIR/ncpa-%{version}/build_resources/listener_init %{buildroot}/etc/init.d/ncpa_listener +install -m 755 $RPM_BUILD_DIR/ncpa-%{version}/build_resources/passive_init %{buildroot}/etc/init.d/ncpa_passive + +%clean +rm -rf %{buildroot} + +%pre +if command -v systemctl > /dev/null +then + systemctl stop ncpa_listener &> /dev/null || true + systemctl stop ncpa_passive &> /dev/null || true +else + service ncpa_listener stop &> /dev/null || true + service ncpa_passive stop &> /dev/null || true +fi + +if ! getent group nagios > /dev/null +then + groupadd -r nagios +fi + +if ! getent passwd nagios > /dev/null +then + useradd -r -g nagios nagios +else + %if 0%{?suse_version} && 0%{?suse_version} < 1210 + usermod -A nagios nagios + %else + usermod -a -G nagios nagios + %endif +fi + +%post +if command -v chkconfig > /dev/null +then + chkconfig --level 3,5 --add ncpa_listener &> /dev/null + chkconfig --level 3,5 --add ncpa_passive &> /dev/null +elif command -v update-rc.d > /dev/null +then + update-rc.d ncpa_listener defaults &> /dev/null + update-rc.d ncpa_passive defaults &> /dev/null +fi + +if [ -z $RPM_INSTALL_PREFIX ] +then + RPM_INSTALL_PREFIX="/usr/local" +fi + +# Set the directory inside the init scripts +dir=$RPM_INSTALL_PREFIX/ncpa +sed -i "s|_BASEDIR_|BASEDIR=\x22$dir\x22|" /etc/init.d/ncpa_listener +sed -i "s|_BASEDIR_|BASEDIR=\x22$dir\x22|" /etc/init.d/ncpa_passive + +# Remove empty cert and key files +if [ -f $RPM_INSTALL_PREFIX/ncpa/ncpa.crt ] +then + rm $RPM_INSTALL_PREFIX/ncpa/ncpa.crt +fi + +if [ -f $RPM_INSTALL_PREFIX/ncpa/ncpa.key ] +then + rm $RPM_INSTALL_PREFIX/ncpa/ncpa.key +fi + +if command -v systemctl > /dev/null +then + systemctl daemon-reload + systemctl start ncpa_listener + systemctl start ncpa_passive +else + service ncpa_listener start + service ncpa_passive start +fi + +%preun +# Only stop on actual uninstall not upgrades +if [ "$1" != "1" ] +then + if command -v systemctl > /dev/null + then + systemctl stop ncpa_listener + systemctl stop ncpa_passive + else + service ncpa_listener stop + service ncpa_passive stop + fi +fi + +%postun +# Only do systemctl daemon-reload after uninstall +if [ "$1" == "0" ] +then + if command -v systemctl > /dev/null + then + systemctl daemon-reload + fi +fi + +%posttrans +if [ -z $RPM_INSTALL_PREFIX ] +then + RPM_INSTALL_PREFIX="/usr/local" +fi + +# Only run on upgrades (restart fixes db removal issue) +if [ ! -f "$RPM_INSTALL_PREFIX/ncpa/var/ncpa.db" ] +then + if command -v systemctl > /dev/null + then + systemctl restart ncpa_listener + systemctl restart ncpa_passive + else + service ncpa_listener restart + service ncpa_passive restart + fi +fi + +%files +%defattr(0755,root,root,0755) +%dir /usr/local/ncpa +/usr/local/ncpa/ncpa_listener +/usr/local/ncpa/ncpa_passive +/etc/init.d/ncpa_listener +/etc/init.d/ncpa_passive + +%defattr(0755,root,root,0755) +/usr/local/ncpa/*.so* + +%defattr(0644,root,root,0755) +/usr/local/ncpa/*.py +/usr/local/ncpa/*.zip +/usr/local/ncpa/*.githash +/usr/local/ncpa/build_resources +/usr/local/ncpa/listener +/usr/local/ncpa/plugins + +%defattr(0664,root,nagios,0775) +%dir /usr/local/ncpa/etc +%dir /usr/local/ncpa/etc/ncpa.cfg.d +/usr/local/ncpa/var + +%defattr(0640,root,nagios,0755) +%config(noreplace) /usr/local/ncpa/etc/ncpa.cfg +%config(noreplace) /usr/local/ncpa/etc/ncpa.cfg.d/example.cfg +/usr/local/ncpa/etc/ncpa.cfg.sample +/usr/local/ncpa/etc/ncpa.cfg.d/README.txt diff --git a/build/resources/macosreadme.txt b/build/resources/macosreadme.txt index d28d4d504..8fae47a2e 100644 --- a/build/resources/macosreadme.txt +++ b/build/resources/macosreadme.txt @@ -20,4 +20,4 @@ This is accomplished by stopping then starting the service. Uninstalling NCPA 1. On the command line, enter: - sudo zsh /usr/local/ncpa/uninstall.sh \ No newline at end of file + sudo zsh /usr/local/ncpa/uninstall.sh diff --git a/build/resources/require.txt b/build/resources/require.txt index 1607f9b4d..ae76867c0 100644 --- a/build/resources/require.txt +++ b/build/resources/require.txt @@ -5,9 +5,9 @@ Jinja2 flask werkzeug docutils -pyOpenSSL -cryptography -gevent +pyOpenSSL==19.1 +cryptography==2.8 +gevent==1.2.2 gevent-websocket cffi appdirs