###############################################################################
#                                                                             #
#
 Copyright 2019. Triad National Security, LLC. All rights reserved.          #
# This program was produced under U.S. Government contract 89233218CNA000001  #
# for Los Alamos National Labor
atory (LANL), which is operated by Triad       #
# National Security, LLC for the U.S. Department of Energy/National Nuclear   #
# Security Administration.                                                    #
#                                                                             #
# All rights in the program are reserved by Triad National Security, LLC, and #
# the U.S. Department of Energy/National Nuclear Security Administration. The #
# Government is granted for itself and others acting on its behalf a          #
# nonexclusive, paid-up, irrevocable worldwide license in this material to    #
# reproduce, prepare derivative works, distribute copies to the public,       #
# perform publicly and display publicly, and to permit others to do so.       #
#                                                                             #
###############################################################################

'''
Created on 2015/07/01

@author: Eric Ball
@change: 2015/12/07 eball Added information about REMOVEX CI to help text
@change: 2016/07/06 eball Separated fix into discrete methods
@change: 2017/06/02 bgonz12 - Change a conditional in reportUbuntu to search for
                    "manual" using regex instead of direct comparison
@change 2017/08/28 rsn Fixing to use new help text methods
@change: 2017/10/23 rsn - change to new service helper interface
@change: 2017/11/14 bgonz12 - Fix removeX dependency issue for deb systems
'''


import os
import re
import traceback
from KVEditorStonix import KVEditorStonix
from logdispatcher import LogPriority
from pkghelper import Pkghelper
from rule import Rule
from CommandHelper import CommandHelper
from ServiceHelper import ServiceHelper
from stonixutilityfunctions import iterate, readFile, writeFile, createFile
from stonixutilityfunctions import resetsecon


class DisableGUILogon(Rule):

    def __init__(self, config, environ, logger, statechglogger):
        Rule.__init__(self, config, environ, logger, statechglogger)
        self.logger = logger
        self.rulenumber = 105
        self.rulename = "DisableGUILogon"
        self.formatDetailedResults("initialize")
        self.mandatory = False
        self.applicable = {'type': 'white',
                           'family': ['linux']}

        # Configuration item instantiation
        datatype = "bool"
        key = "DISABLEX"
        instructions = "To enable this item, set the value of DISABLEX " + \
            "to True. When enabled, this rule will disable the automatic " + \
            "GUI login, and the system will instead boot to the console " + \
            "(runlevel 3). This will not remove any GUI components, and the " + \
            "GUI can still be started using the \"startx\" command."
        default = False
        self.ci1 = self.initCi(datatype, key, instructions, default)

        datatype = "bool"
        key = "LOCKDOWNX"
        instructions = "To enable this item, set the value of LOCKDOWNX " + \
            "to True. When enabled, this item will help secure X Windows by " + \
            "disabling the X Font Server (xfs) service and disabling X " + \
            "Window System Listening. This item should be enabled if X " + \
            "Windows is disabled but will be occasionally started via " + \
            "startx, unless there is a mission-critical need for xfs or " + \
            "a remote display."
        default = False
        self.ci2 = self.initCi(datatype, key, instructions, default)

        datatype = "bool"
        key = "REMOVEX"
        instructions = "To enable this item, set the value of REMOVEX " + \
            "to True. When enabled, this item will COMPLETELY remove X " + \
            "Windows from the system, and on most platforms will disable " + \
            "any currently running display manager. It is therefore " + \
            "recommended that this rule be run from a console session " + \
            "rather than from the GUI.\nREMOVEX cannot be undone."
        default = False
        self.ci3 = self.initCi(datatype, key, instructions, default)

        self.guidance = ["NSA 3.6.1.1", "NSA 3.6.1.2", "NSA 3.6.1.3",
                         "CCE 4462-8", "CCE 4422-2", "CCE 4448-7",
                         "CCE 4074-1"]
        self.iditerator = 0
        self.ph = Pkghelper(self.logger, self.environ)
        self.ch = CommandHelper(self.logger)
        self.sh = ServiceHelper(self.environ, self.logger)
        self.myos = self.environ.getostype().lower()
        self.sethelptext()

    def report(self):
        '''@author: Eric Ball

        :param self: essential if you override this definition
        :returns: bool - True if system is compliant, False if it isn't

        '''
        try:
            compliant = True
            results = ""

            if os.path.exists("/bin/systemctl"):
                self.initver = "systemd"
                compliant, results = self.reportSystemd()
            elif re.search("debian", self.myos):
                self.initver = "debian"
                compliant, results = self.reportDebian()
            elif re.search("ubuntu", self.myos):
                self.initver = "ubuntu"
                compliant, results = self.reportUbuntu()
            else:
                self.initver = "inittab"
                compliant, results = self.reportInittab()

            # NSA guidance specifies disabling of X Font Server (xfs),
            # however, this guidance seems to be obsolete as of RHEL 6,
            # and does not apply to the Debian family.
            if self.sh.auditService("xfs", _="_"):
                compliant = False
                results += "xfs is currently enabled\n"

            xremoved = True
            self.xservSecure = True
            if re.search("debian|ubuntu", self.myos):
                if self.ph.check("xserver-xorg-core"):
                    compliant = False
                    xremoved = False
                    results += "Core X11 components are present\n"
            elif re.search("opensuse", self.myos):
                if self.ph.check("xorg-x11-server"):
                    compliant = False
                    xremoved = False
                    results += "Core X11 components are present\n"
            else:
                if self.ph.check("xorg-x11-server-Xorg"):
                    compliant = False
                    xremoved = False
                    results += "Core X11 components are present\n"
            # Removing X will take xserverrc with it. If X is not present, we
            # do not need to check for xserverrc
            if not xremoved:
                self.serverrc = "/etc/X11/xinit/xserverrc"
                self.xservSecure = False
                if os.path.exists(self.serverrc):
                    serverrcText = readFile(self.serverrc, self.logger)
                    if re.search("opensuse", self.myos):
                        for line in serverrcText:
                            reSearch = r'exec (/usr/bin/)?X \$dspnum.*\$args'
                            if re.search(reSearch, line):
                                self.xservSecure = True
                                break
                    else:
                        for line in serverrcText:
                            reSearch = r'^exec (/usr/bin/)?X (:0 )?-nolisten tcp ("$@"|.?\$@)'
                            if re.search(reSearch, line):
                                self.xservSecure = True
                                break
                    if not self.xservSecure:
                        compliant = False
                        results += self.serverrc + " does not contain proper " \
                            + "settings to disable X Window System " + \
                            "Listening/remote display\n"
          