Completed
Push — master ( d462aa...30f501 )
by
unknown
11s
created

RuleData.revert_changes()   A

Complexity

Conditions 2

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 3
nop 3
dl 0
loc 6
rs 9.4285
c 0
b 0
f 0
1
#
2
# Copyright (C) 2013  Red Hat, Inc.
3
#
4
# This copyrighted material is made available to anyone wishing to use,
5
# modify, copy, or redistribute it subject to the terms and conditions of
6
# the GNU General Public License v.2, or (at your option) any later version.
7
# This program is distributed in the hope that it will be useful, but WITHOUT
8
# ANY WARRANTY expressed or implied, including the implied warranties of
9
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
10
# Public License for more details.  You should have received a copy of the
11
# GNU General Public License along with this program; if not, write to the
12
# Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
13
# 02110-1301, USA.  Any Red Hat trademarks that are incorporated in the
14
# source code or documentation are not subject to the GNU General Public
15
# License and may only be used or replicated with the express permission of
16
# Red Hat, Inc.
17
#
18
# Red Hat Author(s): Vratislav Podzimek <[email protected]>
19
#
20
21
"""
22
Module with various classes for handling pre-installation rules.
23
24
"""
25
26
import optparse
27
import shlex
28
import logging
29
from pyanaconda.pwpolicy import F22_PwPolicyData
30
from org_fedora_oscap import common
31
from org_fedora_oscap.common import OSCAPaddonError, RuleMessage
32
33
# everything else should be private
34
__all__ = ["RuleData"]
35
36
37
log = logging.getLogger("anaconda")
38
39
_ = common._
40
41
42
# TODO: use set instead of list for mount options?
43
def parse_csv(option, opt_str, value, parser):
44
    for item in value.split(","):
45
        if item:
46
            parser.values.ensure_value(option.dest, []).append(item)
47
48
49
class ModifiedOptionParserException(Exception):
50
    """Exception to be raised by ModifiedOptionParser."""
51
    pass
52
53
54
class ModifiedOptionParser(optparse.OptionParser):
55
    """Overrides error behavior of OptionParser."""
56
    def error(self, msg):
57
        raise ModifiedOptionParserException(msg)
58
59
    def exit(self, status=0, msg=None):
60
        raise ModifiedOptionParserException(msg)
61
62
63
PART_RULE_PARSER = ModifiedOptionParser()
64
PART_RULE_PARSER.add_option("--mountoptions", dest="mount_options",
65
                            action="callback", callback=parse_csv, nargs=1,
66
                            type="string")
67
68
PASSWD_RULE_PARSER = ModifiedOptionParser()
69
PASSWD_RULE_PARSER.add_option("--minlen", dest="minlen", action="store",
70
                              default=0, type="int")
71
72
PACKAGE_RULE_PARSER = ModifiedOptionParser()
73
PACKAGE_RULE_PARSER.add_option("--add", dest="add_pkgs", action="append",
74
                               type="string")
75
PACKAGE_RULE_PARSER.add_option("--remove", dest="remove_pkgs", action="append",
76
                               type="string")
77
78
BOOTLOADER_RULE_PARSER = ModifiedOptionParser()
79
BOOTLOADER_RULE_PARSER.add_option("--passwd", dest="passwd", action="store_true",
80
                                  default=False)
81
82
KDUMP_RULE_PARSER = ModifiedOptionParser()
83
KDUMP_RULE_PARSER.add_option("--enable", action="store_true",
84
                             dest="kdenabled", default=None)
85
KDUMP_RULE_PARSER.add_option("--disable", action="store_false",
86
                             dest="kdenabled", default=None)
87
88
FIREWALL_RULE_PARSER = ModifiedOptionParser()
89
FIREWALL_RULE_PARSER.add_option("--enable", action="store_true",
90
                                dest="fwenabled", default=None)
91
FIREWALL_RULE_PARSER.add_option("--disable", action="store_false",
92
                                dest="fwenabled", default=None)
93
FIREWALL_RULE_PARSER.add_option("--service", dest="add_svcs", action="append",
94
                                type="string")
95
FIREWALL_RULE_PARSER.add_option("--port", dest="add_port", action="append",
96
                                type="string")
97
FIREWALL_RULE_PARSER.add_option("--trust", dest="add_trust", action="append",
98
                                type="string")
99
FIREWALL_RULE_PARSER.add_option("--remove-service", dest="remove_svcs",
100
                                action="append", type="string")
101
102
103
class RuleHandler(object):
104
    """Base class for the rule handlers."""
105
106
    def eval_rules(self, ksdata, storage, report_only=False):
107
        """
108
        Method that should check the current state (as defined by the ksdata
109
        and storage parameters) against the rules the instance of RuleHandler
110
        holds. Depending on the value of report_only it should fix the state
111
        with changes that can be done automatically or not and return the list
112
        of warnings and errors for fixes that need to be done manually together
113
        with info messages about the automatic changes. One should make sure
114
        this method is called with report_only set to False at least once so
115
        that the automatic fixes are done.
116
117
        :param ksdata: data representing the values set by user
118
        :type ksdata: pykickstart.base.BaseHandler
119
        :param storage: object storing storage-related information
120
                        (disks, partitioning, bootloader, etc.)
121
        :type storage: blivet.Blivet
122
        :param report_only: whether to do fixing or just report information
123
        :type report_only: bool
124
        :return: errors and warnings for fixes that need to be done manually
125
                 and info messages about the automatic changes
126
        :rtype: list of common.RuleMessage objects
127
128
        """
129
130
        return []
131
132
    def revert_changes(self, ksdata, storage):
133
        """
134
        Method that should revert all changes done by the previous calls of the
135
        eval_rules method with the report_only set to False.
136
137
        :see: eval_rules
138
139
        """
140
141
        # inheriting classes are supposed to override this
142
        pass
143
144
145
class UknownRuleError(OSCAPaddonError):
146
    """Exception class for cases when an uknown rule is to be processed."""
147
148
    pass
149
150
151
class RuleData(RuleHandler):
152
    """Class holding data parsed from the applied rules."""
153
154
    def __init__(self):
155
        """Constructor initializing attributes."""
156
157
        self._part_rules = PartRules()
158
        self._passwd_rules = PasswdRules()
159
        self._package_rules = PackageRules()
160
        self._bootloader_rules = BootloaderRules()
161
        self._kdump_rules = KdumpRules()
162
        self._firewall_rules = FirewallRules()
163
164
        self._rule_handlers = (self._part_rules, self._passwd_rules,
165
                               self._package_rules, self._bootloader_rules,
166
                               self._kdump_rules, self._firewall_rules,
167
                               )
168
169
    def __str__(self):
170
        """Standard method useful for debugging and testing."""
171
172
        ret = ""
173
174
        part_strs = str(self._part_rules)
175
        if part_strs:
176
            ret += part_strs
177
178
        passwd_str = str(self._passwd_rules)
179
        if passwd_str:
180
            ret += "\n" + passwd_str
181
182
        packages_str = str(self._package_rules)
183
        if packages_str:
184
            ret += "\n" + packages_str
185
186
        firewall_str = str(self._firewall_rules)
187
        if firewall_str:
188
            ret += "\n" + firewall_str
189
190
        return ret
191
192
    def new_rule(self, rule):
193
        """
194
        Method that handles a single rule line (e.g. "part /tmp").
195
196
        :param rule: a single rule line
197
        :type rule: str
198
199
        """
200
201
        actions = {"part": self._new_part_rule,
202
                   "passwd": self._new_passwd_rule,
203
                   "package": self._new_package_rule,
204
                   "bootloader": self._new_bootloader_rule,
205
                   "kdump": self._new_kdump_rule,
206
                   "firewall": self._new_firewall_rule,
207
                   }
208
209
        rule = rule.strip()
210
        if not rule:
211
            return
212
213
        first_word = rule.split(None, 1)[0]
214
        try:
215
            actions[first_word](rule)
216
        except (ModifiedOptionParserException, KeyError) as e:
217
            log.warning("Unknown OSCAP Addon rule '{}': {}".format(rule, e))
218
219
    def eval_rules(self, ksdata, storage, report_only=False):
220
        """:see: RuleHandler.eval_rules"""
221
222
        messages = []
223
224
        # evaluate all subgroups of rules
225
        for rule_handler in self._rule_handlers:
226
            messages += rule_handler.eval_rules(ksdata, storage, report_only)
227
228
        return messages
229
230
    def revert_changes(self, ksdata, storage):
231
        """:see: RuleHandler.revert_changes"""
232
233
        # revert changes in all subgroups of rules
234
        for rule_handler in self._rule_handlers:
235
            rule_handler.revert_changes(ksdata, storage)
236
237
    def _new_part_rule(self, rule):
238
        args = shlex.split(rule)
239
        (opts, args) = PART_RULE_PARSER.parse_args(args)
240
241
        # args contain both "part" and mount point (e.g. "/tmp")
242
        mount_point = args[1]
243
244
        self._part_rules.ensure_mount_point(mount_point)
245
246
        if opts.mount_options:
247
            part_data = self._part_rules[mount_point]
248
            part_data.add_mount_options(opts.mount_options)
249
250
    def _new_passwd_rule(self, rule):
251
        args = shlex.split(rule)
252
        (opts, args) = PASSWD_RULE_PARSER.parse_args(args)
253
254
        self._passwd_rules.update_minlen(opts.minlen)
255
256
    def _new_package_rule(self, rule):
257
        args = shlex.split(rule)
258
        (opts, args) = PACKAGE_RULE_PARSER.parse_args(args)
259
260
        self._package_rules.add_packages(opts.add_pkgs)
261
        self._package_rules.remove_packages(opts.remove_pkgs)
262
263
    def _new_bootloader_rule(self, rule):
264
        args = shlex.split(rule)
265
        (opts, args) = BOOTLOADER_RULE_PARSER.parse_args(args)
266
267
        if opts.passwd:
268
            self._bootloader_rules.require_password()
269
270
    def _new_kdump_rule(self, rule):
271
        args = shlex.split(rule)
272
        (opts, args) = KDUMP_RULE_PARSER.parse_args(args)
273
274
        self._kdump_rules.kdump_enabled(opts.kdenabled)
275
276
    def _new_firewall_rule(self, rule):
277
        args = shlex.split(rule)
278
        (opts, args) = FIREWALL_RULE_PARSER.parse_args(args)
279
280
        self._firewall_rules.add_services(opts.add_svcs)
281
        self._firewall_rules.remove_services(opts.remove_svcs)
282
        self._firewall_rules.add_trusts(opts.add_trust)
283
        self._firewall_rules.add_ports(opts.add_port)
284
        self._firewall_rules.firewall_enabled(opts.fwenabled)
285
286
    @property
287
    def passwd_rules(self):
288
        # needed for fixups in GUI
289
        return self._passwd_rules
290
291
292
class PartRules(RuleHandler):
293
    """Simple class holding data from the rules affecting partitioning."""
294
295
    def __init__(self):
296
        """Constructor initializing attributes."""
297
298
        self._rules = dict()
299
300
    def __str__(self):
301
        """Standard method useful for debugging and testing."""
302
303
        return "\n".join(str(rule) for rule in self._rules.values())
304
305
    def __getitem__(self, key):
306
        """Method to support dictionary-like syntax."""
307
308
        return self._rules[key]
309
310
    def __setitem__(self, key, value):
311
        """Method to support dictionary-like syntax."""
312
313
        self._rules[key] = value
314
315
    def __delitem__(self, key):
316
        """One of the methods needed to implement a container."""
317
318
        self._rules.__delitem__(key)
319
320
    def __len__(self):
321
        """One of the methods needed to implement a container."""
322
323
        return self._rules.__len__()
324
325
    def __contains__(self, key):
326
        """Method needed for the 'in' operator to work."""
327
328
        return key in self._rules
329
330
    def ensure_mount_point(self, mount_point):
331
        if mount_point not in self._rules:
332
            self._rules[mount_point] = PartRule(mount_point)
333
334
    def eval_rules(self, ksdata, storage, report_only=False):
335
        """:see: RuleHandler.eval_rules"""
336
337
        messages = []
338
        for part_rule in self._rules.values():
339
            messages += part_rule.eval_rules(ksdata, storage, report_only)
340
341
        return messages
342
343
    def revert_changes(self, ksdata, storage):
344
        """:see: RuleHandler.revert_changes"""
345
346
        for part_rule in self._rules.values():
347
            part_rule.revert_changes(ksdata, storage)
348
349
350
class PartRule(RuleHandler):
351
    """Simple class holding rule data for a single partition/mount point."""
352
353
    def __init__(self, mount_point):
354
        """
355
        Constructor initializing attributes.
356
357
        :param mount_point: the mount point the object holds data for
358
        :type mount_point: str
359
360
        """
361
362
        self._mount_point = mount_point
363
        self._mount_options = []
364
        self._added_mount_options = []
365
366
    def __str__(self):
367
        """Standard method useful for debugging and testing."""
368
369
        ret = "part %s" % self._mount_point
370
        if self._mount_options:
371
            ret += " --mountoptions=%s" % ",".join(self._mount_options)
372
373
        return ret
374
375
    def add_mount_options(self, mount_options):
376
        """
377
        Add  new mount options (do not add duplicates).
378
379
        :param mount_options: list of mount options to be added
380
        :type mount_options: list of strings
381
382
        """
383
384
        self._mount_options.extend(opt for opt in mount_options
385
                                   if opt not in self._mount_options)
386
387
    def eval_rules(self, ksdata, storage, report_only=False):
388
        """:see: RuleHandler.eval_rules"""
389
390
        messages = []
391
        if self._mount_point not in storage.mountpoints:
392
            msg = _("{0} must be on a separate partition or logical "
393
                    "volume and has to be created in the "
394
                    "partitioning layout before installation can occur "
395
                    "with a security profile").format(self._mount_point)
396
            messages.append(RuleMessage(self.__class__,
397
                                        common.MESSAGE_TYPE_FATAL, msg))
398
399
            # mount point doesn't exist, nothing more can be found here
400
            return messages
401
402
        # template for the message
403
        msg_tmpl = _("mount option '%(mount_option)s' added for "
404
                     "the mount point %(mount_point)s")
405
406
        # add message for every option already added
407
        for opt in self._added_mount_options:
408
            msg = msg_tmpl % {"mount_option": opt,
409
                              "mount_point": self._mount_point}
410
            messages.append(RuleMessage(self.__class__,
411
                                        common.MESSAGE_TYPE_INFO, msg))
412
413
        # mount point to be created during installation
414
        target_mount_point = storage.mountpoints[self._mount_point]
415
416
        # generator for the new options that should be added
417
        new_opts = (opt for opt in self._mount_options
0 ignored issues
show
introduced by
The variable opt does not seem to be defined in case the for loop on line 407 is not entered. Are you sure this can never be the case?
Loading history...
418
                    if opt not in target_mount_point.format.options.split(","))
419
420
        # add message for every mount option added
421
        for opt in new_opts:
422
            msg = msg_tmpl % {"mount_option": opt,
423
                              "mount_point": self._mount_point}
424
425
            # add message for the mount option in any case
426
            messages.append(RuleMessage(self.__class__,
427
                                        common.MESSAGE_TYPE_INFO, msg))
428
429
            # add new options to the target mount point if not reporting only
430
            if not report_only:
431
                target_mount_point.format.options += ",%s" % opt
432
                self._added_mount_options.append(opt)
433
434
        return messages
435
436
    def revert_changes(self, ksdata, storage):
437
        """
438
        Removes the mount options added to the mount point by this PartRule
439
        instance.
440
441
        :see: RuleHandler.revert_changes
442
443
        """
444
445
        if self._mount_point not in storage.mountpoints:
446
            # mount point doesn't exist, nothing can be reverted
447
            return
448
449
        # mount point to be created during installation
450
        target_mount_point = storage.mountpoints[self._mount_point]
451
452
        # mount options to be defined for the created mount point
453
        tgt_mount_options = target_mount_point.format.options
454
455
        # generator of the options that should remain
456
        result_opts = (opt for opt in tgt_mount_options.split(",")
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable opt does not seem to be defined.
Loading history...
457
                       if opt not in self._added_mount_options)
458
459
        # set the new list of options
460
        target_mount_point.format.options = ",".join(result_opts)
461
462
        # reset the remembered added mount options
463
        self._added_mount_options = []
464
465
466
class PasswdRules(RuleHandler):
467
    """Simple class holding data from the rules affecting passwords."""
468
469
    def __init__(self):
470
        """Constructor initializing attributes."""
471
472
        self._minlen = 0
473
        self._created_policy = False
474
        self._orig_minlen = None
475
        self._orig_strict = None
476
477
    def __str__(self):
478
        """Standard method useful for debugging and testing."""
479
480
        if self._minlen > 0:
481
            return "passwd --minlen=%d" % self._minlen
482
        else:
483
            return ""
484
485
    def update_minlen(self, minlen):
486
        """Update password minimal length requirements."""
487
488
        if minlen > self._minlen:
489
            self._minlen = minlen
490
491
    def eval_rules(self, ksdata, storage, report_only=False):
492
        """:see: RuleHandler.eval_rules"""
493
494
        if self._minlen == 0:
495
            # no password restrictions, nothing to be done here
496
            return []
497
498
        ret = []
499
        if not ksdata.rootpw.password:
500
            # root password was not set
501
502
            msg = _("make sure to create password with minimal length of %d "
503
                    "characters") % self._minlen
504
            ret = [RuleMessage(self.__class__,
505
                               common.MESSAGE_TYPE_WARNING, msg)]
506
        else:
507
            # root password set
508
            if ksdata.rootpw.isCrypted:
509
                msg = _("cannot check root password length (password is crypted)")
510
                log.warning("cannot check root password length (password is crypted)")
511
                return [RuleMessage(self.__class__,
512
                                    common.MESSAGE_TYPE_WARNING, msg)]
513
            elif len(ksdata.rootpw.password) < self._minlen:
514
                # too short
515
                msg = _("root password is too short, a longer one with at "
516
                        "least %d characters is required") % self._minlen
517
                ret = [RuleMessage(self.__class__,
518
                                   common.MESSAGE_TYPE_FATAL, msg)]
519
            else:
520
                ret = []
521
522
        if report_only:
523
            return ret
524
525
        # set the policy in any case (so that a weaker password is not entered)
526
        pw_policy = ksdata.anaconda.pwpolicy.get_policy("root")
527
        if pw_policy is None:
528
            pw_policy = F22_PwPolicyData()
529
            log.info("OSCAP addon: setting password policy %s" % pw_policy)
530
            ksdata.anaconda.pwpolicy.policyList.append(pw_policy)
531
            log.info("OSCAP addon: password policy list: %s" % ksdata.anaconda.pwpolicy.policyList)
532
            self._created_policy = True
533
534
        self._orig_minlen = pw_policy.minlen
535
        self._orig_strict = pw_policy.strict
536
        pw_policy.minlen = self._minlen
537
        pw_policy.strict = True
538
539
        return ret
540
541
    def revert_changes(self, ksdata, storage):
542
        """:see: RuleHander.revert_changes"""
543
544
        pw_policy = ksdata.anaconda.pwpolicy.get_policy("root")
545
        if self._created_policy:
546
            log.info("OSCAP addon: removing password policy: %s" % pw_policy)
547
            ksdata.anaconda.pwpolicy.policyList.remove(pw_policy)
548
            log.info("OSCAP addon: password policy list: %s" % ksdata.anaconda.pwpolicy.policyList)
549
            self._created_policy = False
550
        else:
551
            if self._orig_minlen is not None:
552
                pw_policy.minlen = self._orig_minlen
553
                self._orig_minlen = None
554
            if self._orig_strict is not None:
555
                pw_policy.strict = self._orig_strict
556
                self._orig_strict = None
557
558
559
class PackageRules(RuleHandler):
560
    """Simple class holding data from the rules affecting installed packages.
561
562
    """
563
564
    def __init__(self):
565
        """Constructor setting the initial value of attributes."""
566
567
        self._add_pkgs = set()
568
        self._remove_pkgs = set()
569
570
        self._added_pkgs = set()
571
        self._removed_pkgs = set()
572
573
    def add_packages(self, packages):
574
        """
575
        New packages that should be added.
576
577
        :param packages: packages to be added
578
        :type packages: iterable
579
580
        """
581
582
        if packages:
583
            self._add_pkgs.update(packages)
584
585
    def remove_packages(self, packages):
586
        """
587
        New packages that should be removed.
588
589
        :param packages: packages to be removed
590
        :type packages: iterable
591
592
        """
593
594
        if packages:
595
            self._remove_pkgs.update(packages)
596
597
    def __str__(self):
598
        """Standard method useful for debugging and testing."""
599
600
        ret = "packages"
601
        adds = " ".join("--add=%s" % package for package in self._add_pkgs)
602
        if adds:
603
            ret += " " + adds
604
605
        rems = " ".join("--remove=%s" % package
606
                        for package in self._remove_pkgs)
607
        if rems:
608
            ret += " " + rems
609
610
        return ret
611
612
    def eval_rules(self, ksdata, storage, report_only=False):
613
        """:see: RuleHandler.eval_rules"""
614
615
        messages = []
616
617
        # add messages for the already added packages
618
        for pkg in self._added_pkgs:
619
            msg = _("package '%s' has been added to the list of to be installed "
620
                    "packages" % pkg)
621
            messages.append(RuleMessage(self.__class__,
622
                                        common.MESSAGE_TYPE_INFO, msg))
623
624
        # packages, that should be added
625
        packages_to_add = (pkg for pkg in self._add_pkgs
0 ignored issues
show
introduced by
The variable pkg does not seem to be defined in case the for loop on line 618 is not entered. Are you sure this can never be the case?
Loading history...
626
                           if pkg not in ksdata.packages.packageList)
627
628
        for pkg in packages_to_add:
629
            # add the package unless already added
630
            if not report_only:
631
                self._added_pkgs.add(pkg)
632
                ksdata.packages.packageList.append(pkg)
633
634
            msg = _("package '%s' has been added to the list of to be installed "
635
                    "packages" % pkg)
636
            messages.append(RuleMessage(self.__class__,
637
                                        common.MESSAGE_TYPE_INFO, msg))
638
639
        # now do the same for the packages that should be excluded
640
641
        # add messages for the already excluded packages
642
        for pkg in self._removed_pkgs:
643
            msg = _("package '%s' has been added to the list of excluded "
644
                    "packages" % pkg)
645
            messages.append(RuleMessage(self.__class__,
646
                                        common.MESSAGE_TYPE_INFO, msg))
647
648
        # packages, that should be added
649
        packages_to_remove = (pkg for pkg in self._remove_pkgs
650
                              if pkg not in ksdata.packages.excludedList)
651
652
        for pkg in packages_to_remove:
653
            # exclude the package unless already excluded
654
            if not report_only:
655
                self._removed_pkgs.add(pkg)
656
                ksdata.packages.excludedList.append(pkg)
657
658
            msg = _("package '%s' has been added to the list of excluded "
659
                    "packages" % pkg)
660
            messages.append(RuleMessage(self.__class__,
661
                                        common.MESSAGE_TYPE_INFO, msg))
662
663
        return messages
664
665
    def revert_changes(self, ksdata, storage):
666
        """:see: RuleHander.revert_changes"""
667
668
        # remove all packages this handler added
669
        for pkg in self._added_pkgs:
670
            if pkg in ksdata.packages.packageList:
671
                ksdata.packages.packageList.remove(pkg)
672
673
        # remove all packages this handler excluded
674
        for pkg in self._removed_pkgs:
675
            if pkg in ksdata.packages.excludedList:
676
                ksdata.packages.excludedList.remove(pkg)
677
678
        self._added_pkgs = set()
679
        self._removed_pkgs = set()
680
681
682
class BootloaderRules(RuleHandler):
683
    """Simple class holding data from the rules affecting bootloader."""
684
685
    def __init__(self):
686
        """Constructor setting the initial value of attributes."""
687
688
        self._require_password = False
689
690
    def require_password(self):
691
        """Requests the bootloader password should be required."""
692
693
        self._require_password = True
694
695
    def __str__(self):
696
        """Standard method useful for debugging and testing."""
697
698
        ret = "bootloader"
699
700
        if self._require_password:
701
            ret += " --passwd"
702
703
        return ret
704
705
    def eval_rules(self, ksdata, storage, report_only=False):
706
        """:see: RuleHandler.eval_rules"""
707
708
        if self._require_password and not storage.bootloader.password:
709
            # Anaconda doesn't provide a way to set bootloader password, so
710
            # users cannot do much about that --> we shouldn't stop the
711
            # installation, should we?
712
            return [RuleMessage(self.__class__, common.MESSAGE_TYPE_WARNING,
713
                                "boot loader password not set up")]
714
        else:
715
            return []
716
717
    # nothing to be reverted for now
718
719
720
class KdumpRules(RuleHandler):
721
    """Simple class holding data from the rules affecting the kdump addon."""
722
723
    def __init__(self):
724
        """Constructor setting the initial value of attributes."""
725
726
        self._kdump_enabled = None
727
        self._kdump_default_enabled = None
728
729
    def kdump_enabled(self, kdenabled):
730
        """Enable or Disable Kdump"""
731
732
        if kdenabled is not None:
733
            self._kdump_enabled = kdenabled
734
735
    def __str__(self):
736
        """Standard method useful for debugging and testing."""
737
738
        ret = "kdump"
739
740
        if self._kdump_enabled is True:
741
            ret += " --enable"
742
743
        if self._kdump_enabled is False:
744
            ret += " --disable"
745
746
        return ret
747
748
    def eval_rules(self, ksdata, storage, report_only=False):
749
        """:see: RuleHandler.eval_rules"""
750
751
        messages = []
752
753
        if self._kdump_enabled is None:
754
            return []
755
        elif self._kdump_enabled is False:
756
            msg = _("Kdump will be disabled on startup")
757
        elif self._kdump_enabled is True:
758
            msg = _("Kdump will be enabled on startup")
759
760
        messages.append(RuleMessage(self.__class__,
761
                                    common.MESSAGE_TYPE_INFO, msg))
0 ignored issues
show
introduced by
The variable msg does not seem to be defined for all execution paths.
Loading history...
762
763
        if not report_only:
764
            try:
765
                if self._kdump_default_enabled is None:
766
                    # Kdump addon default startup setting
767
                    self._kdump_default_enabled = ksdata.addons.com_redhat_kdump.enabled
768
                ksdata.addons.com_redhat_kdump.enabled = self._kdump_enabled
769
            except AttributeError:
770
                log.warning("com_redhat_kdump is not installed. "
771
                            "Skipping kdump configuration")
772
773
        return messages
774
775
    def revert_changes(self, ksdata, storage):
776
        """:see: RuleHander.revert_changes"""
777
778
        try:
779
            if self._kdump_enabled is not None:
780
                ksdata.addons.com_redhat_kdump.enabled = self._kdump_default_enabled
781
        except AttributeError:
782
            log.warning("com_redhat_kdump is not installed. "
783
                        "Skipping reverting kdump configuration")
784
785
        self._kdump_enabled = None
786
        self._kdump_default_enabled = None
787
788
789
class FirewallRules(RuleHandler):
790
    """Simple class holding data from the rules affecting firewall configurations."""
791
792
    def __init__(self):
793
        """Constructor setting the initial value of attributes."""
794
795
        self._add_svcs = set()
796
        self._remove_svcs = set()
797
        self._add_trusts = set()
798
        self._add_ports = set()
799
800
        self._added_svcs = set()
801
        self._added_ports = set()
802
        self._added_trusts = set()
803
        self._removed_svcs = set()
804
805
        self._firewall_enabled = None
806
        self._firewall_default_enabled = None
807
808
    def add_services(self, services):
809
        """
810
        Services that should be allowed through firewall.
811
812
        :param services: services to be added
813
        :type services: iterable
814
815
        """
816
817
        if services:
818
            self._add_svcs.update(services)
819
820
    def add_ports(self, ports):
821
        """
822
        Ports that should be allowed through firewall.
823
824
        :param ports: ports to be added
825
        :type ports: iterable
826
827
        """
828
829
        if ports:
830
            self._add_ports.update(ports)
831
832
    def add_trusts(self, trusts):
833
        """
834
        trusts that should be allowed through firewall.
835
836
        :param trusts: trusts to be added
837
        :type trusts: iterable
838
839
        """
840
841
        if trusts:
842
            self._add_trusts.update(trusts)
843
844
    def remove_services(self, services):
845
        """
846
        New services that should not be allowed through firewall.
847
848
        :param services: services to be removed
849
        :type services: iterable
850
851
        """
852
853
        if services:
854
            self._remove_svcs.update(services)
855
856
    def firewall_enabled(self, fwenabled):
857
        """Enable or disable firewall"""
858
859
        if fwenabled is not None:
860
            self._firewall_enabled = fwenabled
861
862
    def __str__(self):
863
        """Standard method useful for debugging and testing."""
864
865
        ret = "firewall"
866
867
        if self._firewall_enabled is True:
868
            ret += " --enable"
869
870
        if self._firewall_enabled is False:
871
            ret += " --disable"
872
873
        adds = " ".join("--service=%s" % service
874
                        for service in self._add_svcs)
875
        if adds:
876
            ret += " " + adds
877
878
        rems = " ".join("--remove-service=%s" % service
879
                        for service in self._remove_svcs)
880
        if rems:
881
            ret += " " + rems
882
883
        ports = " ".join("--port=%s" % port
884
                         for port in self._add_ports)
885
        if ports:
886
            ret += " " + ports
887
888
        trusts = " ".join("--trust=%s" % trust
889
                          for trust in self._add_trusts)
890
        if trusts:
891
            ret += " " + trusts
892
893
        return ret
894
895
    def eval_rules(self, ksdata, storage, report_only=False):
896
        """:see: RuleHandler.eval_rules"""
897
898
        messages = []
899
900
        if self._firewall_default_enabled is None:
901
            # firewall default startup setting
902
            self._firewall_default_enabled = ksdata.firewall.enabled
903
904
        if self._firewall_enabled is False:
905
            msg = _("Firewall will be disabled on startup")
906
            messages.append(RuleMessage(self.__class__,
907
                                        common.MESSAGE_TYPE_INFO, msg))
908
            if not report_only:
909
                ksdata.firewall.enabled = self._firewall_enabled
910
911
        elif self._firewall_enabled is True:
912
            msg = _("Firewall will be enabled on startup")
913
            messages.append(RuleMessage(self.__class__,
914
                                        common.MESSAGE_TYPE_INFO, msg))
915
            if not report_only:
916
                ksdata.firewall.enabled = self._firewall_enabled
917
918
        # add messages for the already added services
919
        for svc in self._added_svcs:
920
            msg = _("service '%s' has been added to the list of services to be "
921
                    "added to the firewall" % svc)
922
            messages.append(RuleMessage(self.__class__,
923
                                        common.MESSAGE_TYPE_INFO, msg))
924
925
        # add messages for the already added ports
926
        for port in self._added_ports:
927
            msg = _("port '%s' has been added to the list of ports to be "
928
                    "added to the firewall" % port)
929
            messages.append(RuleMessage(self.__class__,
930
                                        common.MESSAGE_TYPE_INFO, msg))
931
932
        # add messages for the already added trusts
933
        for trust in self._added_trusts:
934
            msg = _("trust '%s' has been added to the list of trusts to be "
935
                    "added to the firewall" % trust)
936
            messages.append(RuleMessage(self.__class__,
937
                                        common.MESSAGE_TYPE_INFO, msg))
938
939
        # services, that should be added
940
        services_to_add = (svc for svc in self._add_svcs
0 ignored issues
show
introduced by
The variable svc does not seem to be defined in case the for loop on line 919 is not entered. Are you sure this can never be the case?
Loading history...
941
                           if svc not in ksdata.firewall.services)
942
943
        # ports, that should be added
944
        ports_to_add = (ports for ports in self._add_ports
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable ports does not seem to be defined.
Loading history...
945
                        if ports not in ksdata.firewall.ports)
946
947
        # trusts, that should be added
948
        trusts_to_add = (trust for trust in self._add_trusts
0 ignored issues
show
introduced by
The variable trust does not seem to be defined in case the for loop on line 933 is not entered. Are you sure this can never be the case?
Loading history...
949
                         if trust not in ksdata.firewall.trusts)
950
951
        for svc in services_to_add:
952
            # add the service unless already added
953
            if not report_only:
954
                self._added_svcs.add(svc)
955
                ksdata.firewall.services.append(svc)
956
957
            msg = _("service '%s' has been added to the list of services to be "
958
                    "added to the firewall" % svc)
959
            messages.append(RuleMessage(self.__class__,
960
                                        common.MESSAGE_TYPE_INFO, msg))
961
962
        for port in ports_to_add:
963
            # add the port unless already added
964
            if not report_only:
965
                self._added_ports.add(port)
966
                ksdata.firewall.ports.append(port)
967
968
            msg = _("port '%s' has been added to the list of ports to be "
969
                    "added to the firewall" % port)
970
            messages.append(RuleMessage(self.__class__,
971
                                        common.MESSAGE_TYPE_INFO, msg))
972
973
        for trust in trusts_to_add:
974
            # add the trust unless already added
975
            if not report_only:
976
                self._added_trusts.add(trust)
977
                ksdata.firewall.trusts.append(trust)
978
979
            msg = _("trust '%s' has been added to the list of trusts to be "
980
                    "added to the firewall" % trust)
981
            messages.append(RuleMessage(self.__class__,
982
                                        common.MESSAGE_TYPE_INFO, msg))
983
984
        # now do the same for the services that should be excluded
985
986
        # add messages for the already excluded services
987
        for svc in self._removed_svcs:
988
            msg = _("service '%s' has been added to the list of services to be "
989
                    "removed from the firewall" % svc)
990
            messages.append(RuleMessage(self.__class__,
991
                                        common.MESSAGE_TYPE_INFO, msg))
992
993
        # services, that should be added
994
        services_to_remove = (svc for svc in self._remove_svcs
995
                              if svc not in ksdata.firewall.remove_services)
996
997
        for svc in services_to_remove:
998
            # exclude the service unless already excluded
999
            if not report_only:
1000
                self._removed_svcs.add(svc)
1001
                ksdata.firewall.remove_services.append(svc)
1002
1003
            msg = _("service '%s' has been added to the list of services to be "
1004
                    "removed from the firewall" % svc)
1005
            messages.append(RuleMessage(self.__class__,
1006
                                        common.MESSAGE_TYPE_INFO, msg))
1007
1008
        return messages
1009
1010
    def revert_changes(self, ksdata, storage):
1011
        """:see: RuleHander.revert_changes"""
1012
1013
        if self._firewall_enabled is not None:
1014
            ksdata.firewall.enabled = self._firewall_default_enabled
1015
1016
        # remove all services this handler added
1017
        for svc in self._added_svcs:
1018
            if svc in ksdata.firewall.services:
1019
                ksdata.firewall.services.remove(svc)
1020
1021
        # remove all ports this handler added
1022
        for port in self._added_ports:
1023
            if port in ksdata.firewall.ports:
1024
                ksdata.firewall.ports.remove(port)
1025
1026
        # remove all trusts this handler added
1027
        for trust in self._added_trusts:
1028
            if trust in ksdata.firewall.trusts:
1029
                ksdata.firewall.trusts.remove(trust)
1030
1031
        # remove all services this handler excluded
1032
        for svc in self._removed_svcs:
1033
            if svc in ksdata.firewall.remove_services:
1034
                ksdata.firewall.remove_services.remove(svc)
1035
1036
        self._added_svcs = set()
1037
        self._added_ports = set()
1038
        self._added_trusts = set()
1039
        self._removed_svcs = set()
1040
        self._firewall_enabled = None
1041
        self._firewall_default_enabled = None
1042