Current File : //bin/compliance
#!/usr/bin/python2.7 -E

#
# Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
#

#
# This program provides information about installed compliance
# benchmarks and allows the user to verify against them
# and generate result reports and compliance guides.
#
# It has the following commands:
#       list [-a] [-b] [-t] [-v] [-p]
#       list -b [-v] [-p] [benchmark...]
#       list -a [-v] [assessment...]
#       guide [-p profile] [-b benchmark] [-o file]
#       guide -a
#       assess [-p profile] [-b benchmark] [-a assessment]
#       assess -t tailoring [-a assessment]
#       report [-f format] [-s what] [-a assessment] [-o file]
#       delete assessment
#       tailor [-t tailoring] [subcommand]
#       compliance set-policy [-b benchmark [-p profile]] [-t tailoring]
#       compliance get-policy
#       help
#

import errno
import fcntl
import getopt
import gettext
import locale
import os
import os.path as path
import re
import signal
import shutil
import solaris.zones as zones
import sys
import time

# import compliance modules
from compliance.common import *
import compliance.smf_util as smf_util
import compliance.tailor as tailor
import compliance.xccdf_util as xccdf_util

_ = gettext.gettext
opt_verbose = 0


def usage(m):
    f = sys.stderr
    p = progname

    sys.stdout.flush()
    if m:
        print >> f, m
    print >> f, _("Usage:")
    print >> f, _("\t%s list [-a] [-b] [-p] [-t] [-v]") % p
    print >> f, _("\t%s list -b [-v] [-p] [benchmark ...]") % p
    print >> f, _("\t%s list -a [-v] [assessment ...]") % p
    print >> f, _("\t%s guide [-p profile] [-b benchmark] [-o file]") % p
    print >> f, _("\t%s guide -a") % p
    print >> f, _("\t%s assess [-b benchmark] [-p profile] [-a assessment]") % p
    print >> f, _("\t%s assess -t tailoring [-a assessment]") % p
    fmt = _("\t%s report [-f format] [-s what] [-a assessment] [-o file]")
    print >> f, fmt % p
    print >> f, _("\t%s delete assessment") % p
    print >> f, _("\t%s tailor [-t tailoring] [subcommand]") % p
    fmt = _("\t%s set-policy [-b benchmark [-p profile]] [-t tailoring]")
    print >> f, fmt % p
    print >> f, _("\t%s get-policy") % p
    exit(m and 1)


#
# get options for the particular command
#
def getcmdopt(options):
    try:
        opts, pargs = getopt.getopt(sys.argv[2:], options)
    except getopt.GetoptError as e:
        usage(e)
    return (opts, pargs)


#
#  compliance list [-b [-p] [profile]] [-a assessment]
#
def do_list():
    """
    process list command
    """
    exit_val = 0
    opts, pargs = getcmdopt("abptv")
    opt_a = False
    opt_b = False
    opt_p = False
    opt_t = False
    global opt_verbose
    for opt, arg in opts:
        if opt == '-a':
            opt_a = True
        elif opt == '-b':
            opt_b = True
        elif opt == '-p':
            opt_p = True
        elif opt == '-t':
            opt_t = True
        elif opt == '-v':
            opt_verbose += 1
    if pargs:
        if not any((opt_b, opt_a)):
            usage(_("Extra arguments require -b or -a"))
        if opt_a and any((opt_b, opt_p)):
            usage(_("Extra arguments used with -a and either -b or -p"))
        if opt_t:
            usage(_("Extra arguments can't be used with -t"))

    # list benchmarks
    if any((opt_b, opt_p)) or not any((opt_a, opt_t)):
        benchinfo = []
        indent = ""
        sepr = " "
        if not any((opt_b, opt_p)) or any((opt_a, opt_t)):
            print _("Benchmarks:")
            indent = "\t"
            sepr = "\n"
        if opt_p or opt_verbose:
            indent = ""
            sepr = "\n"
        benchmarks = xccdf_util.bench_list()
        if len(pargs):
            for arg in pargs:
                if benchmarks.count(arg) == 0:
                    if path.isabs(arg):
                        benchmarks.append(arg)
                    else:
                        print >> sys.stderr, _("No benchmark '%s' found") % arg
                        exit_val = 1
        for benchmark in benchmarks:
            xccdf = benchmark
            if not path.isabs(benchmark):
                xccdf = xccdf_util.bench_path(benchmark)

            if len(pargs) and pargs.count(benchmark) == 0:
                continue
            info = benchmark

            try:
                collections = xccdf_util.xccdf_collect(filename=xccdf)
            except Exception as e:
                print >> sys.stderr, e
                continue

            if opt_p:
                info += ":\t"
                proflist = [p.id for p in collections["Profile"] if p.id]
                if len(proflist):
                    info += strjoin(", ", proflist)
                else:
                    info += _("<No profiles specified>")
            if opt_verbose:
                b = collections["Benchmark"][0]
                if b.title:
                    info += "\n\t\t" + b.title
            if opt_verbose > 1:
                info += "\n\t"
                infolist = [r.title for r in collections["Rule"] if r.title]
                if len(infolist):
                    info += strjoin("\n\t", infolist)
            benchinfo.append(info)
        if len(benchmarks):
            if len(benchinfo):
                benchinfo.sort()
                print indent + strjoin(sepr + indent, benchinfo)
        else:
            print indent + _("No benchmarks available")

    # list assessments
    if opt_a or not any((opt_b, opt_p, opt_t)):
        indent = ""
        sepr = "\n"
        if not opt_a or any((opt_b, opt_p, opt_t)):
            print _("Assessments:")
            indent = "\t"
        if opt_verbose:
            indent = ""
        try:
            assessments = os.listdir(ASSESSMENTS)
        except:
            assessments = []
        if len(pargs):
            for arg in pargs:
                if assessments.count(arg) == 0:
                    print >> sys.stderr, _("No assessment '%s' found") % arg
                    exit_val = 1
        assessmentinfo = []
        for assessment in assessments:
            if len(pargs) and pargs.count(assessment) == 0:
                continue
            info = assessment
            if opt_verbose:
                info += ":\t"
                try:
                    reports = os.listdir(path.join(ASSESSMENTS, assessment))
                except:
                    reports = []
                if len(reports):
                    reports.sort()
                    info += strjoin(" ", reports)
                else:
                    info += _("No reports have been generated")
            assessmentinfo.append(info)
        if len(assessments):
            if len(assessmentinfo):
                assessmentinfo.sort()
                print indent + strjoin(sepr + indent, assessmentinfo)
        else:
            print indent + _("No assessments available")

    # list tailorings
    if opt_t:
        if any((opt_a, opt_b, opt_p)):
            print _("Tailorings:")
        tailor.list_tailorings(opt_verbose)

    exit(exit_val)


# get file mtime
def getmtime(fpath, mtime=0):
    try:
        statbuf = os.stat(fpath)
        mtime = statbuf.st_mtime
    except:
        pass
    return mtime


#
#  create a new process
#
def newproc():
    try:
        child = os.fork()
    except Exception as e:
        fatal(3, _("Cannot create child process: %s") % e)
    return child


#
#  print exec file name and arguments
#
def printexecargs(f, a):
    print >> f, "+", a[0], strjoin(" ", a[1:], "'")


#
#  compliance guide [-a] [-p profile] [-b benchmark] [-o file]
#
def do_guide():
    """
    process guide command
    """
    opts, pargs = getcmdopt("ab:o:p:qv")
    opt_a = None
    opt_b = None
    opt_o = None
    opt_p = None
    global opt_verbose
    for opt, arg in opts:
        if (opt == '-a'):
            opt_a = True
        if (opt == '-b'):
            opt_b = arg
        elif (opt == '-o'):
            opt_o = arg
        elif (opt == '-p'):
            opt_p = arg
        elif (opt == '-v'):
            opt_verbose += 1
    if not service and len(pargs) > 0:
        usage(_("Unrecognized parameters specified"))
    if opt_a and (opt_b or opt_o or opt_p):
        usage(_("Option -a cannot be used with other options"))

    guides_locked = []

    def lock_guides():
        if guides_locked:
            return
        lock = path.join(GUIDES, ".lock")
        try:
            lockf = open(lock, 'w')
            fcntl.lockf(lockf.fileno(), fcntl.LOCK_EX | fcntl.LOCK_NB, 1, 1, 0)
            guides_locked.append(True)
        except Exception as e:
            # no service error
            fatal(serviceOK(1), _("Cannot lock guides storage: %s") % str(e))

    def guide_path(benchmark, profile):
        gfile = benchmark
        if profile:
            gfile += "." + profile
        gfile += ".html"
        return path.join(GUIDES, gfile)

    def gen_guide(xccdf, profile, gfile):
        myargv = [OSCAP, "xccdf", "generate"]
        myargv.append("guide")
        if profile:
            myargv.extend(["--profile", profile])
        myargv.extend(["--output", gfile, xccdf])
        if opt_verbose:
            printexecargs(sys.stderr, myargv)
        status = os.spawnv(os.P_WAIT, myargv[0], myargv)
        return os.WIFEXITED(status) and os.WEXITSTATUS(status) == 0

    if opt_a or service:
        #
        # process all installed benchmarks and associated profiles
        #    as a service process, silently give up
        #    if we can't create directories or lock guides
        #
        if not path.isdir(GUIDES):
            create_shared_dirs(GUIDES, "guides")
        lock_guides()
        benchmarks = xccdf_util.bench_list()
        for benchmark in benchmarks:
            xccdf = xccdf_util.bench_path(benchmark)
            xccdftime = getmtime(xccdf, time.time())
            guidefile = guide_path(benchmark, None)
            guidetime = getmtime(guidefile)
            if guidetime > xccdftime:
                if not service:
                    print guidefile
            elif gen_guide(xccdf, None, guidefile):
                print guidefile
            else:
                continue

            proflist = xccdf_util.benchmark_profiles(xccdf)
            for profile in proflist:
                guidefile = guide_path(benchmark, profile)
                guidetime = getmtime(guidefile)
                if guidetime > xccdftime:
                    if not service:
                        print guidefile
                elif gen_guide(xccdf, profile, guidefile):
                    print guidefile
        return

    #
    # generate a single guide specified by options
    #
    if not opt_b:
        opt_b = "solaris"
    xccdf = opt_b
    if not path.isabs(opt_b):
        xccdf = xccdf_util.bench_path(opt_b)
    if not path.isfile(xccdf):
        fatal(1, _("Benchmark tests file not found: %s") % xccdf)
    if opt_p:
        proflist = xccdf_util.benchmark_profiles(xccdf)
        if opt_p not in proflist:
            fatal(1, _("Benchmark %(b)s has no '%(p)s' profile") %
                  {"b": opt_b, "p": opt_p})

    if opt_o:
        guidefile = opt_o
        ruid = os.getuid()
        if os.geteuid() != ruid:
            # drop privileges before accessing user-specified pathname
            os.setreuid(ruid, ruid)
    else:
        if not path.isdir(GUIDES):
            create_shared_dirs(GUIDES, "guides")
        gfile = opt_b
        if opt_p:
            gfile += "." + opt_p
        gfile += ".html"
        guidefile = path.join(GUIDES, gfile)
        if not path.isfile(guidefile):
            lock_guides()
    if not opt_o and path.isfile(guidefile) or gen_guide(xccdf, opt_p,
                                                         guidefile):
        print guidefile
        exit(0)
    else:
        print _("Unable to create guide file: %s") % guidefile
        exit(1)


#
#  compliance assess [-p profile] [-b benchmark] [-a assessment]
#
def do_assess():
    """
    process assess command
    """
    opts, pargs = getcmdopt("a:b:p:qt:v")
    opt_a = None
    opt_b = None
    opt_p = None
    opt_q = False
    opt_t = None

    global opt_verbose
    for opt, arg in opts:
        if (opt == '-a'):
            opt_a = arg
        elif (opt == '-b'):
            opt_b = arg
        elif (opt == '-p'):
            opt_p = arg
        elif (opt == '-q'):
            opt_q = True
        elif (opt == '-t'):
            opt_t = arg
        elif (opt == '-v'):
            opt_verbose += 1

    user = realuser()
    if not haveauth(AUTH_ASSESS, user):
        fatal(1, _("User %(u)s lacks authorization %(a)s") %
              {"u": user, "a": AUTH_ASSESS})

    if not any((opt_b, opt_p, opt_t)):
        (opt_b, opt_p, opt_t) = smf_util.get_policy()

    msgs = []
    if opt_t:
        if opt_b:
            opt_t = "%s/%s" % (opt_b, opt_t)
            opt_b = None
        if opt_p:
            usage(_("Option -t cannot be used with -p option"))
        # compute benchmark and profile from tailoring
        (opt_b, opt_p, tpath, msgs) = tailor.getassessopts(opt_t)
        if not opt_b or not opt_p:
            fatal(1, _("Unable to use tailoring '%(t)s': %(m)s") %
                  {"t": opt_t, "m": msgs})
    if not opt_b:
        opt_b = "solaris"

    xccdf = xccdf_util.bench_path(opt_b)
    if not path.isfile(xccdf):
        fatal(1, _("Benchmark tests file not found: %s") % xccdf)

    if not opt_p:
        proflist = xccdf_util.benchmark_profiles(xccdf)
        if len(proflist):
            opt_p = proflist[0]
    if len(pargs) > 0:
        usage(_("Unrecognized parameters specified"))

    if not opt_a:
        timept = time.time()
        now = time.localtime(timept)
        if opt_t:
            opt_a = re.sub("/", "-", opt_t)
        else:
            opt_a = opt_b
            if opt_p:
                opt_a += "." + opt_p
        opt_a += time.strftime(".%F,%R", now)
        if not opt_q:
            print _("Assessment will be named '%s'") % opt_a
    if re.search("/", opt_a):
        fatal(1, _("Invalid assessment name: '%s'") % opt_a)
    assessmentrep = path.join(ASSESSMENTS, opt_a)
    if path.isdir(assessmentrep):
        fatal(1, _("Assessment repository already exists: %s") % assessmentrep)
    else:
        create_shared_dirs(COMPLIANCE_VAR, "compliance")
        # make the assessments and assessment directories mode 0711
        create_shared_dirs(assessmentrep, "assessment", umask=0066)
    try:  # set isglobalzone indicator file
        isgzpath = path.join(COMPLIANCE_VAR, ".isglobalzone")
        if zones.getzoneid() == 0:
            isgzfile = open(isgzpath, "w+")
            isgzfile.close()
        else:
            os.remove(isgzpath)
    except:
        pass
    log = path.join(assessmentrep, "log")
    results = path.join(assessmentrep, RESULTS)
    report = path.join(assessmentrep, REPORT)

    evalargv = [OSCAP, "xccdf", "eval"]
    if opt_t:
        evalargv.extend(["--tailoring-file", tpath])
    if opt_p:
        evalargv.extend(["--profile", opt_p])
    evalargv.extend(["--results", results])
    evalargv.extend(["--report", report])
    evalargv.append(xccdf)

    sys.stdout.flush()
    logf = None
    try:
        logf = open(log, 'w')
        os.fchmod(logf.fileno(), 0644)
        # lock usage -
        #    byte 0: assessment active
        #    byte 1: directory contents being updated
        fcntl.lockf(logf.fileno(), fcntl.LOCK_EX, 2, 0, 0)
        printexecargs(logf, evalargv)
        for m in msgs:
            print >> logf, m
        logf.flush()
    except:
        fatal(3, _("Can't establish log: '%s'") % log)
    for m in msgs:
        print >> sys.stderr, m
    sys.stderr.flush()

    if not opt_q:
        teeargv = ["/usr/bin/tee", "-ai", log]
        teeinfd, evaloutfd = os.pipe()
        evalout = os.fdopen(evaloutfd, "w")

        teechild = newproc()
        if teechild == 0:
            os.dup2(teeinfd, sys.stdin.fileno())
            evalout.close()
            try:
                os.execv(teeargv[0], teeargv)
            except Exception, e:
                fatal(3, _("Failed to execute: %(c)s: %(e)s") %
                      {"c": strjoin(" ", teeargv, "'"), "e": e})
        os.close(teeinfd)
    else:
        evalout = logf

    evalchild = newproc()
    if evalchild == 0:
        os.dup2(evalout.fileno(), sys.stdout.fileno())
        if not opt_q:
            os.dup2(evalout.fileno(), sys.stderr.fileno())
        try:
            os.execv(evalargv[0], evalargv)
        except Exception, e:
            fatal(3, _("Failed to execute: %(c)s: %(e)s") %
                  {"c": strjoin(" ", evalargv, "'"), "e": e})
    evalout.close()

    # wait for teechild, evalchild
    sigint_handler = signal.signal(signal.SIGINT, signal.SIG_IGN)
    if not opt_q:
        _proc, status = os.waitpid(teechild, 0)
    _proc, status = os.waitpid(evalchild, 0)
    signal.signal(signal.SIGINT, sigint_handler)
    if not os.WIFEXITED(status):
        fatal(3, _("Execution failure: %s") % strjoin(" ", evalargv, "'"))
    eval_status = os.WEXITSTATUS(status)

    if not opt_q:
        print _("Assessment %s completed") % opt_a
    elif eval_status == 2:
        # oscap's exit code for successful run with failures
        eval_status = 0

    exit(eval_status)


#
#  compliance report [-f format] [-a assessment]
#
def do_report():
    """
    process report command
    """
    opts, pargs = getcmdopt("a:f:o:s:v")
    opt_a = None
    opt_f = None
    opt_o = None
    opt_s = None
    global opt_verbose
    for opt, arg in opts:
        if (opt == '-a'):
            opt_a = arg
        elif (opt == '-f'):
            opt_f = arg
        elif (opt == '-o'):
            opt_o = arg
        elif (opt == '-s'):
            opt_s = arg
        elif (opt == '-v'):
            opt_verbose += 1

    def bad_assessment(_rfile):
        print (_("The assessment '%s' has a corrupted repository.") % opt_a)
        print (_("Please delete and retake the assessment."))
        return 0

    def do_html(rfile):
        xccdf = path.join(assessmentrep, RESULTS)
        myargv = [OSCAP, "xccdf", "generate"]
        myargv.append("report")
        if opt_s:
            myargv.extend(["--show", opt_s])
        myargv.extend(["--output", rfile, xccdf])
        if opt_verbose:
            printexecargs(sys.stderr, myargv)
        status = os.spawnv(os.P_WAIT, myargv[0], myargv)
        return os.WIFEXITED(status) and os.WEXITSTATUS(status) == 0
    FORMATS = (  # (option,    filename,   function)
        ("html",     REPORT,     do_html),
        ("log",      "log",      bad_assessment),
        ("xccdf",    RESULTS,    bad_assessment))

    if not opt_f:
        opt_f = "html"
    if opt_s and opt_f != "html":
        usage(_("Use of -s option only permitted with html format"))
    try:
        _fname, ffile, ffunc = [f for f in FORMATS if f[0] == opt_f][0]
    except Exception as _e:
        fnames = [f[0] for f in FORMATS]
        usage(_("Unrecognized format request '%(o)s', valid choices: %(c)s") %
              {"o": opt_f, "c": strjoin(", ", fnames)})
    if len(pargs) > 0:
        usage(_("Unrecognized parameters specified"))
    if not opt_a:
        # scan assessments, find newest log
        newesttime = None
        try:
            assessments = os.listdir(ASSESSMENTS)
        except:
            assessments = []
        for assessment in assessments:
            try:
                logpath = path.join(ASSESSMENTS, assessment, "log")
                logtime = path.getctime(logpath)
            except:
                continue
            if not newesttime or logtime > newesttime:
                opt_a = assessment
                newesttime = logtime
        if not opt_a:
            fatal(1, _("No assessments available"))

    if re.search("/", opt_a):
        fatal(1, _("Invalid assessment name: '%s'") % opt_a)
    assessmentrep = path.join(ASSESSMENTS, opt_a)
    if not path.isdir(assessmentrep):
        fatal(1, _("Assessment repository does not exist: %s") % assessmentrep)
    if opt_s:
        exact = len(opt_s) and opt_s[0] == '='
        sl = opt_s[exact:].split(",")
        sl.sort()
        opt_s = (exact and "=" or "") + reduce(lambda a, b:  a + "," + b, sl)
        ffile = "report." + opt_s + ".html"
    reportfile = path.join(assessmentrep, ffile)
    log = path.join(assessmentrep, "log")
    logf = None
    try:
        if opt_o or path.isfile(reportfile):
            logf = open(log, 'r')
            fcntl.lockf(logf.fileno(), fcntl.LOCK_SH | fcntl.LOCK_NB, 1, 0, 0)
        else:
            logf = open(log, 'r+')
            fcntl.lockf(logf.fileno(), fcntl.LOCK_EX | fcntl.LOCK_NB, 1, 1, 0)
        statbuf = os.fstat(logf.fileno())
        if not statbuf or statbuf.st_size == 0:
            raise EnvironmentError
    except:
        fatal(1, _("Assessment '%s' is not finished") % opt_a)
    if opt_o:
        logf.close()
        ruid = os.getuid()
        if os.geteuid() != ruid:
            # drop privileges before accessing user-specified pathname
            os.setreuid(ruid, ruid)
        reportfile = opt_o
    if not opt_o and path.isfile(reportfile) or ffunc(reportfile):
        print reportfile
        exit(0)
    else:
        print _("Unable to create report file: %s") % reportfile
        exit(1)


#
#  compliance delete assessment
#
def do_delete():
    """
    process delete command
    """
    _opts, pargs = getcmdopt("")
    if len(pargs) < 1:
        usage(_("Missing argument: assessment"))
    if len(pargs) > 1:
        usage(_("More than one assessment specified"))

    user = realuser()
    if not haveauth(AUTH_ASSESS, user):
        fatal(1, _("User %(u)s lacks authorization %(a)s") %
              {"u": user, "a": AUTH_ASSESS})
    assessment = pargs[0]
    if re.search("/", assessment) or len(assessment) == 0:
        fatal(1, _("Invalid assessment name: '%s'") % assessment)
    assessmentrep = path.join(ASSESSMENTS, assessment)
    shutil.rmtree(assessmentrep, True)


def do_get_policy():
    (benchmark, profile, tailoring) = smf_util.get_policy()
    print _("Benchmark:\t%s") % benchmark
    print _("Profile:\t%s") % profile
    print _("Tailoring:\t%s") % tailoring


def do_set_policy():
    opts, pargs = getcmdopt("b:p:t:")
    opt_b = ""
    opt_p = ""
    opt_t = ""
    for opt, arg in opts:
        if (opt == '-b'):
            opt_b = arg
        if (opt == '-p'):
            opt_p = arg
        if (opt == '-t'):
            opt_t = arg
    if pargs:
        usage(_("Extra arguments for set-policy"))

    if opt_t:
        if opt_p:
            usage(_("Option -t cannot be used with -p"))
        if opt_b:
            tailoring = "%s/%s" % (opt_b, opt_t)
        else:
            tailoring = opt_t
        # compute benchmark and profile from tailoring
        (benchmark, profile, _tpath, msgs) = tailor.getassessopts(tailoring)
        if not benchmark or not profile:
            fatal(1, _("Tailoring not found '%(t)s': %(m)s") %
                  {"t": tailoring, "m": msgs})
    elif opt_b:
        xccdf = xccdf_util.bench_path(opt_b)
        if not path.isfile(xccdf):
            fatal(1, _("Benchmark tests file not found: %s") % xccdf)
        if opt_p:
            proflist = xccdf_util.benchmark_profiles(xccdf)
            if opt_p not in proflist:
                fatal(1, _("Benchmark %(b)s has no '%(p)s' profile") %
                      {"b": opt_b, "p": opt_p})
    elif opt_p:
        usage(_("Option -p cannot be used without -b"))

    if not any((opt_b, opt_p, opt_t)):
        usage(_("No policy parameters specified"))

    smf_util.set_policy(opt_b, opt_p, opt_t)


#
# main program
#
try:
    locale.setlocale(locale.LC_ALL, "")
except locale.Error:
    pass
gettext.textdomain("compliance")

if (len(sys.argv) == 1):
    usage(_("No command specified"))

#
# main program dispatch
#
if (command == "smf-service"):
    if not os.environ.get("SMF_FMRI"):
        fatal(1, _("Service functionality invoked outside service context"))
    if len(sys.argv) < 2:
        fatal(1, _("Service method not specified"))
    service = sys.argv[2]
    service_set(service)  # propagate to common namespace
    if service not in ("start", "refresh"):
        fatal(1, _("Invalid service method: %s") % service)
    do_guide()
elif (command == "list"):
    do_list()
elif (command == "guide"):
    do_guide()
elif (command == "assess"):
    do_assess()
elif (command == "report"):
    do_report()
elif (command == "delete"):
    do_delete()
elif (command == "tailor"):
    tailor.do_tailor()
elif (command == "get-policy"):
    do_get_policy()
elif (command == "set-policy"):
    do_set_policy()
elif re.search("help", command, re.IGNORECASE):
    usage(None)
else:
    usage(_("Command '%s' not recognized") % command)