diff options
Diffstat (limited to 'dynamic-layers/meta-perl')
28 files changed, 9312 insertions, 0 deletions
diff --git a/dynamic-layers/meta-perl/recipes-scanners/checksecurity/checksecurity_2.0.15.bb b/dynamic-layers/meta-perl/recipes-scanners/checksecurity/checksecurity_2.0.15.bb new file mode 100644 index 0000000..e053a15 --- /dev/null +++ b/dynamic-layers/meta-perl/recipes-scanners/checksecurity/checksecurity_2.0.15.bb | |||
@@ -0,0 +1,21 @@ | |||
1 | SUMMARY = "basic system security checks" | ||
2 | DESCRIPTION = "checksecurity is a simple package which will scan your system for several simple security holes." | ||
3 | SECTION = "security" | ||
4 | LICENSE = "GPL-2.0-only" | ||
5 | LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/GPL-2.0-only;md5=801f80980d171dd6425610833a22dbe6" | ||
6 | |||
7 | SRC_URI = "http://ftp.de.debian.org/debian/pool/main/c/checksecurity/checksecurity_${PV}.tar.gz \ | ||
8 | file://setuid-log-folder.patch \ | ||
9 | file://check-setuid-use-more-portable-find-args.patch" | ||
10 | |||
11 | SRC_URI[md5sum] = "a30161c3e24d3be710b2fd13fcd1f32f" | ||
12 | SRC_URI[sha256sum] = "67abe3d6391c96146e96f376d3fd6eb7a9418b0f7fe205b465219889791dba32" | ||
13 | |||
14 | do_compile() { | ||
15 | } | ||
16 | |||
17 | do_install() { | ||
18 | oe_runmake PREFIX=${D} | ||
19 | } | ||
20 | |||
21 | RDEPENDS:${PN} = "perl libenv-perl perl-module-tie-array perl-module-getopt-long perl-module-file-glob perl-module-carp perl-module-env perl-module-tap-parser-iterator-array util-linux findutils coreutils" | ||
diff --git a/dynamic-layers/meta-perl/recipes-scanners/checksecurity/files/check-setuid-use-more-portable-find-args.patch b/dynamic-layers/meta-perl/recipes-scanners/checksecurity/files/check-setuid-use-more-portable-find-args.patch new file mode 100644 index 0000000..f1fe8ed --- /dev/null +++ b/dynamic-layers/meta-perl/recipes-scanners/checksecurity/files/check-setuid-use-more-portable-find-args.patch | |||
@@ -0,0 +1,23 @@ | |||
1 | From f3073b8e06a607677d47ad9a19533b2e33408a4f Mon Sep 17 00:00:00 2001 | ||
2 | From: Christopher Larson <chris_larson@mentor.com> | ||
3 | Date: Wed, 5 Sep 2018 23:21:43 +0500 | ||
4 | Subject: [PATCH] check-setuid: use more portable find args | ||
5 | |||
6 | Signed-off-by: Christopher Larson <chris_larson@mentor.com> | ||
7 | --- | ||
8 | plugins/check-setuid | 6 +++--- | ||
9 | 1 file changed, 3 insertions(+), 3 deletions(-) | ||
10 | |||
11 | Index: checksecurity-2.0.15/plugins/check-setuid | ||
12 | =================================================================== | ||
13 | --- checksecurity-2.0.15.orig/plugins/check-setuid 2018-09-06 00:49:23.930934294 +0500 | ||
14 | +++ checksecurity-2.0.15/plugins/check-setuid 2018-09-06 00:49:49.694934757 +0500 | ||
15 | @@ -99,7 +99,7 @@ | ||
16 | ionice -t -c3 \ | ||
17 | find `mount | grep -vE "$CHECKSECURITY_FILTER" | cut -d ' ' -f 3` \ | ||
18 | -xdev $PATHCHK \ | ||
19 | - \( -type f -perm +06000 -o \( \( -type b -o -type c \) \ | ||
20 | + \( -type f \( -perm -4000 -o -perm -2000 \) -o \( \( -type b -o -type c \) \ | ||
21 | $DEVCHK \) \) \ | ||
22 | -ignore_readdir_race \ | ||
23 | -printf "%8i %5m %3n %-10u %-10g %9s %t %h/%f\n" | | ||
diff --git a/dynamic-layers/meta-perl/recipes-scanners/checksecurity/files/setuid-log-folder.patch b/dynamic-layers/meta-perl/recipes-scanners/checksecurity/files/setuid-log-folder.patch new file mode 100644 index 0000000..540ea9c --- /dev/null +++ b/dynamic-layers/meta-perl/recipes-scanners/checksecurity/files/setuid-log-folder.patch | |||
@@ -0,0 +1,52 @@ | |||
1 | From 24dbeec135ff83f2fd35ef12fe9842f02d6fd337 Mon Sep 17 00:00:00 2001 | ||
2 | From: Andrei Dinu <andrei.adrianx.dinu@intel.com> | ||
3 | Date: Thu, 20 Jun 2013 15:14:55 +0300 | ||
4 | Subject: [PATCH] changed log folder for check-setuid | ||
5 | |||
6 | check-setuid was creating logs in /var/log directory, | ||
7 | which cannot be created persistently. To avoid errors | ||
8 | the log folder was changed to /etc/checksecurity/. | ||
9 | |||
10 | Signed-off-by: Andrei Dinu <andrei.adrianx.dinu@intel.com> | ||
11 | --- | ||
12 | etc/check-setuid.conf | 2 +- | ||
13 | plugins/check-setuid | 6 +++--- | ||
14 | 2 files changed, 4 insertions(+), 4 deletions(-) | ||
15 | |||
16 | diff --git a/etc/check-setuid.conf b/etc/check-setuid.conf | ||
17 | index 621336f..e1532c0 100644 | ||
18 | --- a/etc/check-setuid.conf | ||
19 | +++ b/etc/check-setuid.conf | ||
20 | @@ -116,4 +116,4 @@ CHECKSECURITY_PATHFILTER="-false" | ||
21 | # | ||
22 | # Location of setuid file databases. | ||
23 | # | ||
24 | -LOGDIR=/var/log/setuid | ||
25 | +LOGDIR=/etc/checksecurity/ | ||
26 | diff --git a/plugins/check-setuid b/plugins/check-setuid | ||
27 | index 8d6f90b..bdb21c1 100755 | ||
28 | --- a/plugins/check-setuid | ||
29 | +++ b/plugins/check-setuid | ||
30 | @@ -44,8 +44,8 @@ if [ `/usr/bin/id -u` != 0 ] ; then | ||
31 | exit 1 | ||
32 | fi | ||
33 | |||
34 | -TMPSETUID=${LOGDIR:=/var/log/setuid}/setuid.new.tmp | ||
35 | -TMPDIFF=${LOGDIR:=/var/log/setuid}/setuid.diff.tmp | ||
36 | +TMPSETUID=${LOGDIR:=/etc/checksecurity/}/setuid.new.tmp | ||
37 | +TMPDIFF=${LOGDIR:=/etc/checksecurity/}/setuid.diff.tmp | ||
38 | |||
39 | # | ||
40 | # Check for NFS/AFS mounts that are not nosuid/nodev | ||
41 | @@ -75,7 +75,7 @@ if [ "$CHECKSECURITY_NOFINDERRORS" = "TRUE" ] ; then | ||
42 | fi | ||
43 | |||
44 | # Guard against undefined vars | ||
45 | -[ -z "$LOGDIR" ] && LOGDIR=/var/log/setuid | ||
46 | +[ -z "$LOGDIR" ] && LOGDIR=/etc/checksecurity/ | ||
47 | if [ ! -e "$LOGDIR" ] ; then | ||
48 | echo "ERROR: Log directory $LOGDIR does not exist" | ||
49 | exit 1 | ||
50 | -- | ||
51 | 1.7.9.5 | ||
52 | |||
diff --git a/dynamic-layers/meta-perl/recipes-security/bastille/bastille_3.2.1.bb b/dynamic-layers/meta-perl/recipes-security/bastille/bastille_3.2.1.bb new file mode 100644 index 0000000..e7852d9 --- /dev/null +++ b/dynamic-layers/meta-perl/recipes-security/bastille/bastille_3.2.1.bb | |||
@@ -0,0 +1,166 @@ | |||
1 | #The functionality of Bastille that is actually available is restricted. Please | ||
2 | #consult the README file for the meta-security layer for additional information. | ||
3 | SUMMARY = "Linux hardening tool" | ||
4 | DESCRIPTION = "Bastille Linux is a Hardening and Reporting/Auditing Program which enhances the security of a Linux box, by configuring daemons, system settings and firewalling." | ||
5 | LICENSE = "GPL-2.0-only" | ||
6 | LIC_FILES_CHKSUM = "file://${S}/COPYING;md5=c93c0550bd3173f4504b2cbd8991e50b" | ||
7 | # Bash is needed for set +o privileged (check busybox), might also need ncurses | ||
8 | DEPENDS = "virtual/kernel" | ||
9 | RDEPENDS:${PN} = "perl bash tcl perl-module-getopt-long perl-module-text-wrap lib-perl perl-module-file-path perl-module-mime-base64 perl-module-file-find perl-module-errno perl-module-file-glob perl-module-tie-hash-namedcapture perl-module-file-copy perl-module-english perl-module-exporter perl-module-cwd libcurses-perl coreutils" | ||
10 | FILES:${PN} += "/run/lock/subsys/bastille" | ||
11 | |||
12 | SRC_URI = "http://sourceforge.net/projects/bastille-linux/files/bastille-linux/3.2.1/Bastille-3.2.1.tar.bz2 \ | ||
13 | file://AccountPermission.pm \ | ||
14 | file://FileContent.pm \ | ||
15 | file://HPSpecific.pm \ | ||
16 | file://Miscellaneous.pm \ | ||
17 | file://ServiceAdmin.pm \ | ||
18 | file://config \ | ||
19 | file://fix_version_parse.patch \ | ||
20 | file://fixed_defined_warnings.patch \ | ||
21 | file://call_output_config.patch \ | ||
22 | file://fix_missing_use_directives.patch \ | ||
23 | file://fix_number_of_modules.patch \ | ||
24 | file://remove_questions_text_file_references.patch \ | ||
25 | file://simplify_B_place.patch \ | ||
26 | file://find_existing_config.patch \ | ||
27 | file://upgrade_options_processing.patch \ | ||
28 | file://accept_os_flag_in_backend.patch \ | ||
29 | file://allow_os_with_assess.patch \ | ||
30 | file://edit_usage_message.patch \ | ||
31 | file://organize_distro_discovery.patch \ | ||
32 | file://do_not_apply_config.patch \ | ||
33 | " | ||
34 | |||
35 | SRC_URI[md5sum] = "df803f7e38085aa5da79f85d0539f91b" | ||
36 | SRC_URI[sha256sum] = "0ea25191b1dc1c8f91e1b6f8cb5436a3aa1e57418809ef902293448efed5021a" | ||
37 | |||
38 | S = "${WORKDIR}/Bastille" | ||
39 | |||
40 | do_install () { | ||
41 | install -d ${D}${sbindir} | ||
42 | install -d ${D}${libdir}/perl5/site_perl/Curses | ||
43 | |||
44 | install -d ${D}${libdir}/Bastille | ||
45 | install -d ${D}${libdir}/Bastille/API | ||
46 | install -d ${D}${datadir}/Bastille | ||
47 | install -d ${D}${datadir}/Bastille/OSMap | ||
48 | install -d ${D}${datadir}/Bastille/OSMap/Modules | ||
49 | install -d ${D}${datadir}/Bastille/Questions | ||
50 | install -d ${D}${datadir}/Bastille/FKL/configs/ | ||
51 | install -d ${D}${sysconfdir}/Bastille | ||
52 | install -m 0755 AutomatedBastille ${D}${sbindir} | ||
53 | install -m 0755 BastilleBackEnd ${D}${sbindir} | ||
54 | install -m 0755 InteractiveBastille ${D}${sbindir} | ||
55 | install -m 0644 Modules.txt ${D}${datadir}/Bastille | ||
56 | # New Weights file(s). | ||
57 | install -m 0644 Weights.txt ${D}${datadir}/Bastille | ||
58 | # Castle graphic | ||
59 | install -m 0644 bastille.jpg ${D}${datadir}/Bastille/ | ||
60 | # Javascript file | ||
61 | install -m 0644 wz_tooltip.js ${D}${datadir}/Bastille/ | ||
62 | install -m 0644 Credits ${D}${datadir}/Bastille | ||
63 | install -m 0644 FKL/configs/fkl_config_redhat.cfg ${D}${datadir}/Bastille/FKL/configs/ | ||
64 | install -m 0755 RevertBastille ${D}${sbindir} | ||
65 | install -m 0755 bin/bastille ${D}${sbindir} | ||
66 | install -m 0644 bastille-firewall ${D}${datadir}/Bastille | ||
67 | install -m 0644 bastille-firewall-reset ${D}${datadir}/Bastille | ||
68 | install -m 0644 bastille-firewall-schedule ${D}${datadir}/Bastille | ||
69 | install -m 0644 bastille-tmpdir-defense.sh ${D}${datadir}/Bastille | ||
70 | install -m 0644 bastille-tmpdir.csh ${D}${datadir}/Bastille | ||
71 | install -m 0644 bastille-tmpdir.sh ${D}${datadir}/Bastille | ||
72 | install -m 0644 bastille-firewall.cfg ${D}${datadir}/Bastille | ||
73 | install -m 0644 bastille-ipchains ${D}${datadir}/Bastille | ||
74 | install -m 0644 bastille-netfilter ${D}${datadir}/Bastille | ||
75 | install -m 0644 bastille-firewall-early.sh ${D}${datadir}/Bastille | ||
76 | install -m 0644 bastille-firewall-pre-audit.sh ${D}${datadir}/Bastille | ||
77 | install -m 0644 complete.xbm ${D}${datadir}/Bastille | ||
78 | install -m 0644 incomplete.xbm ${D}${datadir}/Bastille | ||
79 | install -m 0644 disabled.xpm ${D}${datadir}/Bastille | ||
80 | install -m 0644 ifup-local ${D}${datadir}/Bastille | ||
81 | install -m 0644 hosts.allow ${D}${datadir}/Bastille | ||
82 | |||
83 | install -m 0644 Bastille/AccountSecurity.pm ${D}${libdir}/Bastille | ||
84 | install -m 0644 Bastille/Apache.pm ${D}${libdir}/Bastille | ||
85 | install -m 0644 Bastille/API.pm ${D}${libdir}/Bastille | ||
86 | install -m 0644 ${WORKDIR}/AccountPermission.pm ${D}${libdir}/Bastille/API | ||
87 | install -m 0644 ${WORKDIR}/FileContent.pm ${D}${libdir}/Bastille/API | ||
88 | install -m 0644 ${WORKDIR}/HPSpecific.pm ${D}${libdir}/Bastille/API | ||
89 | install -m 0644 ${WORKDIR}/ServiceAdmin.pm ${D}${libdir}/Bastille/API | ||
90 | install -m 0644 ${WORKDIR}/Miscellaneous.pm ${D}${libdir}/Bastille/API | ||
91 | install -m 0644 Bastille/BootSecurity.pm ${D}${libdir}/Bastille | ||
92 | install -m 0644 Bastille/ConfigureMiscPAM.pm ${D}${libdir}/Bastille | ||
93 | install -m 0644 Bastille/DisableUserTools.pm ${D}${libdir}/Bastille | ||
94 | install -m 0644 Bastille/DNS.pm ${D}${libdir}/Bastille | ||
95 | install -m 0644 Bastille/FilePermissions.pm ${D}${libdir}/Bastille | ||
96 | install -m 0644 Bastille/FTP.pm ${D}${libdir}/Bastille | ||
97 | install -m 0644 Bastille/Firewall.pm ${D}${libdir}/Bastille | ||
98 | install -m 0644 Bastille/OSX_API.pm ${D}${libdir}/Bastille | ||
99 | install -m 0644 Bastille/LogAPI.pm ${D}${libdir}/Bastille | ||
100 | install -m 0644 Bastille/HP_UX.pm ${D}${libdir}/Bastille | ||
101 | install -m 0644 Bastille/IOLoader.pm ${D}${libdir}/Bastille | ||
102 | install -m 0644 Bastille/Patches.pm ${D}${libdir}/Bastille | ||
103 | install -m 0644 Bastille/Logging.pm ${D}${libdir}/Bastille | ||
104 | install -m 0644 Bastille/MiscellaneousDaemons.pm ${D}${libdir}/Bastille | ||
105 | install -m 0644 Bastille/PatchDownload.pm ${D}${libdir}/Bastille | ||
106 | install -m 0644 Bastille/Printing.pm ${D}${libdir}/Bastille | ||
107 | install -m 0644 Bastille/PSAD.pm ${D}${libdir}/Bastille | ||
108 | install -m 0644 Bastille/RemoteAccess.pm ${D}${libdir}/Bastille | ||
109 | install -m 0644 Bastille/SecureInetd.pm ${D}${libdir}/Bastille | ||
110 | install -m 0644 Bastille/Sendmail.pm ${D}${libdir}/Bastille | ||
111 | install -m 0644 Bastille/TestDriver.pm ${D}${libdir}/Bastille | ||
112 | install -m 0644 Bastille/TMPDIR.pm ${D}${libdir}/Bastille | ||
113 | install -m 0644 Bastille/test_AccountSecurity.pm ${D}${libdir}/Bastille | ||
114 | install -m 0644 Bastille/test_Apache.pm ${D}${libdir}/Bastille | ||
115 | install -m 0644 Bastille/test_DNS.pm ${D}${libdir}/Bastille | ||
116 | install -m 0644 Bastille/test_FTP.pm ${D}${libdir}/Bastille | ||
117 | install -m 0644 Bastille/test_HP_UX.pm ${D}${libdir}/Bastille | ||
118 | install -m 0644 Bastille/test_MiscellaneousDaemons.pm ${D}${libdir}/Bastille | ||
119 | install -m 0644 Bastille/test_Patches.pm ${D}${libdir}/Bastille | ||
120 | install -m 0644 Bastille/test_SecureInetd.pm ${D}${libdir}/Bastille | ||
121 | install -m 0644 Bastille/test_Sendmail.pm ${D}${libdir}/Bastille | ||
122 | install -m 0644 Bastille/test_BootSecurity.pm ${D}${libdir}/Bastille | ||
123 | install -m 0644 Bastille/test_DisableUserTools.pm ${D}${libdir}/Bastille | ||
124 | install -m 0644 Bastille/test_FilePermissions.pm ${D}${libdir}/Bastille | ||
125 | install -m 0644 Bastille/test_Logging.pm ${D}${libdir}/Bastille | ||
126 | install -m 0644 Bastille/test_Printing.pm ${D}${libdir}/Bastille | ||
127 | install -m 0644 Bastille/IPFilter.pm ${D}${libdir}/Bastille | ||
128 | install -m 0644 Bastille_Curses.pm ${D}${libdir}/perl5/site_perl | ||
129 | install -m 0644 Bastille_Tk.pm ${D}${libdir}/perl5/site_perl | ||
130 | install -m 0644 Curses/Widgets.pm ${D}${libdir}/perl5/site_perl/Curses | ||
131 | |||
132 | install -m 0644 OSMap/LINUX.bastille ${D}${datadir}/Bastille/OSMap | ||
133 | install -m 0644 OSMap/LINUX.system ${D}${datadir}/Bastille/OSMap | ||
134 | install -m 0644 OSMap/LINUX.service ${D}${datadir}/Bastille/OSMap | ||
135 | install -m 0644 OSMap/HP-UX.bastille ${D}${datadir}/Bastille/OSMap | ||
136 | install -m 0644 OSMap/HP-UX.system ${D}${datadir}/Bastille/OSMap | ||
137 | install -m 0644 OSMap/HP-UX.service ${D}${datadir}/Bastille/OSMap | ||
138 | install -m 0644 OSMap/OSX.bastille ${D}${datadir}/Bastille/OSMap | ||
139 | install -m 0644 OSMap/OSX.system ${D}${datadir}/Bastille/OSMap | ||
140 | |||
141 | install -m 0777 ${WORKDIR}/config ${D}${sysconfdir}/Bastille/config | ||
142 | |||
143 | for file in `cat Modules.txt` ; do | ||
144 | install -m 0644 Questions/$file.txt ${D}${datadir}/Bastille/Questions | ||
145 | done | ||
146 | |||
147 | ${THISDIR}/files/set_required_questions.py ${D}${sysconfdir}/Bastille/config ${D}${datadir}/Bastille/Questions | ||
148 | |||
149 | ln -s RevertBastille ${D}${sbindir}/UndoBastille | ||
150 | |||
151 | # Create /var/log/Bastille in runtime. | ||
152 | if [ "${@bb.utils.filter('DISTRO_FEATURES', 'systemd', d)}" ]; then | ||
153 | install -d ${D}${nonarch_libdir}/tmpfiles.d | ||
154 | echo "d ${localstatedir}/log/Bastille - - - -" > ${D}${nonarch_libdir}/tmpfiles.d/Bastille.conf | ||
155 | fi | ||
156 | if [ "${@bb.utils.filter('DISTRO_FEATURES', 'sysvinit', d)}" ]; then | ||
157 | install -d ${D}${sysconfdir}/default/volatiles | ||
158 | echo "d root root 0755 ${localstatedir}/log/Bastille none" > ${D}${sysconfdir}/default/volatiles/99_Bastille | ||
159 | fi | ||
160 | } | ||
161 | |||
162 | FILES:${PN} += "${datadir}/Bastille \ | ||
163 | ${libdir}/Bastille \ | ||
164 | ${libdir}/perl* \ | ||
165 | ${sysconfdir}/* \ | ||
166 | ${nonarch_libdir}/tmpfiles.d" | ||
diff --git a/dynamic-layers/meta-perl/recipes-security/bastille/files/API.pm b/dynamic-layers/meta-perl/recipes-security/bastille/files/API.pm new file mode 100644 index 0000000..5060f52 --- /dev/null +++ b/dynamic-layers/meta-perl/recipes-security/bastille/files/API.pm | |||
@@ -0,0 +1,2528 @@ | |||
1 | # Copyright (C) 1999-2007 Jay Beale | ||
2 | # Copyright (C) 2001-2008 Hewlett-Packard Development Company, L.P. | ||
3 | # Licensed under the GNU General Public License, version 2 | ||
4 | |||
5 | package Bastille::API; | ||
6 | |||
7 | ## TO DO: | ||
8 | # | ||
9 | # | ||
10 | # 1) Look for more places to insert error handling... | ||
11 | # | ||
12 | # 2) Document this module more | ||
13 | # | ||
14 | # | ||
15 | |||
16 | |||
17 | ########################################################################## | ||
18 | # | ||
19 | # This module forms the basis for the v1.1 API. | ||
20 | # | ||
21 | ########################################################################## | ||
22 | |||
23 | # | ||
24 | # This module forms the initial basis for the Bastille Engine, implemented | ||
25 | # presently via a Perl API for Perl modules. | ||
26 | # | ||
27 | # This is still under construction -- it is very usable, but not very well | ||
28 | # documented, yet. | ||
29 | # | ||
30 | |||
31 | ########################################################################## | ||
32 | # | ||
33 | # API Function Listing | ||
34 | # | ||
35 | ########################################################################## | ||
36 | # The routines which should be called by Bastille modules are listed here, | ||
37 | # though they are better documented throughout this file. | ||
38 | # | ||
39 | # Distro Specific Stuff: | ||
40 | # | ||
41 | # &GetDistro - figures out what distro we're running, if it knows it... | ||
42 | # &ConfigureForDistro - sets global variables based on the distro | ||
43 | # &GetGlobal - returns hash values defined in ConfigureForDistro | ||
44 | # | ||
45 | # &getGlobalConfig - returns value of hash set up by ReadConfig | ||
46 | # | ||
47 | # Logging Specific Stuff has moved to LogAPI.pm: | ||
48 | # | ||
49 | # &B_log(type,msg) -- takes care of all logging | ||
50 | # | ||
51 | # | ||
52 | # Input functions for the old input method... | ||
53 | # | ||
54 | # File open/close/backup functions | ||
55 | # | ||
56 | # &B_open * -- opens a file handle and logs the action/error (OLD WAY!) | ||
57 | # &B_open_plus -- opens a pair of file handles for the old and new version | ||
58 | # of a file; respects logonly flag. (NEW WAY) | ||
59 | # &B_close * -- closes a file handle and logs the action/error (OLD WAY!) | ||
60 | # &B_close_plus -- closes a pair of file handles opened by B_open_plus, | ||
61 | # backing up one file and renaming the new file to the | ||
62 | # old one's name, logging actions/errors. Respects the | ||
63 | # logonly flag -- needs B_backup file. Finally, sets | ||
64 | # new file's mode,uid,gid to old file's... (NEW WAY) | ||
65 | # &B_backup_file - backs up a file that is being changed/deleted into the | ||
66 | # $GLOBAL_BDIR{"backup"} directory. | ||
67 | # | ||
68 | # Non-content file modification functions | ||
69 | # | ||
70 | # &B_delete_file - deletes the named file, backing up a copy | ||
71 | # &B_create_file - creates the named file, if it doesn't exist | ||
72 | # | ||
73 | # &B_symlink - create a symlink to a file, recording the revert rm | ||
74 | # | ||
75 | # More stuff | ||
76 | # | ||
77 | # &B_createdir - make a directory, if it doesn't exist, record revert rmdir | ||
78 | # &B_cp - copy a file, respecting LOGONLY and revert func. | ||
79 | # &B_mknod - wrap mknod with revert and logonly and prefix functionality | ||
80 | # | ||
81 | # &B_read_sums - reads sum.csv file and parses input into the GLOBAL_SUM hash | ||
82 | # &B_write_sums - writes sum.csv file from GLOBAL_SUM hash | ||
83 | # &B_check_sum($) - take a file name and compares the stored cksum with the current | ||
84 | # cksum of said file | ||
85 | # &B_set_sum($) - takes a file name and gets that files current cksum then sets | ||
86 | # that sum in the GLOBAL_SUM hash | ||
87 | # &B_revert_log - create entry in shell script, executed later by bastille -r | ||
88 | # &showDisclaimer - Print the disclaimer and wait for 5 minutes for acceptance | ||
89 | ########################################################################### | ||
90 | # Note: GLOBAL_VERBOSE | ||
91 | # | ||
92 | # All logging functions now check GLOBAL_VERBOSE and, if set, will print | ||
93 | # all the information sent to log files to STDOUT/STDERR as well. | ||
94 | # | ||
95 | |||
96 | # | ||
97 | # Note: GLOBAL_LOGONLY | ||
98 | # | ||
99 | # All Bastille API functions now check for the existence of a GLOBAL_LOGONLY | ||
100 | # variable. When said variable is set, no function actually modifies the | ||
101 | # system. | ||
102 | # | ||
103 | # Note: GLOBAL_DEBUG | ||
104 | # | ||
105 | # The B_log("DEBUG",...) function now checks GLOBAL_DEBUG and, if set, it will | ||
106 | # print all the information to a new debug-log file. If GLOBAL_VERBOSE is | ||
107 | # set it might log to STDOUT/STDERR as well (not yet implemented, pending | ||
108 | # discussion). Developers should populate appropriate places with &B_log(DEBUG) | ||
109 | # in order to be able to tell users to use this options and send the logs | ||
110 | # for inspection and debugging. | ||
111 | # | ||
112 | # | ||
113 | |||
114 | |||
115 | # Libraries for the Backup_file routine: Cwd and File::Path | ||
116 | use Cwd; | ||
117 | use Bastille::OSX_API; | ||
118 | use Bastille::LogAPI; | ||
119 | use File::Path; | ||
120 | use File::Basename; | ||
121 | |||
122 | # Export the API functions listed below for use by the modules. | ||
123 | |||
124 | use Exporter; | ||
125 | @ISA = qw ( Exporter ); | ||
126 | @EXPORT = qw( | ||
127 | setOptions GetDistro ConfigureForDistro B_log B_revert_log | ||
128 | SanitizeEnv | ||
129 | B_open B_close B_symlink StopLogging | ||
130 | B_open_plus B_close_plus | ||
131 | B_isFileinSumDB | ||
132 | B_create_file B_read_sums B_check_sum B_set_sum isSumDifferent listModifiedFiles | ||
133 | B_create_dir B_create_log_file | ||
134 | B_delete_file | ||
135 | B_cp B_place B_mknod | ||
136 | showDisclaimer | ||
137 | getSupportedOSHash | ||
138 | B_Backtick | ||
139 | B_System | ||
140 | isProcessRunning | ||
141 | checkProcsForService | ||
142 | |||
143 | |||
144 | $GLOBAL_OS $GLOBAL_ACTUAL_OS $CLI | ||
145 | $GLOBAL_LOGONLY $GLOBAL_VERBOSE $GLOBAL_DEBUG $GLOBAL_AUDITONLY $GLOBAL_AUDIT_NO_BROWSER $errorFlag | ||
146 | %GLOBAL_BIN %GLOBAL_DIR %GLOBAL_FILE | ||
147 | %GLOBAL_BDIR %GLOBAL_BFILE | ||
148 | %GLOBAL_CONFIG %GLOBAL_SUM | ||
149 | |||
150 | %GLOBAL_SERVICE %GLOBAL_SERVTYPE %GLOBAL_PROCESS %GLOBAL_RC_CONFIG | ||
151 | %GLOBAL_TEST | ||
152 | |||
153 | getGlobal setGlobal getGlobalConfig | ||
154 | |||
155 | |||
156 | B_parse_fstab | ||
157 | B_parse_mtab B_is_rpm_up_to_date | ||
158 | |||
159 | NOTSECURE_CAN_CHANGE SECURE_CANT_CHANGE | ||
160 | NOT_INSTALLED INCONSISTENT MANUAL NOTEST SECURE_CAN_CHANGE | ||
161 | STRING_NOT_DEFINED NOT_INSTALLED_NOTSECURE DONT_KNOW | ||
162 | RELEVANT_HEADERQ NOTRELEVANT_HEADERQ | ||
163 | ); | ||
164 | |||
165 | |||
166 | |||
167 | ###################################################### | ||
168 | ###Testing Functions | ||
169 | ################################################################## | ||
170 | |||
171 | #Define "Constants" for test functions. Note these constants sometimes get | ||
172 | #interpreted as literal strings when used as hash references, so you may | ||
173 | # have to use CONSTANT() to disambiguate, like below. Sorry, it was either | ||
174 | # that or create even *more* global variables. | ||
175 | # See TestDriver.pm for definitions, and test design doc for full explaination | ||
176 | use constant { | ||
177 | NOTSECURE_CAN_CHANGE => 0, | ||
178 | SECURE_CANT_CHANGE => 1, | ||
179 | NOT_INSTALLED => 2, # (where the lack makes the system secure, eg telnet) | ||
180 | INCONSISTENT => 3, | ||
181 | MANUAL => 4, | ||
182 | NOTEST => 5, | ||
183 | SECURE_CAN_CHANGE => 6, | ||
184 | STRING_NOT_DEFINED => 7, | ||
185 | NOT_INSTALLED_NOTSECURE => 8, #(Where the missing s/w makes the system less secure eg IPFilter) | ||
186 | #Intentional duplicates follow | ||
187 | DONT_KNOW => 5, | ||
188 | RELEVANT_HEADERQ => 6, | ||
189 | NOTRELEVANT_HEADERQ => 0 | ||
190 | }; | ||
191 | |||
192 | &SanitizeEnv; | ||
193 | |||
194 | # Set up some common error messages. These are independent of | ||
195 | # operating system | ||
196 | |||
197 | # These will allow us to line up the warnings and error messages | ||
198 | my $err ="ERROR: "; | ||
199 | my $spc =" "; | ||
200 | my $GLOBAL_OS="None"; | ||
201 | my $GLOBAL_ACTUAL_OS="None"; | ||
202 | my %GLOBAL_SUMS=(); | ||
203 | my $CLI=''; | ||
204 | |||
205 | #OS independent Error Messages Follow, normally "bastille" script filters | ||
206 | #options before interactive or Bastille runs, so this check is often redundant | ||
207 | $GLOBAL_ERROR{"usage"}="\n". | ||
208 | "$spc Usage: bastille [ -b | -c | -x ] [ --os <version> ] [ -f <alternate config> ]\n". | ||
209 | "$spc bastille [ -r | --assess | --assessnobowser ]\n\n". | ||
210 | "$spc --assess : check status of system and report in browser\n". | ||
211 | "$spc --assessnobrowser : check status of system and list report locations\n". | ||
212 | "$spc -b : use a saved config file to apply changes\n". | ||
213 | "$spc directly to system\n". | ||
214 | "$spc -c : use the Curses (non-X11) TUI\n". | ||
215 | "$spc -f <alternate config>: populate answers with a different config file\n". | ||
216 | "$spc -r : revert all Bastille changes to-date\n". | ||
217 | "$spc -x : use the Perl/Tk (X11) GUI\n" . | ||
218 | "$spc --os <version> : ask all questions for the given operating system\n" . | ||
219 | "$spc version. e.g. --os RH6.0\n"; | ||
220 | |||
221 | # These options don't work universally, so it's best not to | ||
222 | # document them here (yet). Hopefully, we'll get them | ||
223 | # straightened out soon. | ||
224 | #"$spc --log : log-only option\n". | ||
225 | #"$spc -v : verbose mode\n". | ||
226 | #"$spc --debug : debug mode\n"; | ||
227 | |||
228 | |||
229 | ############################################################################## | ||
230 | # | ||
231 | # Directory structure for Bastille Linux v1.2 and up | ||
232 | # | ||
233 | ############################################################################## | ||
234 | # | ||
235 | # /usr/sbin/ -- location of Bastille binaries | ||
236 | # /usr/lib/Bastille -- location of Bastille modules | ||
237 | # /usr/share/Bastille -- location of Bastille data files | ||
238 | # /etc/Bastille -- location of Bastille config files | ||
239 | # | ||
240 | # /var/log/Bastille -- location of Bastille log files | ||
241 | # /var/log/Bastille/revert -- directory holding all Bastille-created revert scripts | ||
242 | # /var/log/Bastille/revert/backup -- directory holding the original files that | ||
243 | # Bastille modifies, with permissions intact | ||
244 | # | ||
245 | ############################################################################## | ||
246 | |||
247 | ############################################################################## | ||
248 | # | ||
249 | # Directory structure for HP-UX Bastille v2.0 and up | ||
250 | # | ||
251 | ############################################################################## | ||
252 | # | ||
253 | # /opt/sec_mgmt/bastille/bin/ -- location of Bastille binaries | ||
254 | # /opt/sec_mgmt/bastille/lib/ -- location of Bastille modules | ||
255 | # /etc/opt/sec_mgmt/bastille/ -- location of Bastille data and config files | ||
256 | # | ||
257 | # /var/opt/sec_mgmt/bastille/log/ -- location of Bastille log files | ||
258 | # /var/opt/sec_mgmt/bastille/revert -- directory holding all Bastille-created | ||
259 | # revert scripts and save files | ||
260 | # | ||
261 | ############################################################################## | ||
262 | |||
263 | |||
264 | ############################################################################## | ||
265 | ############################################################################## | ||
266 | ################## Actual functions start here... ########################### | ||
267 | ############################################################################## | ||
268 | ############################################################################## | ||
269 | |||
270 | ########################################################################### | ||
271 | # setOptions takes six arguments, $GLOBAL_DEBUG, $GLOBAL_LOGONLY, | ||
272 | # $GLOBAL_VERBOSE, $GLOBAL_AUDITONLY, $GLOBAL_AUDIT_NO_BROWSER, and GLOBAL_OS; | ||
273 | ########################################################################### | ||
274 | sub setOptions($$$$$$) { | ||
275 | ($GLOBAL_DEBUG,$GLOBAL_LOGONLY,$GLOBAL_VERBOSE,$GLOBAL_AUDITONLY, | ||
276 | $GLOBAL_AUDIT_NO_BROWSER,$GLOBAL_OS) = @_; | ||
277 | if ($GLOBAL_AUDIT_NO_BROWSER) { | ||
278 | $GLOBAL_AUDITONLY = 1; | ||
279 | } | ||
280 | if (not(defined($GLOBAL_OS))){ | ||
281 | $GLOBAL_OS="None"; | ||
282 | } | ||
283 | } | ||
284 | ########################################################################### | ||
285 | # | ||
286 | # SanitizeEnv load a proper environment so Bastille cannot be tricked | ||
287 | # and Perl modules work correctly. | ||
288 | # | ||
289 | ########################################################################### | ||
290 | sub SanitizeEnv { | ||
291 | delete @ENV{'IFS','CDPATH','ENV','BASH_ENV'}; | ||
292 | $ENV{CDPATH}="."; | ||
293 | $ENV{BASH_ENV}= ""; | ||
294 | # Bin is needed here or else /usr/lib/perl5/5.005/Cwd.pm | ||
295 | # will not find `pwd` | ||
296 | # Detected while testing with -w, jfs | ||
297 | $ENV{PATH} = "/bin:/usr/bin"; | ||
298 | # Giorgi, is /usr/local/bin needed? (jfs) | ||
299 | } | ||
300 | |||
301 | ########################################################################### | ||
302 | # | ||
303 | # GetDistro checks to see if the target is a known distribution and reports | ||
304 | # said distribution. | ||
305 | # | ||
306 | # This is used throughout the script, but also by ConfigureForDistro. | ||
307 | # | ||
308 | # | ||
309 | ########################################################################### | ||
310 | |||
311 | sub GetDistro() { | ||
312 | |||
313 | my ($release,$distro); | ||
314 | |||
315 | # Only read files for the distro once. | ||
316 | # if the --os option was used then | ||
317 | if ($GLOBAL_OS eq "None") { | ||
318 | if ( -e "/etc/mandrake-release" ) { | ||
319 | open(MANDRAKE_RELEASE,"/etc/mandrake-release"); | ||
320 | $release=<MANDRAKE_RELEASE>; | ||
321 | |||
322 | if ( ($release =~ /^Mandrake Linux release (\d+\.\d+\w*)/) or ($release =~ /^Linux Mandrake release (\d+\.\d+\w*)/) ) { | ||
323 | $distro="MN$1"; | ||
324 | } | ||
325 | elsif ( $release =~ /^Mandrakelinux release (\d+\.\d+)\b/ ) { | ||
326 | $distro="MN$1"; | ||
327 | } | ||
328 | else { | ||
329 | print STDERR "$err Couldn't determine Mandrake/Mandriva version! Setting to 10.1!\n"; | ||
330 | $distro="MN10.1"; | ||
331 | } | ||
332 | |||
333 | close(MANDRAKE_RELEASE); | ||
334 | } | ||
335 | elsif ( -e "/etc/immunix-release" ) { | ||
336 | open(IMMUNIX_RELEASE,"/etc/immunix-release"); | ||
337 | $release=<IMMUNIX_RELEASE>; | ||
338 | unless ($release =~ /^Immunix Linux release (\d+\.\d+\w*)/) { | ||
339 | print STDERR "$err Couldn't determine Immunix version! Setting to 6.2!\n"; | ||
340 | $distro="RH6.2"; | ||
341 | } | ||
342 | else { | ||
343 | $distro="RH$1"; | ||
344 | } | ||
345 | close(*IMMUNIX_RELEASE); | ||
346 | } | ||
347 | elsif ( -e '/etc/fedora-release' ) { | ||
348 | open(FEDORA_RELEASE,'/etc/fedora-release'); | ||
349 | $release=<FEDORA_RELEASE>; | ||
350 | close FEDORA_RELEASE; | ||
351 | if ($release =~ /^Fedora Core release (\d+\.?\d*)/) { | ||
352 | $distro = "RHFC$1"; | ||
353 | } | ||
354 | elsif ($release =~ /^Fedora release (\d+\.?\d*)/) { | ||
355 | $distro = "RHFC$1"; | ||
356 | } | ||
357 | else { | ||
358 | print STDERR "$err Could not determine Fedora version! Setting to Fedora Core 8\n"; | ||
359 | $distro='RHFC8'; | ||
360 | } | ||
361 | } | ||
362 | elsif ( -e "/etc/redhat-release" ) { | ||
363 | open(*REDHAT_RELEASE,"/etc/redhat-release"); | ||
364 | $release=<REDHAT_RELEASE>; | ||
365 | if ($release =~ /^Red Hat Linux release (\d+\.?\d*\w*)/) { | ||
366 | $distro="RH$1"; | ||
367 | } | ||
368 | elsif ($release =~ /^Red Hat Linux .+ release (\d+)\.?\d*([AEW]S)/) { | ||
369 | $distro="RHEL$1$2"; | ||
370 | } | ||
371 | elsif ($release =~ /^Red Hat Enterprise Linux ([AEW]S) release (\d+)/) { | ||
372 | $distro="RHEL$2$1"; | ||
373 | } | ||
374 | elsif ($release =~ /^CentOS release (\d+\.\d+)/) { | ||
375 | my $version = $1; | ||
376 | if ($version =~ /^4\./) { | ||
377 | $distro='RHEL4AS'; | ||
378 | } | ||
379 | elsif ($version =~ /^3\./) { | ||
380 | $distro='RHEL3AS'; | ||
381 | } | ||
382 | else { | ||
383 | print STDERR "$err Could not determine CentOS version! Setting to Red Hat Enterprise 4 AS.\n"; | ||
384 | $distro='RHEL4AS'; | ||
385 | } | ||
386 | } | ||
387 | else { | ||
388 | # JJB/HP - Should this be B_log? | ||
389 | print STDERR "$err Couldn't determine Red Hat version! Setting to 9!\n"; | ||
390 | $distro="RH9"; | ||
391 | } | ||
392 | close(REDHAT_RELEASE); | ||
393 | |||
394 | } | ||
395 | elsif ( -e "/etc/debian_version" ) { | ||
396 | $stable="3.1"; #Change this when Debian stable changes | ||
397 | open(*DEBIAN_RELEASE,"/etc/debian_version"); | ||
398 | $release=<DEBIAN_RELEASE>; | ||
399 | unless ($release =~ /^(\d+\.\d+\w*)/) { | ||
400 | print STDERR "$err System is not running a stable Debian GNU/Linux version. Setting to $stable.\n"; | ||
401 | $distro="DB$stable"; | ||
402 | } | ||
403 | else { | ||
404 | $distro="DB$1"; | ||
405 | } | ||
406 | close(DEBIAN_RELEASE); | ||
407 | } | ||
408 | elsif ( -e "/etc/SuSE-release" ) { | ||
409 | open(*SUSE_RELEASE,"/etc/SuSE-release"); | ||
410 | $release=<SUSE_RELEASE>; | ||
411 | if ($release =~ /^SuSE Linux (\d+\.\d+\w*)/i) { | ||
412 | $distro="SE$1"; | ||
413 | } | ||
414 | elsif ($release =~ /^SUSE LINUX Enterprise Server (\d+\.?\d?\w*)/i) { | ||
415 | $distro="SESLES$1"; | ||
416 | } | ||
417 | elsif ($release =~ /^SUSE Linux Enterprise Server (\d+\.?\d?\w*)/i) { | ||
418 | $distro="SESLES$1"; | ||
419 | } | ||
420 | elsif ($release =~ /^openSuSE (\d+\.\d+\w*)/i) { | ||
421 | $distro="SE$1"; | ||
422 | } | ||
423 | else { | ||
424 | print STDERR "$err Couldn't determine SuSE version! Setting to 10.3!\n"; | ||
425 | $distro="SE10.3"; | ||
426 | } | ||
427 | close(SUSE_RELEASE); | ||
428 | } | ||
429 | elsif ( -e "/etc/turbolinux-release") { | ||
430 | open(*TURBOLINUX_RELEASE,"/etc/turbolinux-release"); | ||
431 | $release=<TURBOLINUX_RELEASE>; | ||
432 | unless ($release =~ /^Turbolinux Workstation (\d+\.\d+\w*)/) { | ||
433 | print STDERR "$err Couldn't determine TurboLinux version! Setting to 7.0!\n"; | ||
434 | $distro="TB7.0"; | ||
435 | } | ||
436 | else { | ||
437 | $distro="TB$1"; | ||
438 | } | ||
439 | close(TURBOLINUX_RELEASE); | ||
440 | } | ||
441 | else { | ||
442 | # We're either on Mac OS X, HP-UX or an unsupported O/S. | ||
443 | if ( -x '/usr/bin/uname') { | ||
444 | # uname is in /usr/bin on Mac OS X and HP-UX | ||
445 | $release=`/usr/bin/uname -sr`; | ||
446 | } | ||
447 | else { | ||
448 | print STDERR "$err Could not determine operating system version!\n"; | ||
449 | $distro="unknown"; | ||
450 | } | ||
451 | |||
452 | # Figure out what kind of system we're on. | ||
453 | if ($release ne "") { | ||
454 | if ($release =~ /^Darwin\s+(\d+)\.(\d+)/) { | ||
455 | if ($1 == 6 ) { | ||
456 | $distro = "OSX10.2"; | ||
457 | } | ||
458 | elsif ($1 == 7) { | ||
459 | $distro = "OSX10.3"; | ||
460 | } | ||
461 | elsif ($1 == 8) { | ||
462 | $distro = "OSX10.3"; | ||
463 | } | ||
464 | else { | ||
465 | $distro = "unknown"; | ||
466 | } | ||
467 | } | ||
468 | elsif ( $release =~ /(^HP-UX)\s*B\.(\d+\.\d+)/ ) { | ||
469 | $distro="$1$2"; | ||
470 | } | ||
471 | else { | ||
472 | print STDERR "$err Could not determine operating system version!\n"; | ||
473 | $distro="unknown"; | ||
474 | } | ||
475 | } | ||
476 | } | ||
477 | |||
478 | $GLOBAL_OS=$distro; | ||
479 | } elsif (not (defined $GLOBAL_OS)) { | ||
480 | print "ERROR: GLOBAL OS Scoping Issue\n"; | ||
481 | } else { | ||
482 | $distro = $GLOBAL_OS; | ||
483 | } | ||
484 | |||
485 | return $distro; | ||
486 | } | ||
487 | |||
488 | ################################################################################### | ||
489 | # &getActualDistro; # | ||
490 | # # | ||
491 | # This subroutine returns the actual os version in which is running on. This # | ||
492 | # os version is independent of the --os switch feed to bastille. # | ||
493 | # # | ||
494 | ################################################################################### | ||
495 | sub getActualDistro { | ||
496 | # set local variable to $GLOBAL_OS | ||
497 | |||
498 | if ($GLOBAL_ACTUAL_OS eq "None") { | ||
499 | my $os = $GLOBAL_OS; | ||
500 | # undef GLOBAL_OS so that the GetDistro routine will return | ||
501 | # the actualDistro, it might otherwise return the distro set | ||
502 | # by the --os switch. | ||
503 | $GLOBAL_OS = "None"; | ||
504 | $GLOBAL_ACTUAL_OS = &GetDistro; | ||
505 | # reset the GLOBAL_OS variable | ||
506 | $GLOBAL_OS = $os; | ||
507 | } | ||
508 | return $GLOBAL_ACTUAL_OS; | ||
509 | } | ||
510 | # These are helper routines which used to be included inside GetDistro | ||
511 | sub is_OS_supported($) { | ||
512 | my $os=$_[0]; | ||
513 | my $supported=0; | ||
514 | my %supportedOSHash = &getSupportedOSHash; | ||
515 | |||
516 | foreach my $oSType (keys %supportedOSHash) { | ||
517 | foreach my $supported_os ( @{$supportedOSHash{$oSType}} ) { | ||
518 | if ( $supported_os eq $os ) { | ||
519 | $supported=1; | ||
520 | } | ||
521 | } | ||
522 | } | ||
523 | |||
524 | return $supported; | ||
525 | } | ||
526 | |||
527 | ############################################################################### | ||
528 | # getSupportedOSHash | ||
529 | # | ||
530 | # This subrountine returns a hash of supported OSTypes, which point to a | ||
531 | # a list of supported distros. When porting to a new distro, add the | ||
532 | # distro id to the hash in its appropriate list. | ||
533 | ############################################################################### | ||
534 | sub getSupportedOSHash () { | ||
535 | |||
536 | my %osHash = ("LINUX" => [ | ||
537 | "DB2.2", "DB3.0", | ||
538 | "RH6.0","RH6.1","RH6.2","RH7.0", | ||
539 | "RH7.1","RH7.2","RH7.3","RH8.0", | ||
540 | "RH9", | ||
541 | "RHEL5", | ||
542 | "RHEL4AS","RHEL4ES","RHEL4WS", | ||
543 | "RHEL3AS","RHEL3ES","RHEL3WS", | ||
544 | "RHEL2AS","RHEL2ES","RHEL2WS", | ||
545 | "RHFC1","RHFC2","RHFC3","RHFC4", | ||
546 | "RHFC5","RHFC6","RHFC7","RHFC8", | ||
547 | "MN6.0","MN6.1 ","MN7.0","MN7.1", | ||
548 | "MN7.2","MN8.0","MN8.1","MN8.2", | ||
549 | "MN10.1", | ||
550 | "SE7.2","SE7.3", "SE8.0","SE8.1","SE9.0","SE9.1", | ||
551 | "SE9.2","SE9.3","SE10.0","SE10.1","SE10.2","SE10.3", | ||
552 | "SESLES8","SESLES9","SESLES10", | ||
553 | "TB7.0" | ||
554 | ], | ||
555 | |||
556 | "HP-UX" => [ | ||
557 | "HP-UX11.00","HP-UX11.11", | ||
558 | "HP-UX11.22", "HP-UX11.23", | ||
559 | "HP-UX11.31" | ||
560 | ], | ||
561 | |||
562 | "OSX" => [ | ||
563 | 'OSX10.2','OSX10.3','OSX10.4' | ||
564 | ] | ||
565 | ); | ||
566 | |||
567 | return %osHash; | ||
568 | |||
569 | } | ||
570 | |||
571 | |||
572 | ############################################################################### | ||
573 | # setFileLocations(OSMapFile, currentDistro); | ||
574 | # | ||
575 | # Given a file map location this subroutine will create the GLOBAL_* | ||
576 | # hash entries specified within this file. | ||
577 | ############################################################################### | ||
578 | sub setFileLocations($$) { | ||
579 | |||
580 | my ($fileInfoFile,$currentDistro) = @_; | ||
581 | |||
582 | # define a mapping from the first argument to the proper hash | ||
583 | my %map = ("BIN" => \%GLOBAL_BIN, | ||
584 | "FILE" => \%GLOBAL_FILE, | ||
585 | "BFILE" => \%GLOBAL_BFILE, | ||
586 | "DIR" => \%GLOBAL_DIR, | ||
587 | "BDIR" => \%GLOBAL_BDIR | ||
588 | ); | ||
589 | my @fileInfo = (); | ||
590 | |||
591 | # File containing file location information | ||
592 | if(open(FILEINFO, "<$fileInfoFile" )) { | ||
593 | |||
594 | @fileInfo = <FILEINFO>; | ||
595 | |||
596 | close(FILEINFO); | ||
597 | |||
598 | } | ||
599 | else { | ||
600 | print STDERR "$err Unable to find file location information for '$distro'.\n" . | ||
601 | "$spc Contact the Bastille support list for details.\n"; | ||
602 | exit(1); | ||
603 | } | ||
604 | |||
605 | # Each line of the file map follows the pattern below: | ||
606 | # bdir,init.d,'/etc/rc.d/init.d',RH7.2,RH7.3 | ||
607 | # if the distro information is not available, e.g. | ||
608 | # bdir,init.d,'/etc/rc.d/init.d' | ||
609 | # then the line applies to all distros under the OSType | ||
610 | foreach my $file (@fileInfo) { | ||
611 | # Perl comments are allowed within the file but only entire line comments | ||
612 | if($file !~ /^\s+\#|^\s+$/) { | ||
613 | chomp $file; | ||
614 | # type relates to the map above, type bin will map to GLOBAL_BIN | ||
615 | # id is the identifier used as the hash key by the GLOBAL hash | ||
616 | # fileLocation is the full path to the file | ||
617 | # distroList is an optional list of distros that this particular | ||
618 | # file location, if no distro list is presented the file location | ||
619 | # is considered to apply to all distros | ||
620 | my ($type,$id,$fileLocation,@distroList) = split /\s*,\s*/, $file; | ||
621 | $fileLocation =~ s/^\'(.*)\'$/$1/; | ||
622 | if($#distroList == -1) { | ||
623 | $map{uc($type)}->{$id}=$fileLocation; | ||
624 | } | ||
625 | else { | ||
626 | foreach my $distro (@distroList) { | ||
627 | # if the current distro matches the distro listed then | ||
628 | # this file location applies | ||
629 | if($currentDistro =~ /$distro/) { | ||
630 | $map{uc($type)}->{$id}=$fileLocation; | ||
631 | } | ||
632 | } | ||
633 | } | ||
634 | } | ||
635 | } | ||
636 | unless(defined($map{uc("BFILE")}->{"current_config"})) { | ||
637 | &setGlobal("BFILE","current_config",&getGlobal("BFILE","config")); | ||
638 | } | ||
639 | } | ||
640 | |||
641 | ############################################################################### | ||
642 | # setServiceInfo($OSServiceMapFile, $currentDistro | ||
643 | # | ||
644 | # Given the location of an OS Service map file, which describes | ||
645 | # a service in terms of configurables, processes and a service type. | ||
646 | # The subroutine fills out the GLOBAL_SERVICE, $GLOBAL_RC_CONFIG, GLOBAL_SERVTYPE, and | ||
647 | # GLOBAL_PROCESS hashes for a given service ID. | ||
648 | ############################################################################### | ||
649 | sub setServiceInfo($$) { | ||
650 | my ($serviceInfoFile,$currentDistro) = @_; | ||
651 | my @serviceInfo = (); | ||
652 | |||
653 | if(open(SERVICEINFO, "<$serviceInfoFile" )) { | ||
654 | |||
655 | @serviceInfo = <SERVICEINFO>; | ||
656 | |||
657 | close(SERVICEINFO); | ||
658 | |||
659 | } | ||
660 | else { | ||
661 | print STDERR "$err Unable to find service, service type, and process information\n" . | ||
662 | "$spc for '$distro'.\n" . | ||
663 | "$spc Contact the Bastille support list for details.\n"; | ||
664 | exit(1); | ||
665 | } | ||
666 | |||
667 | |||
668 | # The following loop, parses the entire (YOUR OS).service file | ||
669 | # to provide service information for YOUR OS. | ||
670 | # The files format is as follows: | ||
671 | # serviceID,servType,('service' 'configuration' 'list'),('process' 'list')[,DISTROS]* | ||
672 | # if distros are not present then the service is assumed to be | ||
673 | # relevant the the current distro | ||
674 | |||
675 | |||
676 | # | ||
677 | # More specifically, this file's format for rc-based daemons is: | ||
678 | # | ||
679 | # script_name,rc,(rc-config-file rc-config-file ...),(rc-variable1 rc-variable2 ...),('program_name1 program_name2 ...') | ||
680 | # | ||
681 | # ...where script_name is a file in /etc/init.d/ and | ||
682 | # ...program_nameN is a program launced by the script. | ||
683 | # | ||
684 | # This file's format for inet-based daemons is: | ||
685 | # | ||
686 | # identifier, inet, line name/file name, program name | ||
687 | # | ||
688 | # label,inet,(port1 port2 ...),(daemon1 daemon2 ...) | ||
689 | # | ||
690 | # ...where label is arbitrary, portN is one of the ports | ||
691 | # ...this one listens on, and daemonN is a program launched | ||
692 | # ...in response to a connection on a port. | ||
693 | |||
694 | foreach my $service (@serviceInfo) { | ||
695 | # This file accepts simple whole line comments perl style | ||
696 | if($service !~ /^\s+\#|^\s+$/) { | ||
697 | chomp $service; | ||
698 | my ($serviceID,$servType,$strConfigList,$strServiceList, | ||
699 | $strProcessList,@distroList) = split /\s*,\s*/, $service; | ||
700 | |||
701 | sub MakeArrayFromString($){ | ||
702 | my $entryString = $_[0]; | ||
703 | my @destArray = (); | ||
704 | if ($entryString =~ /\'\S+\'/) { #Make sure we have something to extract before we try | ||
705 | @destArray = split /\'\s+\'/, $entryString; | ||
706 | $destArray[0] =~ s/^\(\'(.+)$/$1/; # Remove leading quotation mark | ||
707 | $destArray[$#destArray] =~ s/^(.*)\'\)$/$1/; #Remove trailing quotation mark | ||
708 | } | ||
709 | return @destArray; | ||
710 | } | ||
711 | |||
712 | # produce a list of configuration files from the files | ||
713 | # format ('configuration' 'files') | ||
714 | my @configList = MakeArrayFromString($strConfigList); | ||
715 | |||
716 | # produce a list of service configurables from the files | ||
717 | # format ('service' 'configurable') | ||
718 | my @serviceList = MakeArrayFromString($strServiceList); | ||
719 | |||
720 | # produce a list of process names from the files format | ||
721 | # ('my' 'process' 'list') | ||
722 | my @processList = MakeArrayFromString($strProcessList); | ||
723 | |||
724 | # if distros were not specified then accept the service information | ||
725 | if($#distroList == -1) { | ||
726 | @{$GLOBAL_SERVICE{$serviceID}} = @serviceList; | ||
727 | $GLOBAL_SERVTYPE{$serviceID} = $servType; | ||
728 | @{$GLOBAL_PROCESS{$serviceID}} = @processList; | ||
729 | @{$GLOBAL_RC_CONFIG{$serviceID}} = @configList; | ||
730 | } | ||
731 | else { | ||
732 | # only if the current distro matches one of the listed distros | ||
733 | # include the service information. | ||
734 | foreach my $distro (@distroList) { | ||
735 | if($currentDistro =~ /$distro/) { | ||
736 | @{$GLOBAL_SERVICE{$serviceID}} = @serviceList; | ||
737 | $GLOBAL_SERVTYPE{$serviceID} = $servType; | ||
738 | @{$GLOBAL_PROCESS{$serviceID}} = @processList; | ||
739 | @{$GLOBAL_RC_CONFIG{$serviceID}} = @configList; | ||
740 | } | ||
741 | } | ||
742 | } | ||
743 | } | ||
744 | } | ||
745 | } | ||
746 | |||
747 | |||
748 | |||
749 | ############################################################################### | ||
750 | # getFileAndServiceInfo($distro,$actualDistro) | ||
751 | # | ||
752 | # This subrountine, given distribution information, will import system file | ||
753 | # and service information into the GLOBA_* hashes. | ||
754 | # | ||
755 | # NOTE: $distro and $actualDistro will only differ when the --os switch is | ||
756 | # used to generate a configuration file for an arbitrary operating | ||
757 | # system. | ||
758 | # | ||
759 | ############################################################################### | ||
760 | sub getFileAndServiceInfo($$) { | ||
761 | |||
762 | my ($distro,$actualDistro) = @_; | ||
763 | |||
764 | # defines the path to the OS map information for any supported OS type. | ||
765 | # OS map information is used to determine file locations for a given | ||
766 | # distribution. | ||
767 | my %oSInfoPath = ( | ||
768 | "LINUX" => "/usr/share/Bastille/OSMap/", | ||
769 | "HP-UX" => "/etc/opt/sec_mgmt/bastille/OSMap/", | ||
770 | "OSX" => "/usr/share/Bastille/OSMap/" | ||
771 | ); | ||
772 | |||
773 | # returns the OS, LINUX, HP-UX, or OSX, associated with this | ||
774 | # distribution | ||
775 | my $actualOS = &getOSType($actualDistro); | ||
776 | my $oS = &getOSType($distro); | ||
777 | |||
778 | if(defined $actualOS && defined $oS) { | ||
779 | my $bastilleInfoFile = $oSInfoPath{$actualOS} . "${actualOS}.bastille"; | ||
780 | my $systemInfoFile = $oSInfoPath{$actualOS} . "${oS}.system"; | ||
781 | my $serviceInfoFile = $oSInfoPath{$actualOS} . "${oS}.service"; | ||
782 | |||
783 | if(-f $bastilleInfoFile) { | ||
784 | &setFileLocations($bastilleInfoFile,$actualDistro); | ||
785 | } | ||
786 | else { | ||
787 | print STDERR "$err Unable to find bastille file information.\n" . | ||
788 | "$spc $bastilleInfoFile does not exist on the system"; | ||
789 | exit(1); | ||
790 | } | ||
791 | |||
792 | if(-f $systemInfoFile) { | ||
793 | &setFileLocations($systemInfoFile,$distro); | ||
794 | } | ||
795 | else { | ||
796 | print STDERR "$err Unable to find system file information.\n" . | ||
797 | "$spc $systemInfoFile does not exist on the system"; | ||
798 | exit(1); | ||
799 | } | ||
800 | # Service info File is optional | ||
801 | if(-f $serviceInfoFile) { | ||
802 | &setServiceInfo($serviceInfoFile,$distro); | ||
803 | } | ||
804 | } | ||
805 | else { | ||
806 | print STDERR "$err Unable to determine operating system type\n" . | ||
807 | "$spc for $actualDistro or $distro\n"; | ||
808 | exit(1); | ||
809 | } | ||
810 | |||
811 | } | ||
812 | |||
813 | |||
814 | # returns the Operating System type associated with the specified | ||
815 | # distribution. | ||
816 | sub getOSType($) { | ||
817 | |||
818 | my $distro = $_[0]; | ||
819 | |||
820 | my %supportedOSHash = &getSupportedOSHash; | ||
821 | foreach my $oSType (keys %supportedOSHash) { | ||
822 | foreach my $oSDistro (@{$supportedOSHash{$oSType}}) { | ||
823 | if($distro eq $oSDistro) { | ||
824 | return $oSType; | ||
825 | } | ||
826 | } | ||
827 | } | ||
828 | |||
829 | return undef; | ||
830 | |||
831 | } | ||
832 | |||
833 | |||
834 | # Test subroutine used to debug file location info for new Distributions as | ||
835 | # they are ported. | ||
836 | sub dumpFileInfo { | ||
837 | print "Dumping File Information\n"; | ||
838 | foreach my $hashref (\%GLOBAL_BIN,\%GLOBAL_DIR,\%GLOBAL_FILE,\%GLOBAL_BFILE,\%GLOBAL_BDIR) { | ||
839 | foreach my $id (keys %{$hashref}) { | ||
840 | print "$id: ${$hashref}{$id}\n"; | ||
841 | } | ||
842 | print "-----------------------\n\n"; | ||
843 | } | ||
844 | } | ||
845 | |||
846 | # Test subroutine used to debug service info for new Distributions as | ||
847 | # they are ported. | ||
848 | sub dumpServiceInfo { | ||
849 | print "Dumping Service Information\n"; | ||
850 | foreach my $serviceId (keys %GLOBAL_SERVICE) { | ||
851 | print "$serviceId:\n"; | ||
852 | print "Type - $GLOBAL_SERVTYPE{$serviceId}\n"; | ||
853 | print "Service List:\n"; | ||
854 | foreach my $service (@{$GLOBAL_SERVICE{$serviceId}}) { | ||
855 | print "$service "; | ||
856 | } | ||
857 | print "\nProcess List:\n"; | ||
858 | foreach my $process (@{$GLOBAL_PROCESS{$serviceId}}) { | ||
859 | print "$process "; | ||
860 | } | ||
861 | print "\n----------------------\n"; | ||
862 | } | ||
863 | } | ||
864 | |||
865 | |||
866 | ########################################################################### | ||
867 | # | ||
868 | # &ConfigureForDistro configures the API for a given distribution. This | ||
869 | # includes setting global variables that tell the Bastille API about | ||
870 | # given binaries and directories. | ||
871 | # | ||
872 | # WARNING: If a distro is not covered here, Bastille may not be 100% | ||
873 | # compatible with it, though 1.1 is written to be much smarter | ||
874 | # about unknown distros... | ||
875 | # | ||
876 | ########################################################################### | ||
877 | sub ConfigureForDistro { | ||
878 | |||
879 | my $retval=1; | ||
880 | |||
881 | # checking to see if the os version given is in fact supported | ||
882 | my $distro = &GetDistro; | ||
883 | |||
884 | # checking to see if the actual os version is in fact supported | ||
885 | my $actualDistro = &getActualDistro; | ||
886 | $ENV{'LOCALE'}=''; # So that test cases checking for english results work ok. | ||
887 | if ((! &is_OS_supported($distro)) or (! &is_OS_supported($actualDistro)) ) { | ||
888 | # if either is not supported then print out a list of supported versions | ||
889 | if (! &is_OS_supported($distro)) { | ||
890 | print STDERR "$err '$distro' is not a supported operating system.\n"; | ||
891 | } | ||
892 | else { | ||
893 | print STDERR "$err Bastille is unable to operate correctly on this\n"; | ||
894 | print STDERR "$spc $distro operating system.\n"; | ||
895 | } | ||
896 | my %supportedOSHash = &getSupportedOSHash; | ||
897 | print STDERR "$spc Valid operating system versions are as follows:\n"; | ||
898 | |||
899 | foreach my $oSType (keys %supportedOSHash) { | ||
900 | |||
901 | print STDERR "$spc $oSType:\n$spc "; | ||
902 | |||
903 | my $os_number = 1; | ||
904 | foreach my $os (@{$supportedOSHash{$oSType}}) { | ||
905 | print STDERR "'$os' "; | ||
906 | if ($os_number == 5){ | ||
907 | print STDERR "\n$spc "; | ||
908 | $os_number = 1; | ||
909 | } | ||
910 | else { | ||
911 | $os_number++; | ||
912 | } | ||
913 | |||
914 | } | ||
915 | print STDERR "\n"; | ||
916 | } | ||
917 | |||
918 | print "\n" . $GLOBAL_ERROR{"usage"}; | ||
919 | exit(1); | ||
920 | } | ||
921 | |||
922 | # First, let's make sure that we do not create any files or | ||
923 | # directories with more permissive permissions than we | ||
924 | # intend via setting the Perl umask | ||
925 | umask(077); | ||
926 | |||
927 | &getFileAndServiceInfo($distro,$actualDistro); | ||
928 | |||
929 | # &dumpFileInfo; # great for debuging file location issues | ||
930 | # &dumpServiceInfo; # great for debuging service information issues | ||
931 | |||
932 | # OS dependent error messages (after configuring file locations) | ||
933 | my $nodisclaim_file = &getGlobal('BFILE', "nodisclaimer"); | ||
934 | |||
935 | $GLOBAL_ERROR{"disclaimer"}="$err Unable to touch $nodisclaim_file:" . | ||
936 | "$spc You must use Bastille\'s -n flag (for example:\n" . | ||
937 | "$spc bastille -f -n) or \'touch $nodisclaim_file \'\n"; | ||
938 | |||
939 | return $retval; | ||
940 | } | ||
941 | |||
942 | |||
943 | ########################################################################### | ||
944 | ########################################################################### | ||
945 | # # | ||
946 | # The B_<perl_function> file utilities are replacements for their Perl # | ||
947 | # counterparts. These replacements log their actions and their errors, # | ||
948 | # but are very similar to said counterparts. # | ||
949 | # # | ||
950 | ########################################################################### | ||
951 | ########################################################################### | ||
952 | |||
953 | |||
954 | ########################################################################### | ||
955 | # B_open is used for opening a file for reading. B_open_plus is the preferred | ||
956 | # function for writing, since it saves a backup copy of the file for | ||
957 | # later restoration. | ||
958 | # | ||
959 | # B_open opens the given file handle, associated with the given filename | ||
960 | # and logs appropriately. | ||
961 | # | ||
962 | ########################################################################### | ||
963 | |||
964 | sub B_open { | ||
965 | my $retval=1; | ||
966 | my ($handle,$filename)=@_; | ||
967 | |||
968 | unless ($GLOBAL_LOGONLY) { | ||
969 | $retval = open $handle,$filename; | ||
970 | } | ||
971 | |||
972 | ($handle) = "$_[0]" =~ /[^:]+::[^:]+::([^:]+)/; | ||
973 | &B_log("ACTION","open $handle,\"$filename\";\n"); | ||
974 | unless ($retval) { | ||
975 | &B_log("ERROR","open $handle, $filename failed...\n"); | ||
976 | } | ||
977 | |||
978 | return $retval; | ||
979 | } | ||
980 | |||
981 | ########################################################################### | ||
982 | # B_open_plus is the v1.1 open command. | ||
983 | # | ||
984 | # &B_open_plus($handle_file,$handle_original,$file) opens the file $file | ||
985 | # for reading and opens the file ${file}.bastille for writing. It is the | ||
986 | # counterpart to B_close_plus, which will move the original file to | ||
987 | # $GLOBAL_BDIR{"backup"} and will place the new file ${file}.bastille in its | ||
988 | # place. | ||
989 | # | ||
990 | # &B_open_plus makes the appropriate log entries in the action and error | ||
991 | # logs. | ||
992 | ########################################################################### | ||
993 | |||
994 | sub B_open_plus { | ||
995 | |||
996 | my ($handle_file,$handle_original,$file)=@_; | ||
997 | my $retval=1; | ||
998 | my $return_file=1; | ||
999 | my $return_old=1; | ||
1000 | |||
1001 | my $original_file = $file; | ||
1002 | |||
1003 | # Open the original file and open a copy for writing. | ||
1004 | unless ($GLOBAL_LOGONLY) { | ||
1005 | # if the temporary filename already exists then the open operation will fail. | ||
1006 | if ( $file eq "" ){ | ||
1007 | &B_log("ERROR","Internal Error - Attempt Made to Open Blank Filename"); | ||
1008 | $return_old=0; | ||
1009 | $return_file=0; | ||
1010 | return 0; #False | ||
1011 | } elsif (-e "${file}.bastille") { | ||
1012 | &B_log("ERROR","Unable to open $file as the swap file ". | ||
1013 | "${file}.bastille\" already exists. Rename the swap ". | ||
1014 | "file to allow Bastille to make desired file modifications."); | ||
1015 | $return_old=0; | ||
1016 | $return_file=0; | ||
1017 | } | ||
1018 | else { | ||
1019 | $return_old = open $handle_original,"$file"; | ||
1020 | $return_file = open $handle_file,("> $file.bastille"); | ||
1021 | } | ||
1022 | } | ||
1023 | |||
1024 | # Error handling/logging here... | ||
1025 | #&B_log("ACTION","# Modifying file $original_file via temporary file $original_file.bastille\n"); | ||
1026 | unless ($return_file) { | ||
1027 | $retval=0; | ||
1028 | &B_log("ERROR","open file: \"$original_file.bastille\" failed...\n"); | ||
1029 | } | ||
1030 | unless ($return_old) { | ||
1031 | $retval=0; | ||
1032 | &B_log("ERROR","open file: \"$original_file\" failed.\n"); | ||
1033 | } | ||
1034 | |||
1035 | return $retval; | ||
1036 | |||
1037 | } | ||
1038 | |||
1039 | ########################################################################### | ||
1040 | # B_close was the v1.0 close command. It is still used in places in the | ||
1041 | # code. | ||
1042 | # However the use of B _close_plus, which implements a new, smarter, | ||
1043 | # backup scheme is preferred. | ||
1044 | # | ||
1045 | # B_close closes the given file handle, associated with the given filename | ||
1046 | # and logs appropriately. | ||
1047 | ########################################################################### | ||
1048 | |||
1049 | |||
1050 | sub B_close { | ||
1051 | my $retval=1; | ||
1052 | |||
1053 | unless ($GLOBAL_LOGONLY) { | ||
1054 | $retval = close $_[0]; | ||
1055 | } | ||
1056 | |||
1057 | &B_log("ACTION", "close $_[0];\n"); | ||
1058 | unless ($retval) { | ||
1059 | &B_log("ERROR", "close $_[0] failed...\n"); | ||
1060 | } | ||
1061 | |||
1062 | return $retval; | ||
1063 | } | ||
1064 | |||
1065 | |||
1066 | ########################################################################### | ||
1067 | # B_close_plus is the v1.1 close command. | ||
1068 | # | ||
1069 | # &B_close_plus($handle_file,$handle_original,$file) closes the files | ||
1070 | # $file and ${file}.bastille, backs up $file to $GLOBAL_BDIR{"backup"} and | ||
1071 | # renames ${file}.bastille to $file. This backup is made using the | ||
1072 | # internal API function &B_backup_file. Further, it sets the new file's | ||
1073 | # permissions and uid/gid to the same as the old file. | ||
1074 | # | ||
1075 | # B_close_plus is the counterpart to B_open_plus, which opened $file and | ||
1076 | # $file.bastille with the file handles $handle_original and $handle_file, | ||
1077 | # respectively. | ||
1078 | # | ||
1079 | # &B_close_plus makes the appropriate log entries in the action and error | ||
1080 | # logs. | ||
1081 | ########################################################################### | ||
1082 | |||
1083 | sub B_close_plus { | ||
1084 | my ($handle_file,$handle_original,$file)=@_; | ||
1085 | my ($mode,$uid,$gid); | ||
1086 | my @junk; | ||
1087 | |||
1088 | my $original_file; | ||
1089 | |||
1090 | my $retval=1; | ||
1091 | my $return_file=1; | ||
1092 | my $return_old=1; | ||
1093 | |||
1094 | # Append the global prefix, but save the original for B_backup_file b/c | ||
1095 | # it appends the prefix on its own... | ||
1096 | |||
1097 | $original_file=$file; | ||
1098 | |||
1099 | # | ||
1100 | # Close the files and prepare for the rename | ||
1101 | # | ||
1102 | |||
1103 | if (($file eq "") or (not(-e $file ))) { | ||
1104 | &B_log("ERROR","Internal Error, attempted to close a blank filename ". | ||
1105 | "or nonexistent file."); | ||
1106 | return 0; #False | ||
1107 | } | ||
1108 | |||
1109 | unless ($GLOBAL_LOGONLY) { | ||
1110 | $return_file = close $handle_file; | ||
1111 | $return_old = close $handle_original; | ||
1112 | } | ||
1113 | |||
1114 | # Error handling/logging here... | ||
1115 | #&B_log("ACTION","#Closing $original_file and backing up to " . &getGlobal('BDIR', "backup")); | ||
1116 | #&B_log("ACTION","/$original_file\n"); | ||
1117 | |||
1118 | unless ($return_file) { | ||
1119 | $retval=0; | ||
1120 | &B_log("ERROR","close $original_file failed...\n"); | ||
1121 | } | ||
1122 | unless ($return_old) { | ||
1123 | $retval=0; | ||
1124 | &B_log("ERROR","close $original_file.bastille failed.\n"); | ||
1125 | } | ||
1126 | |||
1127 | # | ||
1128 | # If we've had no errors, backup the old file and put the new one | ||
1129 | # in its place, with the Right permissions. | ||
1130 | # | ||
1131 | |||
1132 | unless ( ($retval == 0) or $GLOBAL_LOGONLY) { | ||
1133 | |||
1134 | # Read the permissions/owners on the old file | ||
1135 | |||
1136 | @junk=stat ($file); | ||
1137 | $mode=$junk[2]; | ||
1138 | $uid=$junk[4]; | ||
1139 | $gid=$junk[5]; | ||
1140 | |||
1141 | # Set the permissions/owners on the new file | ||
1142 | |||
1143 | chmod $mode, "$file.bastille" or &B_log("ERROR","Not able to retain permissions on $original_file!!!\n"); | ||
1144 | chown $uid, $gid, "$file.bastille" or &B_log("ERROR","Not able to retain owners on $original_file!!!\n"); | ||
1145 | |||
1146 | # Backup the old file and put a new one in place. | ||
1147 | |||
1148 | &B_backup_file($original_file); | ||
1149 | rename "$file.bastille", $file or | ||
1150 | &B_log("ERROR","B_close_plus: not able to move $original_file.bastille to $original_file\n"); | ||
1151 | |||
1152 | # We add the file to the GLOBAL_SUMS hash if it is not already present | ||
1153 | &B_set_sum($file); | ||
1154 | |||
1155 | } | ||
1156 | |||
1157 | return $retval; | ||
1158 | } | ||
1159 | |||
1160 | ########################################################################### | ||
1161 | # &B_backup_file ($file) makes a backup copy of the file $file in | ||
1162 | # &getGlobal('BDIR', "backup"). Note that this routine is intended for internal | ||
1163 | # use only -- only Bastille API functions should call B_backup_file. | ||
1164 | # | ||
1165 | ########################################################################### | ||
1166 | |||
1167 | sub B_backup_file { | ||
1168 | |||
1169 | my $file=$_[0]; | ||
1170 | my $complain = 1; | ||
1171 | my $original_file = $file; | ||
1172 | |||
1173 | my $backup_dir = &getGlobal('BDIR', "backup"); | ||
1174 | my $backup_file = $backup_dir . $original_file; | ||
1175 | |||
1176 | my $retval=1; | ||
1177 | |||
1178 | # First, separate the file into the directory and the relative filename | ||
1179 | |||
1180 | my $directory =""; | ||
1181 | if ($file =~ /^(.*)\/([^\/]+)$/) { | ||
1182 | #$relative_file=$2; | ||
1183 | $directory = $1; | ||
1184 | } else { | ||
1185 | $directory=cwd; | ||
1186 | } | ||
1187 | |||
1188 | # Now, if the directory does not exist, create it. | ||
1189 | # Later: | ||
1190 | # Try to set the same permissions on the patch directory that the | ||
1191 | # original had...? | ||
1192 | |||
1193 | unless ( -d ($backup_dir . $directory) ) { | ||
1194 | mkpath(( $backup_dir . $directory),0,0700); | ||
1195 | |||
1196 | } | ||
1197 | |||
1198 | # Now we backup the file. If there is already a backup file there, | ||
1199 | # we will leave it alone, since it exists from a previous run and | ||
1200 | # should be the _original_ (possibly user-modified) distro's version | ||
1201 | # of the file. | ||
1202 | |||
1203 | if ( -e $file ) { | ||
1204 | |||
1205 | unless ( -e $backup_file ) { | ||
1206 | my $command=&getGlobal("BIN","cp"); | ||
1207 | &B_Backtick("$command -p $file $backup_file"); | ||
1208 | &B_revert_log (&getGlobal("BIN","mv"). " $backup_file $file"); | ||
1209 | } | ||
1210 | |||
1211 | } else { | ||
1212 | # The file we were trying to backup doesn't exist. | ||
1213 | |||
1214 | $retval=0; | ||
1215 | # This is a non-fatal error, not worth complaining about | ||
1216 | $complain = 0; | ||
1217 | #&ErrorLog ("# Failed trying to backup file $file -- it doesn't exist!\n"); | ||
1218 | } | ||
1219 | |||
1220 | # Check to make sure that the file does exist in the backup location. | ||
1221 | |||
1222 | unless ( -e $backup_file ) { | ||
1223 | $retval=0; | ||
1224 | if ( $complain == 1 ) { | ||
1225 | &B_log("ERROR","Failed trying to backup $file -- the copy was not created.\n"); | ||
1226 | } | ||
1227 | } | ||
1228 | |||
1229 | return $retval; | ||
1230 | } | ||
1231 | |||
1232 | |||
1233 | ########################################################################### | ||
1234 | # &B_read_sums reads in the sum.csv file which contains information | ||
1235 | # about Bastille modified files. The file structure is as follows: | ||
1236 | # | ||
1237 | # filename,filesize,cksum | ||
1238 | # | ||
1239 | # It reads the information into the GLOBAL_SUM hash i.e. | ||
1240 | # $GLOBAL_SUM{$file}{sum} = $cksum | ||
1241 | # $GLOBAL_SUM{$file}{filesize} = $size | ||
1242 | # For the first run of Bastille on a given system this subroutine | ||
1243 | # is a no-op, and returns "undefined." | ||
1244 | ########################################################################### | ||
1245 | |||
1246 | sub B_read_sums { | ||
1247 | |||
1248 | my $sumFile = &getGlobal('BFILE',"sum.csv"); | ||
1249 | |||
1250 | if ( -e $sumFile ) { | ||
1251 | |||
1252 | open( SUM, "< $sumFile") or &B_log("ERROR","Unable to open $sumFile for read.\n$!\n"); | ||
1253 | |||
1254 | while( my $line = <SUM> ) { | ||
1255 | chomp $line; | ||
1256 | my ($file,$filesize,$sum,$flag) = split /,/, $line; | ||
1257 | if(-e $file) { | ||
1258 | $GLOBAL_SUM{"$file"}{filesize} = $filesize; | ||
1259 | $GLOBAL_SUM{"$file"}{sum} = $sum; | ||
1260 | } | ||
1261 | } | ||
1262 | |||
1263 | close(SUM); | ||
1264 | } else { | ||
1265 | return undef; | ||
1266 | } | ||
1267 | } | ||
1268 | |||
1269 | |||
1270 | ########################################################################### | ||
1271 | # &B_write_sums writes out the sum.csv file which contains information | ||
1272 | # about Bastille modified files. The file structure is as follows: | ||
1273 | # | ||
1274 | # filename,filesize,cksum | ||
1275 | # | ||
1276 | # It writes the information from the GLOBAL_SUM hash i.e. | ||
1277 | # | ||
1278 | # $file,$GLOBAL_SUM{$file}{sum},$GLOBAL_SUM{$file}{filesize} | ||
1279 | # | ||
1280 | # This subroutine requires access to the GLOBAL_SUM hash. | ||
1281 | ########################################################################### | ||
1282 | |||
1283 | sub B_write_sums { | ||
1284 | |||
1285 | my $sumFile = &getGlobal('BFILE',"sum.csv"); | ||
1286 | |||
1287 | if ( %GLOBAL_SUM ) { | ||
1288 | |||
1289 | open( SUM, "> $sumFile") or &B_log("ERROR","Unable to open $sumFile for write.\n$!\n"); | ||
1290 | |||
1291 | for my $file (sort keys %GLOBAL_SUM) { | ||
1292 | if( -e $file) { | ||
1293 | print SUM "$file,$GLOBAL_SUM{\"$file\"}{filesize},$GLOBAL_SUM{\"$file\"}{sum}\n"; | ||
1294 | } | ||
1295 | } | ||
1296 | |||
1297 | close(SUM); | ||
1298 | } | ||
1299 | |||
1300 | } | ||
1301 | |||
1302 | |||
1303 | ########################################################################### | ||
1304 | # &B_check_sum($file) compares the stored cksum and filesize of the given | ||
1305 | # file compared to the current cksum and filesize respectively. | ||
1306 | # This subroutine also keeps the state of the sum check by setting the | ||
1307 | # checked flag which tells the subroutine that on this run this file | ||
1308 | # has already been checked. | ||
1309 | # | ||
1310 | # $GLOBAL_SUM{$file}{checked} = 1; | ||
1311 | # | ||
1312 | # This subroutine requires access to the GLOBAL_SUM hash. | ||
1313 | # | ||
1314 | # Returns 1 if sum checks out and 0 if not | ||
1315 | ########################################################################### | ||
1316 | |||
1317 | sub B_check_sum($) { | ||
1318 | my $file = $_[0]; | ||
1319 | my $cksum = &getGlobal('BIN',"cksum"); | ||
1320 | |||
1321 | if (not(%GLOBAL_SUM)) { | ||
1322 | &B_read_sums; | ||
1323 | } | ||
1324 | |||
1325 | if(-e $file) { | ||
1326 | my ($sum,$size,$ckfile) = split(/\s+/, `$cksum $file`); | ||
1327 | my $commandRetVal = ($? >> 8); # find the command's return value | ||
1328 | |||
1329 | if($commandRetVal != 0) { | ||
1330 | &B_log("ERROR","$cksum reported the following error:\n$!\n"); | ||
1331 | return 0; | ||
1332 | } else { | ||
1333 | if ( exists $GLOBAL_SUM{$file} ) { | ||
1334 | # if the file size or file sum differ from those recorded. | ||
1335 | if (( $GLOBAL_SUM{$file}{filesize} == $size) and | ||
1336 | ($GLOBAL_SUM{$file}{sum} == $sum )) { | ||
1337 | return 1; #True, since saved state matches up, all is well. | ||
1338 | } else { | ||
1339 | return 0; #False, since saved state doesn't match | ||
1340 | } | ||
1341 | } else { | ||
1342 | &B_log("ERROR","File: $file does not exist in sums database."); | ||
1343 | return 0; | ||
1344 | } | ||
1345 | } | ||
1346 | } else { | ||
1347 | &B_log("ERROR","The file: $file does not exist for comparison in B_check_sum."); | ||
1348 | return 0; | ||
1349 | } | ||
1350 | } | ||
1351 | |||
1352 | # Don't think we need this anymore as function now check_sums returns | ||
1353 | # results directly | ||
1354 | #sub isSumDifferent($) { | ||
1355 | # my $file = $_[0]; | ||
1356 | # if(exists $GLOBAL_SUM{$file}) { | ||
1357 | # return $GLOBAL_SUM{$file}{flag} | ||
1358 | # } | ||
1359 | #} | ||
1360 | |||
1361 | sub listModifiedFiles { | ||
1362 | my @listModifiedFiles=sort keys %GLOBAL_SUM; | ||
1363 | return @listModifiedFiles; | ||
1364 | } | ||
1365 | |||
1366 | ########################################################################### | ||
1367 | # &B_isFileinSumDB($file) checks to see if a given file's sum was saved. | ||
1368 | # | ||
1369 | # $GLOBAL_SUM{$file}{filesize} = $size; | ||
1370 | # $GLOBAL_SUM{$file}{sum} = $cksum; | ||
1371 | # | ||
1372 | # This subroutine requires access to the GLOBAL_SUM hash. | ||
1373 | ########################################################################### | ||
1374 | |||
1375 | sub B_isFileinSumDB($) { | ||
1376 | my $file = $_[0]; | ||
1377 | |||
1378 | if (not(%GLOBAL_SUM)) { | ||
1379 | &B_log("DEBUG","Reading in DB from B_isFileinSumDB"); | ||
1380 | &B_read_sums; | ||
1381 | } | ||
1382 | if (exists($GLOBAL_SUM{"$file"})){ | ||
1383 | &B_log("DEBUG","$file is in sum database"); | ||
1384 | return 1; #true | ||
1385 | } else { | ||
1386 | &B_log("DEBUG","$file is not in sum database"); | ||
1387 | return 0; #false | ||
1388 | } | ||
1389 | } | ||
1390 | |||
1391 | ########################################################################### | ||
1392 | # &B_set_sum($file) sets the current cksum and filesize of the given | ||
1393 | # file into the GLOBAL_SUM hash. | ||
1394 | # | ||
1395 | # $GLOBAL_SUM{$file}{filesize} = $size; | ||
1396 | # $GLOBAL_SUM{$file}{sum} = $cksum; | ||
1397 | # | ||
1398 | # This subroutine requires access to the GLOBAL_SUM hash. | ||
1399 | ########################################################################### | ||
1400 | |||
1401 | sub B_set_sum($) { | ||
1402 | |||
1403 | my $file = $_[0]; | ||
1404 | my $cksum = &getGlobal('BIN',"cksum"); | ||
1405 | if( -e $file) { | ||
1406 | |||
1407 | my ($sum,$size,$ckfile) = split(/\s+/, `$cksum $file`); | ||
1408 | my $commandRetVal = ($? >> 8); # find the command's return value | ||
1409 | |||
1410 | if($commandRetVal != 0) { | ||
1411 | |||
1412 | &B_log("ERROR","$cksum reported the following error:\n$!\n"); | ||
1413 | |||
1414 | } | ||
1415 | else { | ||
1416 | |||
1417 | # new file size and sum are added to the hash | ||
1418 | $GLOBAL_SUM{$file}{filesize} = $size; | ||
1419 | $GLOBAL_SUM{$file}{sum} = $sum; | ||
1420 | &B_write_sums; | ||
1421 | |||
1422 | } | ||
1423 | } else { | ||
1424 | &B_log("ERROR","Can not save chksum for file: $file since it does not exist"); | ||
1425 | } | ||
1426 | } | ||
1427 | |||
1428 | |||
1429 | ########################################################################### | ||
1430 | # | ||
1431 | # &B_delete_file ($file) deletes the file $file and makes a backup to | ||
1432 | # the backup directory. | ||
1433 | # | ||
1434 | ########################################################################## | ||
1435 | |||
1436 | |||
1437 | sub B_delete_file($) { #Currently Linux only (TMPDIR) | ||
1438 | #consideration: should create clear_sum routine if this is ever used to remove | ||
1439 | # A Bastille-generated file. | ||
1440 | |||
1441 | # | ||
1442 | # This API routine deletes the named file, backing it up first to the | ||
1443 | # backup directory. | ||
1444 | # | ||
1445 | |||
1446 | my $filename=shift @_; | ||
1447 | my $retval=1; | ||
1448 | |||
1449 | # We have to append the prefix ourselves since we don't use B_open_plus | ||
1450 | |||
1451 | my $original_filename=$filename; | ||
1452 | |||
1453 | &B_log("ACTION","Deleting (and backing-up) file $original_filename\n"); | ||
1454 | &B_log("ACTION","rm $original_filename\n"); | ||
1455 | |||
1456 | unless ($filename) { | ||
1457 | &B_log("ERROR","B_delete_file called with no arguments!\n"); | ||
1458 | } | ||
1459 | |||
1460 | unless ($GLOBAL_LOGONLY) { | ||
1461 | if ( B_backup_file($original_filename) ) { | ||
1462 | unless ( unlink $filename ) { | ||
1463 | &B_log("ERROR","Couldn't unlink file $original_filename"); | ||
1464 | $retval=0; | ||
1465 | } | ||
1466 | } | ||
1467 | else { | ||
1468 | $retval=0; | ||
1469 | &B_log("ERROR","B_delete_file did not delete $original_filename since it could not back it up\n"); | ||
1470 | } | ||
1471 | } | ||
1472 | |||
1473 | $retval; | ||
1474 | |||
1475 | } | ||
1476 | |||
1477 | |||
1478 | ########################################################################### | ||
1479 | # &B_create_file ($file) creates the file $file, if it doesn't already | ||
1480 | # exist. | ||
1481 | # It will set a default mode of 0700 and a default uid/gid or 0/0. | ||
1482 | # | ||
1483 | # &B_create_file, to support Bastille's revert functionality, writes an | ||
1484 | # rm $file command to the end of the file &getGlobal('BFILE', "created-files"). | ||
1485 | # | ||
1486 | ########################################################################## | ||
1487 | |||
1488 | |||
1489 | sub B_create_file($) { | ||
1490 | |||
1491 | my $file = $_[0]; | ||
1492 | my $retval=1; | ||
1493 | |||
1494 | # We have to create the file ourselves since we don't use B_open_plus | ||
1495 | |||
1496 | my $original_file = $file; | ||
1497 | |||
1498 | if ($file eq ""){ | ||
1499 | &B_log("ERROR","Internal Error, attempt made to create blank filename"); | ||
1500 | return 0; #False | ||
1501 | } | ||
1502 | |||
1503 | unless ( -e $file ) { | ||
1504 | |||
1505 | unless ($GLOBAL_LOGONLY) { | ||
1506 | |||
1507 | # find the directory in which the file is to reside. | ||
1508 | my $dirName = dirname($file); | ||
1509 | # if the directory does not exist then | ||
1510 | if(! -d $dirName) { | ||
1511 | # create it. | ||
1512 | mkpath ($dirName,0,0700); | ||
1513 | } | ||
1514 | |||
1515 | $retval=open CREATE_FILE,">$file"; | ||
1516 | |||
1517 | if ($retval) { | ||
1518 | close CREATE_FILE; | ||
1519 | chmod 0700,$file; | ||
1520 | # Make the revert functionality | ||
1521 | &B_revert_log( &getGlobal('BIN','rm') . " $original_file \n"); | ||
1522 | } else { | ||
1523 | &B_log("ERROR","Couldn't create file $original_file even though " . | ||
1524 | "it didn't already exist!\n"); | ||
1525 | } | ||
1526 | } | ||
1527 | &B_log("ACTION","Created file $original_file\n"); | ||
1528 | } else { | ||
1529 | &B_log("DEBUG","Didn't create file $original_file since it already existed.\n"); | ||
1530 | $retval=0; | ||
1531 | } | ||
1532 | |||
1533 | $retval; | ||
1534 | } | ||
1535 | |||
1536 | |||
1537 | ########################################################################### | ||
1538 | # &B_create_dir ($dir) creates the directory $dir, if it doesn't already | ||
1539 | # exist. | ||
1540 | # It will set a default mode of 0700 and a default uid/gid or 0/0. | ||
1541 | # | ||
1542 | ########################################################################## | ||
1543 | |||
1544 | |||
1545 | sub B_create_dir($) { | ||
1546 | |||
1547 | my $dir = $_[0]; | ||
1548 | my $retval=1; | ||
1549 | |||
1550 | # We have to append the prefix ourselves since we don't use B_open_plus | ||
1551 | |||
1552 | my $original_dir=$dir; | ||
1553 | |||
1554 | unless ( -d $dir ) { | ||
1555 | unless ($GLOBAL_LOGONLY) { | ||
1556 | $retval=mkdir $dir,0700; | ||
1557 | |||
1558 | if ($retval) { | ||
1559 | # Make the revert functionality | ||
1560 | &B_revert_log (&getGlobal('BIN','rmdir') . " $original_dir\n"); | ||
1561 | } | ||
1562 | else { | ||
1563 | &B_log("ERROR","Couldn't create dir $original_dir even though it didn't already exist!"); | ||
1564 | } | ||
1565 | |||
1566 | } | ||
1567 | &B_log("ACTION","Created directory $original_dir\n"); | ||
1568 | } | ||
1569 | else { | ||
1570 | &B_log("ACTION","Didn't create directory $original_dir since it already existed.\n"); | ||
1571 | $retval=0; | ||
1572 | } | ||
1573 | |||
1574 | $retval; | ||
1575 | } | ||
1576 | |||
1577 | |||
1578 | |||
1579 | ########################################################################### | ||
1580 | # &B_symlink ($original_file,$new_symlink) creates a symbolic link from | ||
1581 | # $original_file to $new_symlink. | ||
1582 | # | ||
1583 | # &B_symlink respects $GLOBAL_LOGONLY. It supports | ||
1584 | # the revert functionality that you've come to know and love by adding every | ||
1585 | # symbolic link it creates to &getGlobal('BFILE', "created-symlinks"), currently set to: | ||
1586 | # | ||
1587 | # /root/Bastille/revert/revert-created-symlinks | ||
1588 | # | ||
1589 | # The revert script, if it works like I think it should, will run this file, | ||
1590 | # which should be a script or rm's... | ||
1591 | # | ||
1592 | ########################################################################## | ||
1593 | |||
1594 | sub B_symlink($$) { | ||
1595 | my ($source_file,$new_symlink)=@_; | ||
1596 | my $retval=1; | ||
1597 | my $original_source = $source_file; | ||
1598 | my $original_symlink = $new_symlink; | ||
1599 | |||
1600 | unless ($GLOBAL_LOGONLY) { | ||
1601 | $retval=symlink $source_file,$new_symlink; | ||
1602 | if ($retval) { | ||
1603 | &B_revert_log (&getGlobal('BIN',"rm") . " $original_symlink\n"); | ||
1604 | } | ||
1605 | } | ||
1606 | |||
1607 | &B_log("ACTION", "Created a symbolic link called $original_symlink from $original_source\n"); | ||
1608 | &B_log("ACTION", "symlink \"$original_source\",\"$original_symlink\";\n"); | ||
1609 | unless ($retval) { | ||
1610 | &B_log("ERROR","Couldn't symlink $original_symlink -> $original_source\n"); | ||
1611 | } | ||
1612 | |||
1613 | $retval; | ||
1614 | |||
1615 | } | ||
1616 | |||
1617 | |||
1618 | sub B_cp($$) { | ||
1619 | |||
1620 | my ($source,$target)=@_; | ||
1621 | my $retval=0; | ||
1622 | |||
1623 | my $had_to_backup_target=0; | ||
1624 | |||
1625 | use File::Copy; | ||
1626 | |||
1627 | my $original_source=$source; | ||
1628 | my $original_target=$target; | ||
1629 | |||
1630 | if( -e $target and -f $target ) { | ||
1631 | &B_backup_file($original_target); | ||
1632 | &B_log("ACTION","About to copy $original_source to $original_target -- had to backup target\n"); | ||
1633 | $had_to_backup_target=1; | ||
1634 | } | ||
1635 | |||
1636 | $retval=copy($source,$target); | ||
1637 | if ($retval) { | ||
1638 | &B_log("ACTION","cp $original_source $original_target\n"); | ||
1639 | |||
1640 | # | ||
1641 | # We want to add a line to the &getGlobal('BFILE', "created-files") so that the | ||
1642 | # file we just put at $original_target gets deleted. | ||
1643 | # | ||
1644 | &B_revert_log(&getGlobal('BIN',"rm") . " $original_target\n"); | ||
1645 | } else { | ||
1646 | &B_log("ERROR","Failed to copy $original_source to $original_target\n"); | ||
1647 | } | ||
1648 | # We add the file to the GLOBAL_SUMS hash if it is not already present | ||
1649 | &B_set_sum($target); | ||
1650 | $retval; | ||
1651 | } | ||
1652 | |||
1653 | |||
1654 | |||
1655 | ############################################################################ | ||
1656 | # &B_place puts a file in place, using Perl's File::cp. This file is taken | ||
1657 | # from &getGlobal('BDIR', "share") and is used to place a file that came with | ||
1658 | # Bastille. | ||
1659 | # | ||
1660 | # This should be DEPRECATED in favor of &B_cp, since the only reason it exists | ||
1661 | # is because of GLOBAL_PREFIX, which has been broken for quite some time. | ||
1662 | # Otherwise, the two routines are identical. | ||
1663 | # | ||
1664 | # It respects $GLOBAL_LOGONLY. | ||
1665 | # If $target is an already-existing file, it is backed up. | ||
1666 | # | ||
1667 | # revert either appends another "rm $target" to &getGlobal('BFILE', "revert-actions") or | ||
1668 | # backs up the file that _was_ there into the &getGlobal('BDIR', "backup"), | ||
1669 | # appending a "mv" to revert-actions to put it back. | ||
1670 | # | ||
1671 | ############################################################################ | ||
1672 | |||
1673 | sub B_place { # Only Linux references left (Firewall / TMPDIR) | ||
1674 | |||
1675 | my ($source,$target)=@_; | ||
1676 | my $retval=0; | ||
1677 | |||
1678 | my $had_to_backup_target=0; | ||
1679 | |||
1680 | use File::Copy; | ||
1681 | |||
1682 | my $original_source=$source; | ||
1683 | $source = &getGlobal('BDIR', "share") . $source; | ||
1684 | my $original_target=$target; | ||
1685 | |||
1686 | if ( -e $target and -f $target ) { | ||
1687 | &B_backup_file($original_target); | ||
1688 | &B_log("ACTION","About to copy $original_source to $original_target -- had to backup target\n"); | ||
1689 | $had_to_backup_target=1; | ||
1690 | } | ||
1691 | $retval=copy($source,$target); | ||
1692 | if ($retval) { | ||
1693 | &B_log("ACTION","placed file $original_source as $original_target\n"); | ||
1694 | # | ||
1695 | # We want to add a line to the &getGlobal('BFILE', "created-files") so that the | ||
1696 | # file we just put at $original_target gets deleted. | ||
1697 | &B_revert_log(&getGlobal('BIN',"rm") . " $original_target\n"); | ||
1698 | } else { | ||
1699 | &B_log("ERROR","Failed to place $original_source as $original_target\n"); | ||
1700 | } | ||
1701 | |||
1702 | # We add the file to the GLOBAL_SUMS hash if it is not already present | ||
1703 | &B_set_sum($target); | ||
1704 | |||
1705 | $retval; | ||
1706 | } | ||
1707 | |||
1708 | |||
1709 | |||
1710 | |||
1711 | |||
1712 | ############################################################################# | ||
1713 | ############################################################################# | ||
1714 | ############################################################################# | ||
1715 | |||
1716 | ########################################################################### | ||
1717 | # &B_mknod ($file) creates the node $file, if it doesn't already | ||
1718 | # exist. It uses the prefix and suffix, like this: | ||
1719 | # | ||
1720 | # mknod $prefix $file $suffix | ||
1721 | # | ||
1722 | # This is just a wrapper to the mknod program, which tries to introduce | ||
1723 | # revert functionality, by writing rm $file to the end of the | ||
1724 | # file &getGlobal('BFILE', "created-files"). | ||
1725 | # | ||
1726 | ########################################################################## | ||
1727 | |||
1728 | |||
1729 | sub B_mknod($$$) { | ||
1730 | |||
1731 | my ($prefix,$file,$suffix) = @_; | ||
1732 | my $retval=1; | ||
1733 | |||
1734 | # We have to create the filename ourselves since we don't use B_open_plus | ||
1735 | |||
1736 | my $original_file = $file; | ||
1737 | |||
1738 | unless ( -e $file ) { | ||
1739 | my $command = &getGlobal("BIN","mknod") . " $prefix $file $suffix"; | ||
1740 | |||
1741 | if ( system($command) == 0) { | ||
1742 | # Since system will return 0 on success, invert the error code | ||
1743 | $retval=1; | ||
1744 | } | ||
1745 | else { | ||
1746 | $retval=0; | ||
1747 | } | ||
1748 | |||
1749 | if ($retval) { | ||
1750 | |||
1751 | # Make the revert functionality | ||
1752 | &B_revert_log(&getGlobal('BIN',"rm") . " $original_file\n"); | ||
1753 | } else { | ||
1754 | &B_log("ERROR","Couldn't mknod $prefix $original_file $suffix even though it didn't already exist!\n"); | ||
1755 | } | ||
1756 | |||
1757 | |||
1758 | &B_log("ACTION","mknod $prefix $original_file $suffix\n"); | ||
1759 | } | ||
1760 | else { | ||
1761 | &B_log("ACTION","Didn't mknod $prefix $original_file $suffix since $original_file already existed.\n"); | ||
1762 | $retval=0; | ||
1763 | } | ||
1764 | |||
1765 | $retval; | ||
1766 | } | ||
1767 | |||
1768 | ########################################################################### | ||
1769 | # &B_revert_log("reverse_command") prepends a command to a shell script. This | ||
1770 | # shell script is intended to be run by bastille -r to reverse the changes that | ||
1771 | # Bastille made, returning the files which Bastille changed to their original | ||
1772 | # state. | ||
1773 | ########################################################################### | ||
1774 | |||
1775 | sub B_revert_log($) { | ||
1776 | |||
1777 | my $revert_command = $_[0]; | ||
1778 | my $revert_actions = &getGlobal('BFILE', "revert-actions"); | ||
1779 | my $revertdir= &getGlobal('BDIR', "revert"); | ||
1780 | my @lines; | ||
1781 | |||
1782 | |||
1783 | if (! (-e $revert_actions)) { | ||
1784 | mkpath($revertdir); #if this doesn't work next line catches | ||
1785 | if (open REVERT_ACTIONS,">" . $revert_actions){ # create revert file | ||
1786 | close REVERT_ACTIONS; # chown to root, rwx------ | ||
1787 | chmod 0700,$revert_actions; | ||
1788 | chown 0,0,$revert_actions; | ||
1789 | } | ||
1790 | else { | ||
1791 | &B_log("FATAL","Can not create revert-actions file: $revert_actions.\n" . | ||
1792 | " Unable to add the following command to the revert\n" . | ||
1793 | " actions script: $revert_command\n"); | ||
1794 | } | ||
1795 | |||
1796 | } | ||
1797 | |||
1798 | &B_open_plus (*REVERT_NEW, *REVERT_OLD, $revert_actions); | ||
1799 | |||
1800 | while (my $line=<REVERT_OLD>) { #copy file into @lines | ||
1801 | push (@lines,$line); | ||
1802 | } | ||
1803 | print REVERT_NEW $revert_command . "\n"; #make the revert command first in the new file | ||
1804 | while (my $line = shift @lines) { #write the rest of the lines of the file | ||
1805 | print REVERT_NEW $line; | ||
1806 | } | ||
1807 | close REVERT_OLD; | ||
1808 | close REVERT_NEW; | ||
1809 | if (rename "${revert_actions}.bastille", $revert_actions) { #replace the old file with the new file we | ||
1810 | chmod 0700,$revert_actions; # just made / mirrors B_close_plus logic | ||
1811 | chown 0,0,$revert_actions; | ||
1812 | } else { | ||
1813 | &B_log("ERROR","B_revert_log: not able to move ${revert_actions}.bastille to ${revert_actions}!!! $!) !!!\n"); | ||
1814 | } | ||
1815 | } | ||
1816 | |||
1817 | |||
1818 | ########################################################################### | ||
1819 | # &getGlobalConfig($$) | ||
1820 | # | ||
1821 | # returns the requested GLOBAL_CONFIG hash value, ignoring the error | ||
1822 | # if the value does not exist (because every module uses this to find | ||
1823 | # out if the question was answered "Y") | ||
1824 | ########################################################################### | ||
1825 | sub getGlobalConfig ($$) { | ||
1826 | my $module = $_[0]; | ||
1827 | my $key = $_[1]; | ||
1828 | if (exists $GLOBAL_CONFIG{$module}{$key}) { | ||
1829 | my $answer=$GLOBAL_CONFIG{$module}{$key}; | ||
1830 | &B_log("ACTION","Answer to question $module.$key is \"$answer\".\n"); | ||
1831 | return $answer; | ||
1832 | } else { | ||
1833 | &B_log("ACTION","Answer to question $module.$key is undefined."); | ||
1834 | return undef; | ||
1835 | } | ||
1836 | } | ||
1837 | |||
1838 | ########################################################################### | ||
1839 | # &getGlobal($$) | ||
1840 | # | ||
1841 | # returns the requested GLOBAL_* hash value, and logs an error | ||
1842 | # if the variable does not exist. | ||
1843 | ########################################################################### | ||
1844 | sub getGlobal ($$) { | ||
1845 | my $type = uc($_[0]); | ||
1846 | my $key = $_[1]; | ||
1847 | |||
1848 | # define a mapping from the first argument to the proper hash | ||
1849 | my %map = ("BIN" => \%GLOBAL_BIN, | ||
1850 | "FILE" => \%GLOBAL_FILE, | ||
1851 | "BFILE" => \%GLOBAL_BFILE, | ||
1852 | "DIR" => \%GLOBAL_DIR, | ||
1853 | "BDIR" => \%GLOBAL_BDIR, | ||
1854 | "ERROR" => \%GLOBAL_ERROR, | ||
1855 | "SERVICE" => \%GLOBAL_SERVICE, | ||
1856 | "SERVTYPE" => \%GLOBAL_SERVTYPE, | ||
1857 | "PROCESS" => \%GLOBAL_PROCESS, | ||
1858 | "RCCONFIG" => \%GLOBAL_RC_CONFIG | ||
1859 | ); | ||
1860 | |||
1861 | # check to see if the desired key is in the desired hash | ||
1862 | if (exists $map{$type}->{$key}) { | ||
1863 | # get the value from the right hash with the key | ||
1864 | return $map{$type}->{$key}; | ||
1865 | } else { | ||
1866 | # i.e. Bastille tried to use $GLOBAL_BIN{'cp'} but it does not exist. | ||
1867 | # Note that we can't use B_log, since it uses getGlobal ... recursive before | ||
1868 | # configureForDistro is run. | ||
1869 | print STDERR "ERROR: Bastille tried to use \$GLOBAL_${type}\{\'$key\'} but it does not exist.\n"; | ||
1870 | return undef; | ||
1871 | } | ||
1872 | } | ||
1873 | |||
1874 | ########################################################################### | ||
1875 | # &getGlobal($$) | ||
1876 | # | ||
1877 | # sets the requested GLOBAL_* hash value | ||
1878 | ########################################################################### | ||
1879 | sub setGlobal ($$$) { | ||
1880 | my $type = uc($_[0]); | ||
1881 | my $key = $_[1]; | ||
1882 | my $input_value = $_[2]; | ||
1883 | |||
1884 | # define a mapping from the first argument to the proper hash | ||
1885 | my %map = ("BIN" => \%GLOBAL_BIN, | ||
1886 | "FILE" => \%GLOBAL_FILE, | ||
1887 | "BFILE" => \%GLOBAL_BFILE, | ||
1888 | "DIR" => \%GLOBAL_DIR, | ||
1889 | "BDIR" => \%GLOBAL_BDIR, | ||
1890 | "ERROR" => \%GLOBAL_ERROR, | ||
1891 | "SERVICE" => \%GLOBAL_SERVICE, | ||
1892 | "SERVTYPE" => \%GLOBAL_SERVTYPE, | ||
1893 | "PROCESS" => \%GLOBAL_PROCESS, | ||
1894 | ); | ||
1895 | |||
1896 | if ($map{$type}->{$key} = $input_value) { | ||
1897 | return 1; | ||
1898 | } else { | ||
1899 | &B_log('ERROR','Internal Error, Unable to set global config value:' . $type . ", " .$key); | ||
1900 | return 0; | ||
1901 | } | ||
1902 | } | ||
1903 | |||
1904 | |||
1905 | ########################################################################### | ||
1906 | # &showDisclaimer: | ||
1907 | # Print the disclaimer and wait for 2 minutes for acceptance | ||
1908 | # Do NOT do so if any of the following conditions hold | ||
1909 | # 1. the -n option was used | ||
1910 | # 2. the file ~/.bastille_disclaimer exists | ||
1911 | ########################################################################### | ||
1912 | |||
1913 | sub showDisclaimer($) { | ||
1914 | |||
1915 | my $nodisclaim = $_[0]; | ||
1916 | my $nodisclaim_file = &getGlobal('BFILE', "nodisclaimer"); | ||
1917 | my $response; | ||
1918 | my $WAIT_TIME = 300; # we'll wait for 5 minutes | ||
1919 | my $developersAnd; | ||
1920 | my $developersOr; | ||
1921 | if ($GLOBAL_OS =~ "^HP-UX") { | ||
1922 | $developersAnd ="HP AND ITS"; | ||
1923 | $developersOr ="HP OR ITS"; | ||
1924 | }else{ | ||
1925 | $developersAnd ="JAY BEALE, THE BASTILLE DEVELOPERS, AND THEIR"; | ||
1926 | $developersOr ="JAY BEALE, THE BASTILLE DEVELOPERS, OR THEIR"; | ||
1927 | } | ||
1928 | my $DISCLAIMER = | ||
1929 | "\n" . | ||
1930 | "Copyright (C) 1999-2006 Jay Beale\n" . | ||
1931 | "Copyright (C) 1999-2001 Peter Watkins\n" . | ||
1932 | "Copyright (C) 2000 Paul L. Allen\n" . | ||
1933 | "Copyright (C) 2001-2007 Hewlett-Packard Development Company, L.P.\n" . | ||
1934 | "Bastille is free software; you are welcome to redistribute it under\n" . | ||
1935 | "certain conditions. See the \'COPYING\' file in your distribution for terms.\n\n" . | ||
1936 | "DISCLAIMER. Use of Bastille can help optimize system security, but does not\n" . | ||
1937 | "guarantee system security. Information about security obtained through use of\n" . | ||
1938 | "Bastille is provided on an AS-IS basis only and is subject to change without\n" . | ||
1939 | "notice. Customer acknowledges they are responsible for their system\'s security.\n" . | ||
1940 | "TO THE EXTENT ALLOWED BY LOCAL LAW, Bastille (\"SOFTWARE\") IS PROVIDED TO YOU \n" . | ||
1941 | "\"AS IS\" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, WHETHER ORAL OR WRITTEN,\n" . | ||
1942 | "EXPRESS OR IMPLIED. $developersAnd SUPPLIERS\n" . | ||
1943 | "DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE \n" . | ||
1944 | "IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.\n" . | ||
1945 | "Some countries, states and provinces do not allow exclusions of implied\n" . | ||
1946 | "warranties or conditions, so the above exclusion may not apply to you. You may\n" . | ||
1947 | "have other rights that vary from country to country, state to state, or province\n" . | ||
1948 | "to province. EXCEPT TO THE EXTENT PROHIBITED BY LOCAL LAW, IN NO EVENT WILL\n" . | ||
1949 | "$developersOr SUBSIDIARIES, AFFILIATES OR\n" . | ||
1950 | "SUPPLIERS BE LIABLE FOR DIRECT, SPECIAL, INCIDENTAL, CONSEQUENTIAL OR OTHER\n" . | ||
1951 | "DAMAGES (INCLUDING LOST PROFIT, LOST DATA, OR DOWNTIME COSTS), ARISING OUT OF\n" . | ||
1952 | "THE USE, INABILITY TO USE, OR THE RESULTS OF USE OF THE SOFTWARE, WHETHER BASED\n" . | ||
1953 | "IN WARRANTY, CONTRACT, TORT OR OTHER LEGAL THEORY, AND WHETHER OR NOT ADVISED\n" . | ||
1954 | "OF THE POSSIBILITY OF SUCH DAMAGES. Your use of the Software is entirely at your\n" . | ||
1955 | "own risk. Should the Software prove defective, you assume the entire cost of all\n" . | ||
1956 | "service, repair or correction. Some countries, states and provinces do not allow\n" . | ||
1957 | "the exclusion or limitation of liability for incidental or consequential \n" . | ||
1958 | "damages, so the above limitation may not apply to you. This notice will only \n". | ||
1959 | "display on the first run on a given system.\n". | ||
1960 | "To suppress the disclaimer on other machines, use Bastille\'s -n flag (example: bastille -n).\n"; | ||
1961 | |||
1962 | |||
1963 | # If the user has specified not to show the disclaimer, or | ||
1964 | # the .bastille_disclaimer file already exists, then return | ||
1965 | if( ( $nodisclaim ) || -e $nodisclaim_file ) { return 1; } | ||
1966 | |||
1967 | # otherwise, show the disclaimer | ||
1968 | print ($DISCLAIMER); | ||
1969 | |||
1970 | # there is a response | ||
1971 | my $touch = &getGlobal('BIN', "touch"); | ||
1972 | my $retVal = system("$touch $nodisclaim_file"); | ||
1973 | if( $retVal != 0 ) { | ||
1974 | &ErrorLog ( &getGlobal('ERROR','disclaimer')); | ||
1975 | } | ||
1976 | } # showDisclaimer | ||
1977 | |||
1978 | |||
1979 | |||
1980 | |||
1981 | ################################################################ | ||
1982 | # &systemCall | ||
1983 | #Function used by exported methods B_Backtick and B_system | ||
1984 | #to handle the mechanics of system calls. | ||
1985 | # This function also manages error handling. | ||
1986 | # Input: a system call | ||
1987 | # Output: a list containing the status, sstdout and stderr | ||
1988 | # of the the system call | ||
1989 | # | ||
1990 | ################################################################ | ||
1991 | sub systemCall ($){ | ||
1992 | no strict; | ||
1993 | local $command=$_[0]; # changed scoping so eval below can read it | ||
1994 | |||
1995 | local $SIG{'ALRM'} = sub { die "timeout" }; # This subroutine exits the "eval" below. The program | ||
1996 | # can then move on to the next operation. Used "local" | ||
1997 | # to avoid name space collision with disclaim alarm. | ||
1998 | local $WAIT_TIME=120; # Wait X seconds for system commands | ||
1999 | local $commandOutput = ''; | ||
2000 | my $errOutput = ''; | ||
2001 | eval{ | ||
2002 | $errorFile = &getGlobal('BFILE','stderrfile'); | ||
2003 | unlink($errorFile); #To make sure we don't mix output | ||
2004 | alarm($WAIT_TIME); # start a time-out for command to complete. Some commands hang, and we want to | ||
2005 | # fail gracefully. When we call "die" it exits this eval statement | ||
2006 | # with a value we use below | ||
2007 | $commandOutput = `$command 2> $errorFile`; # run the command and gather its output | ||
2008 | my $commandRetVal = ($? >> 8); # find the commands return value | ||
2009 | if ($commandRetVal == 0) { | ||
2010 | &B_log("ACTION","Executed Command: " . $command . "\n"); | ||
2011 | &B_log("ACTION","Command Output: " . $commandOutput . "\n"); | ||
2012 | die "success"; | ||
2013 | } else { | ||
2014 | die "failure"; | ||
2015 | }; | ||
2016 | }; | ||
2017 | |||
2018 | my $exitcode=$@; | ||
2019 | alarm(0); # End of the timed operation | ||
2020 | |||
2021 | my $cat = &getGlobal("BIN","cat"); | ||
2022 | if ( -e $errorFile ) { | ||
2023 | $errOutput = `$cat $errorFile`; | ||
2024 | } | ||
2025 | |||
2026 | if ($exitcode) { # The eval command above will exit with one of the 3 values below | ||
2027 | if ($exitcode =~ /timeout/) { | ||
2028 | &B_log("WARNING","No response received from $command after $WAIT_TIME seconds.\n" . | ||
2029 | "Command Output: " . $commandOutput . "\n"); | ||
2030 | return (0,'',''); | ||
2031 | } elsif ($exitcode =~ /success/) { | ||
2032 | return (1,$commandOutput,$errOutput); | ||
2033 | } elsif ($exitcode =~ /failure/) { | ||
2034 | return (0,$commandOutput,$errOutput); | ||
2035 | } else { | ||
2036 | &B_log("FATAL","Unexpected return state from command execution: $command\n" . | ||
2037 | "Command Output: " . $commandOutput . "\n"); | ||
2038 | } | ||
2039 | } | ||
2040 | } | ||
2041 | |||
2042 | ############################################# | ||
2043 | # Use this **only** for commands used that are | ||
2044 | # intended to test system state and | ||
2045 | # not make any system change. Use this in place of the | ||
2046 | # prior use of "backticks throughout Bastille | ||
2047 | # Handles basic output redirection, but not for stdin | ||
2048 | # Input: Command | ||
2049 | # Output: Results | ||
2050 | ############################################# | ||
2051 | |||
2052 | sub B_Backtick($) { | ||
2053 | my $command=$_[0]; | ||
2054 | my $combineOutput=0; | ||
2055 | my $stdoutRedir = ""; | ||
2056 | my $stderrRedir = ""; | ||
2057 | my $echo = &getGlobal('BIN','echo'); | ||
2058 | |||
2059 | if (($command =~ s/2>&1//) or | ||
2060 | (s/>&2//)){ | ||
2061 | $combineOutput=1; | ||
2062 | } | ||
2063 | if ($command =~ s/>\s*([^>\s])+// ) { | ||
2064 | $stdoutRedir = $1; | ||
2065 | } | ||
2066 | if ($command =~ s/2>\s*([^>\s])+// ) { | ||
2067 | $stderrRedir = $1; | ||
2068 | } | ||
2069 | |||
2070 | my ($ranFine, $stdout, $stderr) = &systemCall($command); | ||
2071 | if ($ranFine) { | ||
2072 | &B_log("DEBUG","Command: $command succeeded for test with output: $stdout , ". | ||
2073 | "and stderr: $stderr"); | ||
2074 | } else { | ||
2075 | &B_log("DEBUG","Command: $command failed for test with output: $stdout , ". | ||
2076 | "and stderr: $stderr"); | ||
2077 | } | ||
2078 | if ($combineOutput) { | ||
2079 | $stdout .= $stderr; | ||
2080 | $stderr = $stdout; #these should be the same | ||
2081 | } | ||
2082 | if ($stdoutRedir ne "") { | ||
2083 | system("$echo \'$stdout\' > $stdoutRedir"); | ||
2084 | } | ||
2085 | if ($stderrRedir ne "") { | ||
2086 | system("$echo \'$stderr\' > $stderrRedir"); | ||
2087 | } | ||
2088 | return $stdout; | ||
2089 | } | ||
2090 | |||
2091 | #################################################################### | ||
2092 | # &B_System($command,$revertcommand); | ||
2093 | # This function executes a command, then places the associated | ||
2094 | # revert command in revert file. It takes two parameters, the | ||
2095 | # command and the command that reverts that command. | ||
2096 | # | ||
2097 | # uses ActionLog and ErrorLog for logging purposes. | ||
2098 | ################################################################### | ||
2099 | sub B_System ($$) { | ||
2100 | my ($command,$revertcmd)=@_; | ||
2101 | |||
2102 | my ($ranFine, $stdout, $stderr) = &systemCall($command); | ||
2103 | if ($ranFine) { | ||
2104 | &B_revert_log ("$revertcmd \n"); | ||
2105 | if ($stderr ne '' ) { | ||
2106 | &B_log("ACTION",$command . "suceeded with STDERR: " . | ||
2107 | $stderr . "\n"); | ||
2108 | } | ||
2109 | return 1; | ||
2110 | } else { | ||
2111 | my $warningString = "Command Failed: " . $command . "\n" . | ||
2112 | "Command Output: " . $stdout . "\n"; | ||
2113 | if ($stderr ne '') { | ||
2114 | $warningString .= "Error message: " . $stderr; | ||
2115 | } | ||
2116 | &B_log("WARNING", $warningString); | ||
2117 | return 0; | ||
2118 | } | ||
2119 | } | ||
2120 | |||
2121 | |||
2122 | ########################################################################### | ||
2123 | # &isProcessRunning($procPattern); | ||
2124 | # | ||
2125 | # If called in scalar context this subroutine will return a 1 if the | ||
2126 | # pattern specified can be matched against the process table. It will | ||
2127 | # return a 0 otherwise. | ||
2128 | # If called in the list context this subroutine will return the list | ||
2129 | # of processes which matched the pattern supplied | ||
2130 | # | ||
2131 | # scalar return values: | ||
2132 | # 0: pattern not in process table | ||
2133 | # 1: pattern is in process table | ||
2134 | # | ||
2135 | # list return values: | ||
2136 | # proc lines from the process table if they are found | ||
2137 | ########################################################################### | ||
2138 | sub isProcessRunning($) { | ||
2139 | |||
2140 | my $procPattern= $_[0]; | ||
2141 | my $ps = &getGlobal('BIN',"ps"); | ||
2142 | |||
2143 | my $isRunning=0; | ||
2144 | # process table. | ||
2145 | my @psTable = `$ps -elf`; | ||
2146 | # list of processes that match the $procPattern | ||
2147 | my @procList; | ||
2148 | foreach my $process (@psTable) { | ||
2149 | if($process =~ $procPattern) { | ||
2150 | $isRunning = 1; | ||
2151 | push @procList, $process . "\n"; | ||
2152 | } | ||
2153 | } | ||
2154 | |||
2155 | &B_log("DEBUG","$procPattern search yielded $isRunning\n\n"); | ||
2156 | # if this subroutine was called in scalar context | ||
2157 | if( ! wantarray ) { | ||
2158 | return $isRunning; | ||
2159 | } | ||
2160 | |||
2161 | return @procList; | ||
2162 | } | ||
2163 | |||
2164 | |||
2165 | ########################################################################### | ||
2166 | # &checkProcsForService($service); | ||
2167 | # | ||
2168 | # Checks if the given service is running by analyzing the process table. | ||
2169 | # This is a helper function to checkServiceOnLinux and checkServiceOnHP | ||
2170 | # | ||
2171 | # Return values: | ||
2172 | # SECURE_CANT_CHANGE() if the service is off | ||
2173 | # INCONSISTENT() if the state of the service cannot be determined | ||
2174 | # | ||
2175 | # Mostly used in "check service" direct-return context, but added option use. | ||
2176 | # to ignore warning if a check for a service ... where a found service doesn't | ||
2177 | # have direct security problems. | ||
2178 | # | ||
2179 | ########################################################################### | ||
2180 | sub checkProcsForService ($;$) { | ||
2181 | my $service=$_[0]; | ||
2182 | my $ignore_warning=$_[1]; | ||
2183 | |||
2184 | my @psnames=@{ &getGlobal('PROCESS',$service)}; | ||
2185 | |||
2186 | my @processes; | ||
2187 | # inetd services don't have a separate process | ||
2188 | foreach my $psname (@psnames) { | ||
2189 | my @procList = &isProcessRunning($psname); | ||
2190 | if(@procList >= 0){ | ||
2191 | splice @processes,$#processes+1,0,@procList; | ||
2192 | } | ||
2193 | } | ||
2194 | |||
2195 | if($#processes >= 0){ | ||
2196 | if ((defined($ignore_warning)) and ($ignore_warning eq "ignore_warning")) { | ||
2197 | &B_log("WARNING","The following processes were still running even though " . | ||
2198 | "the corresponding service appears to be turned off. Bastille " . | ||
2199 | "question and action will be skipped.\n\n" . | ||
2200 | "@processes\n\n"); | ||
2201 | # processes were still running, service is not off, but we don't know how | ||
2202 | # to configure it so we skip the question | ||
2203 | return INCONSISTENT(); | ||
2204 | } else { | ||
2205 | return NOTSECURE_CAN_CHANGE(); # In the case we're ignoring the warning, | ||
2206 | # ie: checking to make *sure* a process | ||
2207 | # is running, the answer isn't inconsistent | ||
2208 | } | ||
2209 | } else { | ||
2210 | &B_log("DEBUG","$service is off. Found no processes running on the system."); | ||
2211 | # no processes, so service is off | ||
2212 | return SECURE_CANT_CHANGE(); | ||
2213 | } | ||
2214 | # Can't determine the state of the service by looking at the processes, | ||
2215 | # so return INCONSISTENT(). | ||
2216 | return INCONSISTENT(); | ||
2217 | } | ||
2218 | |||
2219 | ########################################################################### | ||
2220 | # B_parse_fstab() | ||
2221 | # | ||
2222 | # Search the filesystem table for a specific mount point. | ||
2223 | # | ||
2224 | # scalar return value: | ||
2225 | # The line form the table that matched the mount point, or the null string | ||
2226 | # if no match was found. | ||
2227 | # | ||
2228 | # list return value: | ||
2229 | # A list of parsed values from the line of the table that matched, with | ||
2230 | # element [3] containing a reference to a hash of the mount options. The | ||
2231 | # keys are: acl, dev, exec, rw, suid, sync, or user. The value of each key | ||
2232 | # can be either 0 or 1. To access the hash, use code similar to this: | ||
2233 | # %HashResult = %{(&B_parse_fstab($MountPoint))[3]}; | ||
2234 | # | ||
2235 | ########################################################################### | ||
2236 | |||
2237 | sub B_parse_fstab($) | ||
2238 | { | ||
2239 | my $name = shift; | ||
2240 | my $file = &getGlobal('FILE','fstab'); | ||
2241 | my ($enable, $disable, $infile); | ||
2242 | my @lineopt; | ||
2243 | my $retline = ""; | ||
2244 | my @retlist = (); | ||
2245 | |||
2246 | unless (open FH, $file) { | ||
2247 | &B_log('ERROR',"B_parse_fstab couldn't open fstab file at path $file.\n"); | ||
2248 | return 0; | ||
2249 | } | ||
2250 | while (<FH>) { | ||
2251 | s/\#.*//; | ||
2252 | next unless /\S/; | ||
2253 | @retlist = split; | ||
2254 | next unless $retlist[1] eq $name; | ||
2255 | $retline .= $_; | ||
2256 | if (wantarray) { | ||
2257 | my $option = { # initialize to defaults | ||
2258 | acl => 0, # for ext2, etx3, reiserfs | ||
2259 | dev => 1, | ||
2260 | exec => 1, | ||
2261 | rw => 1, | ||
2262 | suid => 1, | ||
2263 | sync => 0, | ||
2264 | user => 0, | ||
2265 | }; | ||
2266 | |||
2267 | my @lineopt = split(',',$retlist[3]); | ||
2268 | foreach my $entry (@lineopt) { | ||
2269 | if ($entry eq 'acl') { | ||
2270 | $option->{'acl'} = 1; | ||
2271 | } | ||
2272 | elsif ($entry eq 'nodev') { | ||
2273 | $option->{'dev'} = 0; | ||
2274 | } | ||
2275 | elsif ($entry eq 'noexec') { | ||
2276 | $option->{'exec'} = 0; | ||
2277 | } | ||
2278 | elsif ($entry eq 'ro') { | ||
2279 | $option->{'rw'} = 0; | ||
2280 | } | ||
2281 | elsif ($entry eq 'nosuid') { | ||
2282 | $option->{'suid'} = 0; | ||
2283 | } | ||
2284 | elsif ($entry eq 'sync') { | ||
2285 | $option->{'sync'} = 1; | ||
2286 | } | ||
2287 | elsif ($entry eq 'user') { | ||
2288 | $option->{'user'} = 1; | ||
2289 | } | ||
2290 | } | ||
2291 | $retlist[3]= $option; | ||
2292 | } | ||
2293 | last; | ||
2294 | } | ||
2295 | |||
2296 | if (wantarray) | ||
2297 | { | ||
2298 | return @retlist; | ||
2299 | } | ||
2300 | else | ||
2301 | { | ||
2302 | return $retline; | ||
2303 | } | ||
2304 | |||
2305 | } | ||
2306 | |||
2307 | |||
2308 | ########################################################################### | ||
2309 | # B_parse_mtab() | ||
2310 | # | ||
2311 | # This routine returns a hash of devices and their mount points from mtab, | ||
2312 | # simply so you can get a list of mounted filesystems. | ||
2313 | # | ||
2314 | ########################################################################### | ||
2315 | |||
2316 | sub B_parse_mtab | ||
2317 | { | ||
2318 | my $mountpoints; | ||
2319 | open(MTAB,&getGlobal('FILE','mtab')); | ||
2320 | while(my $mtab_line = <MTAB>) { | ||
2321 | #test if it's a device | ||
2322 | if ($mtab_line =~ /^\//) | ||
2323 | { | ||
2324 | #parse out device and mount point | ||
2325 | $mtab_line =~ /^(\S+)\s+(\S+)/; | ||
2326 | $mountpoints->{$1} = $2; | ||
2327 | } | ||
2328 | } | ||
2329 | return $mountpoints; | ||
2330 | } | ||
2331 | |||
2332 | |||
2333 | ########################################################################### | ||
2334 | # B_is_rpm_up_to_date() | ||
2335 | # | ||
2336 | # | ||
2337 | ########################################################################### | ||
2338 | |||
2339 | sub B_is_rpm_up_to_date(@) | ||
2340 | { | ||
2341 | my($nameB,$verB,$relB,$epochB) = @_; | ||
2342 | my $installedpkg = $nameB; | ||
2343 | |||
2344 | if ($epochB =~ /(none)/) { | ||
2345 | $epochB = 0; | ||
2346 | } | ||
2347 | |||
2348 | my $rpmA = `rpm -q --qf '%{VERSION}-%{RELEASE}-%{EPOCH}\n' $installedpkg`; | ||
2349 | my $nameA = $nameB; | ||
2350 | my ($verA,$relA,$epochA); | ||
2351 | |||
2352 | my $retval; | ||
2353 | |||
2354 | # First, if the RPM isn't installed, let's handle that. | ||
2355 | if ($rpmA =~ /is not installed/) { | ||
2356 | $retval = -1; | ||
2357 | return $retval; | ||
2358 | } | ||
2359 | else { | ||
2360 | # Next, let's try to parse the EVR information without as few | ||
2361 | # calls as possible to rpm. | ||
2362 | if ($rpmA =~ /([^-]+)-([^-]+)-([^-]+)$/) { | ||
2363 | $verA = $1; | ||
2364 | $relA = $2; | ||
2365 | $epochA = $3; | ||
2366 | } | ||
2367 | else { | ||
2368 | $nameA = `rpm -q --qf '%{NAME}' $installedpkg`; | ||
2369 | $verA = `rpm -q --qf '%{VERSION}' $installedpkg`; | ||
2370 | $relA = `rpm -q --qf '%{RELEASE}' $installedpkg`; | ||
2371 | $epochA = `rpm -q --qf '%{EPOCH}' $installedpkg`; | ||
2372 | } | ||
2373 | } | ||
2374 | |||
2375 | # Parse "none" as 0. | ||
2376 | if ($epochA =~ /(none)/) { | ||
2377 | $epochA = 0; | ||
2378 | } | ||
2379 | |||
2380 | # Handle the case where only one of them is zero. | ||
2381 | if ($epochA == 0 xor $epochB == 0) | ||
2382 | { | ||
2383 | if ($epochA != 0) | ||
2384 | { | ||
2385 | $retval = 1; | ||
2386 | } | ||
2387 | else | ||
2388 | { | ||
2389 | $retval = 0; | ||
2390 | } | ||
2391 | } | ||
2392 | else | ||
2393 | { | ||
2394 | # ...otherwise they are either both 0 or both non-zero and | ||
2395 | # so the situation isn't trivial. | ||
2396 | |||
2397 | # Check epoch first - highest epoch wins. | ||
2398 | my $rpmcmp = &cmp_vers_part($epochA, $epochB); | ||
2399 | #print "epoch rpmcmp is $rpmcmp\n"; | ||
2400 | if ($rpmcmp > 0) | ||
2401 | { | ||
2402 | $retval = 1; | ||
2403 | } | ||
2404 | elsif ($rpmcmp < 0) | ||
2405 | { | ||
2406 | $retval = 0; | ||
2407 | } | ||
2408 | else | ||
2409 | { | ||
2410 | # Epochs were the same. Check Version now. | ||
2411 | $rpmcmp = &cmp_vers_part($verA, $verB); | ||
2412 | #print "epoch rpmcmp is $rpmcmp\n"; | ||
2413 | if ($rpmcmp > 0) | ||
2414 | { | ||
2415 | $retval = 1; | ||
2416 | } | ||
2417 | elsif ($rpmcmp < 0) | ||
2418 | { | ||
2419 | $retval = 0; | ||
2420 | } | ||
2421 | else | ||
2422 | { | ||
2423 | # Versions were the same. Check Release now. | ||
2424 | my $rpmcmp = &cmp_vers_part($relA, $relB); | ||
2425 | #print "epoch rpmcmp is $rpmcmp\n"; | ||
2426 | if ($rpmcmp >= 0) | ||
2427 | { | ||
2428 | $retval = 1; | ||
2429 | } | ||
2430 | elsif ($rpmcmp < 0) | ||
2431 | { | ||
2432 | $retval = 0; | ||
2433 | } | ||
2434 | } | ||
2435 | } | ||
2436 | } | ||
2437 | return $retval; | ||
2438 | } | ||
2439 | |||
2440 | ################################################# | ||
2441 | # Helper function for B_is_rpm_up_to_date() | ||
2442 | ################################################# | ||
2443 | |||
2444 | #This cmp_vers_part function taken from Kirk Bauer's Autorpm. | ||
2445 | # This version comparison code was sent in by Robert Mitchell and, although | ||
2446 | # not yet perfect, is better than the original one I had. He took the code | ||
2447 | # from freshrpms and did some mods to it. Further mods by Simon Liddington | ||
2448 | # <sjl96v@ecs.soton.ac.uk>. | ||
2449 | # | ||
2450 | # Splits string into minors on . and change from numeric to non-numeric | ||
2451 | # characters. Minors are compared from the beginning of the string. If the | ||
2452 | # minors are both numeric then they are numerically compared. If both minors | ||
2453 | # are non-numeric and a single character they are alphabetically compared, if | ||
2454 | # they are not a single character they are checked to be the same if the are not | ||
2455 | # the result is unknown (currently we say the first is newer so that we have | ||
2456 | # a choice to upgrade). If one minor is numeric and one non-numeric then the | ||
2457 | # numeric one is newer as it has a longer version string. | ||
2458 | # We also assume that (for example) .15 is equivalent to 0.15 | ||
2459 | |||
2460 | sub cmp_vers_part($$) { | ||
2461 | my($va, $vb) = @_; | ||
2462 | my(@va_dots, @vb_dots); | ||
2463 | my($a, $b); | ||
2464 | my($i); | ||
2465 | |||
2466 | if ($vb !~ /^pre/ and $va =~ s/^pre(\d+.*)$/$1/) { | ||
2467 | if ($va eq $vb) { return -1; } | ||
2468 | } elsif ($va !~ /^pre/ and $vb =~ s/^pre(\d+.*)$/$1/) { | ||
2469 | if ($va eq $vb) { return 1; } | ||
2470 | } | ||
2471 | |||
2472 | @va_dots = split(/\./, $va); | ||
2473 | @vb_dots = split(/\./, $vb); | ||
2474 | |||
2475 | $a = shift(@va_dots); | ||
2476 | $b = shift(@vb_dots); | ||
2477 | # We also assume that (for example) .15 is equivalent to 0.15 | ||
2478 | if ($a eq '' && $va ne '') { $a = "0"; } | ||
2479 | if ($b eq '' && $vb ne '') { $b = "0"; } | ||
2480 | while ((defined($a) && $a ne '') || (defined($b) && $b ne '')) { | ||
2481 | # compare each minor from left to right | ||
2482 | if ((not defined($a)) || ($a eq '')) { return -1; } # the longer version is newer | ||
2483 | if ((not defined($b)) || ($b eq '')) { return 1; } | ||
2484 | if ($a =~ /^\d+$/ && $b =~ /^\d+$/) { | ||
2485 | # I have changed this so that when the two strings are numeric, but one or both | ||
2486 | # of them start with a 0, then do a string compare - Kirk Bauer - 5/28/99 | ||
2487 | if ($a =~ /^0/ or $b =~ /^0/) { | ||
2488 | # We better string-compare so that netscape-4.6 is newer than netscape-4.08 | ||
2489 | if ($a ne $b) {return ($a cmp $b);} | ||
2490 | } | ||
2491 | # numeric compare | ||
2492 | if ($a != $b) { return $a <=> $b; } | ||
2493 | } elsif ($a =~ /^\D+$/ && $b =~ /^\D+$/) { | ||
2494 | # string compare | ||
2495 | if (length($a) == 1 && length($b) == 1) { | ||
2496 | # only minors with one letter seem to be useful for versioning | ||
2497 | if ($a ne $b) { return $a cmp $b; } | ||
2498 | } elsif (($a cmp $b) != 0) { | ||
2499 | # otherwise we should at least check they are the same and if not say unknown | ||
2500 | # say newer for now so at least we get choice whether to upgrade or not | ||
2501 | return -1; | ||
2502 | } | ||
2503 | } elsif ( ($a =~ /^\D+$/ && $b =~ /^\d+$/) || ($a =~ /^\d+$/ && $b =~ /^\D+$/) ) { | ||
2504 | # if we get a number in one and a word in another the one with a number | ||
2505 | # has a longer version string | ||
2506 | if ($a =~ /^\d+$/) { return 1; } | ||
2507 | if ($b =~ /^\d+$/) { return -1; } | ||
2508 | } else { | ||
2509 | # minor needs splitting | ||
2510 | $a =~ /\d+/ || $a =~ /\D+/; | ||
2511 | # split the $a minor into numbers and non-numbers | ||
2512 | my @va_bits = ($`, $&, $'); | ||
2513 | $b =~ /\d+/ || $b =~ /\D+/; | ||
2514 | # split the $b minor into numbers and non-numbers | ||
2515 | my @vb_bits = ($`, $&, $'); | ||
2516 | for ( my $j=2; $j >= 0; $j--) { | ||
2517 | if ($va_bits[$j] ne '') { unshift(@va_dots,$va_bits[$j]); } | ||
2518 | if ($vb_bits[$j] ne '') { unshift(@vb_dots,$vb_bits[$j]); } | ||
2519 | } | ||
2520 | } | ||
2521 | $a = shift(@va_dots); | ||
2522 | $b = shift(@vb_dots); | ||
2523 | } | ||
2524 | return 0; | ||
2525 | } | ||
2526 | |||
2527 | 1; | ||
2528 | |||
diff --git a/dynamic-layers/meta-perl/recipes-security/bastille/files/AccountPermission.pm b/dynamic-layers/meta-perl/recipes-security/bastille/files/AccountPermission.pm new file mode 100644 index 0000000..132b30c --- /dev/null +++ b/dynamic-layers/meta-perl/recipes-security/bastille/files/AccountPermission.pm | |||
@@ -0,0 +1,1060 @@ | |||
1 | package Bastille::API::AccountPermission; | ||
2 | use strict; | ||
3 | |||
4 | use Bastille::API; | ||
5 | |||
6 | use Bastille::API::HPSpecific; | ||
7 | |||
8 | require Exporter; | ||
9 | our @ISA = qw(Exporter); | ||
10 | our @EXPORT_OK = qw( | ||
11 | B_chmod | ||
12 | B_chmod_if_exists | ||
13 | B_chown | ||
14 | B_chown_link | ||
15 | B_chgrp | ||
16 | B_chgrp_link | ||
17 | B_userdel | ||
18 | B_groupdel | ||
19 | B:remove_user_from_group | ||
20 | B_check_owner_group | ||
21 | B_is_unowned_file | ||
22 | B_is_ungrouped_file | ||
23 | B_check_permissions | ||
24 | B_permission_test | ||
25 | B_find_homes | ||
26 | B_is_executable | ||
27 | B_is_suid | ||
28 | B_is_sgid | ||
29 | B_get_user_list | ||
30 | B_get_group_list | ||
31 | B:remove_suid | ||
32 | ); | ||
33 | our @EXPORT = @EXPORT_OK; | ||
34 | |||
35 | ########################################################################### | ||
36 | # &B_chmod ($mode, $file) sets the mode of $file to $mode. $mode must | ||
37 | # be stored in octal, so if you want to give mode 700 to /etc/aliases, | ||
38 | # you need to use: | ||
39 | # | ||
40 | # &B_chmod ( 0700 , "/etc/aliases"); | ||
41 | # | ||
42 | # where the 0700 denotes "octal 7-0-0". | ||
43 | # | ||
44 | # &B_chmod ($mode_changes,$file) also respects the symbolic methods of | ||
45 | # changing file permissions, which are often what question authors are | ||
46 | # really seeking. | ||
47 | # | ||
48 | # &B_chmod ("u-s" , "/bin/mount") | ||
49 | # or | ||
50 | # &B_chmod ("go-rwx", "/bin/mount") | ||
51 | # | ||
52 | # | ||
53 | # &B_chmod respects GLOBAL_LOGONLY and uses | ||
54 | # &B_revert_log used to insert a shell command that will return | ||
55 | # the permissions to the pre-Bastille state. | ||
56 | # | ||
57 | # B_chmod allow for globbing now, as of 1.2.0. JJB | ||
58 | # | ||
59 | ########################################################################## | ||
60 | |||
61 | |||
62 | sub B_chmod($$) { | ||
63 | my ($new_perm,$file_expr)=@_; | ||
64 | my $old_perm; | ||
65 | my $old_perm_raw; | ||
66 | my $new_perm_formatted; | ||
67 | my $old_perm_formatted; | ||
68 | |||
69 | my $retval=1; | ||
70 | |||
71 | my $symbolic = 0; | ||
72 | my ($chmod_noun,$add_remove,$capability) = (); | ||
73 | # Handle symbolic possibilities too | ||
74 | if ($new_perm =~ /([ugo]+)([+-]{1})([rwxst]+)/) { | ||
75 | $symbolic = 1; | ||
76 | $chmod_noun = $1; | ||
77 | $add:remove = $2; | ||
78 | $capability = $3; | ||
79 | } | ||
80 | |||
81 | my $file; | ||
82 | my @files = glob ($file_expr); | ||
83 | |||
84 | foreach $file (@files) { | ||
85 | |||
86 | # Prepend global prefix, but save the original filename for B_backup_file | ||
87 | my $original_file=$file; | ||
88 | |||
89 | # Store the old permissions so that we can log them. | ||
90 | unless (stat $file) { | ||
91 | &B_log("ERROR","Couldn't stat $original_file from $old_perm to change permissions\n"); | ||
92 | next; | ||
93 | } | ||
94 | |||
95 | $old_perm_raw=(stat(_))[2]; | ||
96 | $old_perm= (($old_perm_raw/512) % 8) . | ||
97 | (($old_perm_raw/64) % 8) . | ||
98 | (($old_perm_raw/8) % 8) . | ||
99 | ($old_perm_raw % 8); | ||
100 | |||
101 | # If we've gone symbolic, calculate the new permissions in octal. | ||
102 | if ($symbolic) { | ||
103 | # | ||
104 | # We calculate the new permissions by applying a bitmask to | ||
105 | # the current permissions, by OR-ing (for +) or XOR-ing (for -). | ||
106 | # | ||
107 | # We create this mask by first calculating a perm_mask that forms | ||
108 | # the right side of this, then multiplying it by 8 raised to the | ||
109 | # appropriate power to affect the correct digit of the octal mask. | ||
110 | # This means that we raise 8 to the power of 0,1,2, or 3, based on | ||
111 | # the noun of "other","group","user", or "suid/sgid/sticky". | ||
112 | # | ||
113 | # Actually, we handle multiple nouns by summing powers of 8. | ||
114 | # | ||
115 | # The only tough part is that we have to handle suid/sgid/sticky | ||
116 | # differently. | ||
117 | # | ||
118 | |||
119 | # We're going to calculate a mask to OR or XOR with the current | ||
120 | # file mode. This mask is $mask. We calculate this by calculating | ||
121 | # a sum of powers of 8, corresponding to user/group/other, | ||
122 | # multiplied with a $premask. The $premask is simply the | ||
123 | # corresponding bitwise expression of the rwx bits. | ||
124 | # | ||
125 | # To handle SUID, SGID or sticky in the simplest way possible, we | ||
126 | # simply add their values to the $mask first. | ||
127 | |||
128 | my $perm_mask = 00; | ||
129 | my $mask = 00; | ||
130 | |||
131 | # Check for SUID, SGID or sticky as these are exceptional. | ||
132 | if ($capability =~ /s/) { | ||
133 | if ($chmod_noun =~ /u/) { | ||
134 | $mask += 04000; | ||
135 | } | ||
136 | if ($chmod_noun =~ /g/) { | ||
137 | $mask += 02000; | ||
138 | } | ||
139 | } | ||
140 | if ($capability =~ /t/) { | ||
141 | $mask += 01000; | ||
142 | } | ||
143 | |||
144 | # Now handle the normal attributes | ||
145 | if ($capability =~ /[rwx]/) { | ||
146 | if ($capability =~ /r/) { | ||
147 | $perm_mask |= 04; | ||
148 | } | ||
149 | if ($capability =~ /w/) { | ||
150 | $perm_mask |= 02; | ||
151 | } | ||
152 | if ($capability =~ /x/) { | ||
153 | $perm_mask |= 01; | ||
154 | } | ||
155 | |||
156 | # Now figure out which 3 bit octal digit we're affecting. | ||
157 | my $power = 0; | ||
158 | if ($chmod_noun =~ /u/) { | ||
159 | $mask += $perm_mask * 64; | ||
160 | } | ||
161 | if ($chmod_noun =~ /g/) { | ||
162 | $mask += $perm_mask * 8; | ||
163 | } | ||
164 | if ($chmod_noun =~ /o/) { | ||
165 | $mask += $perm_mask * 1; | ||
166 | } | ||
167 | } | ||
168 | # Now apply the mask to get the new permissions | ||
169 | if ($add_remove eq '+') { | ||
170 | $new_perm = $old_perm_raw | $mask; | ||
171 | } | ||
172 | elsif ($add_remove eq '-') { | ||
173 | $new_perm = $old_perm_raw & ( ~($mask) ); | ||
174 | } | ||
175 | } | ||
176 | |||
177 | # formating for simple long octal output of the permissions in string form | ||
178 | $new_perm_formatted=sprintf "%5lo",$new_perm; | ||
179 | $old_perm_formatted=sprintf "%5lo",$old_perm_raw; | ||
180 | |||
181 | &B_log("ACTION","change permissions on $original_file from $old_perm_formatted to $new_perm_formatted\n"); | ||
182 | |||
183 | &B_log("ACTION", "chmod $new_perm_formatted,\"$original_file\";\n"); | ||
184 | |||
185 | # Change the permissions on the file | ||
186 | |||
187 | if ( -e $file ) { | ||
188 | unless ($GLOBAL_LOGONLY) { | ||
189 | $retval=chmod $new_perm,$file; | ||
190 | if($retval){ | ||
191 | # if the distribution is HP-UX then the modifications should | ||
192 | # also be made to the IPD (installed product database) | ||
193 | if(&GetDistro =~ "^HP-UX"){ | ||
194 | &B_swmodify($file); | ||
195 | } | ||
196 | # making changes revert-able | ||
197 | &B_revert_log(&getGlobal('BIN', "chmod") . " $old_perm $file\n"); | ||
198 | } | ||
199 | } | ||
200 | unless ($retval) { | ||
201 | &B_log("ERROR","Couldn't change permissions on $original_file from $old_perm_formatted to $new_perm_formatted\n"); | ||
202 | $retval=0; | ||
203 | } | ||
204 | } | ||
205 | else { | ||
206 | &B_log("ERROR", "chmod: File $original_file doesn't exist!\n"); | ||
207 | $retval=0; | ||
208 | } | ||
209 | } | ||
210 | |||
211 | $retval; | ||
212 | |||
213 | } | ||
214 | |||
215 | ########################################################################### | ||
216 | # &B_chmod_if_exists ($mode, $file) sets the mode of $file to $mode *if* | ||
217 | # $file exists. $mode must be stored in octal, so if you want to give | ||
218 | # mode 700 to /etc/aliases, you need to use: | ||
219 | # | ||
220 | # &B_chmod_if_exists ( 0700 , "/etc/aliases"); | ||
221 | # | ||
222 | # where the 0700 denotes "octal 7-0-0". | ||
223 | # | ||
224 | # &B_chmod_if_exists respects GLOBAL_LOGONLY and uses | ||
225 | # &B_revert_log to reset the permissions of the file. | ||
226 | # | ||
227 | # B_chmod_if_exists allow for globbing now, as of 1.2.0. JJB | ||
228 | # | ||
229 | ########################################################################## | ||
230 | |||
231 | |||
232 | sub B_chmod_if_exists($$) { | ||
233 | my ($new_perm,$file_expr)=@_; | ||
234 | # If $file_expr has a glob character, pass it on (B_chmod won't complain | ||
235 | # about nonexistent files if given a glob pattern) | ||
236 | if ( $file_expr =~ /[\*\[\{]/ ) { # } just to match open brace for vi | ||
237 | &B_log("ACTION","Running chmod $new_perm $file_expr"); | ||
238 | return(&B_chmod($new_perm,$file_expr)); | ||
239 | } | ||
240 | # otherwise, test for file existence | ||
241 | if ( -e $file_expr ) { | ||
242 | &B_log("ACTION","File exists, running chmod $new_perm $file_expr"); | ||
243 | return(&B_chmod($new_perm,$file_expr)); | ||
244 | } | ||
245 | } | ||
246 | |||
247 | ########################################################################### | ||
248 | # &B_chown ($uid, $file) sets the owner of $file to $uid, like this: | ||
249 | # | ||
250 | # &B_chown ( 0 , "/etc/aliases"); | ||
251 | # | ||
252 | # &B_chown respects $GLOBAL_LOGONLY and uses | ||
253 | # &B_revert_log to insert a shell command that will return | ||
254 | # the file/directory owner to the pre-Bastille state. | ||
255 | # | ||
256 | # Unlike Perl, we've broken the chown function into B_chown/B_chgrp to | ||
257 | # make error checking simpler. | ||
258 | # | ||
259 | # As of 1.2.0, this now supports file globbing. JJB | ||
260 | # | ||
261 | ########################################################################## | ||
262 | |||
263 | |||
264 | sub B_chown($$) { | ||
265 | my ($newown,$file_expr)=@_; | ||
266 | my $oldown; | ||
267 | my $oldgown; | ||
268 | |||
269 | my $retval=1; | ||
270 | |||
271 | my $file; | ||
272 | my @files = glob($file_expr); | ||
273 | |||
274 | foreach $file (@files) { | ||
275 | |||
276 | # Prepend prefix, but save original filename | ||
277 | my $original_file=$file; | ||
278 | |||
279 | $oldown=(stat $file)[4]; | ||
280 | $oldgown=(stat $file)[5]; | ||
281 | |||
282 | &B_log("ACTION","change ownership on $original_file from $oldown to $newown\n"); | ||
283 | &B_log("ACTION","chown $newown,$oldgown,\"$original_file\";\n"); | ||
284 | if ( -e $file ) { | ||
285 | unless ($GLOBAL_LOGONLY) { | ||
286 | # changing the files owner using perl chown function | ||
287 | $retval = chown $newown,$oldgown,$file; | ||
288 | if($retval){ | ||
289 | # if the distribution is HP-UX then the modifications should | ||
290 | # also be made to the IPD (installed product database) | ||
291 | if(&GetDistro =~ "^HP-UX"){ | ||
292 | &B_swmodify($file); | ||
293 | } | ||
294 | # making ownership change revert-able | ||
295 | &B_revert_log(&getGlobal('BIN', "chown") . " $oldown $file\n"); | ||
296 | } | ||
297 | } | ||
298 | unless ($retval) { | ||
299 | &B_log("ERROR","Couldn't change ownership to $newown on file $original_file\n"); | ||
300 | } | ||
301 | } | ||
302 | else { | ||
303 | &B_log("ERROR","chown: File $original_file doesn't exist!\n"); | ||
304 | $retval=0; | ||
305 | } | ||
306 | } | ||
307 | |||
308 | $retval; | ||
309 | } | ||
310 | |||
311 | ########################################################################### | ||
312 | # &B_chown_link just like &B_chown but one exception: | ||
313 | # if the input file is a link it will not change the target's ownship, it only change the link itself's ownship | ||
314 | ########################################################################### | ||
315 | sub B_chown_link($$){ | ||
316 | my ($newown,$file_expr)=@_; | ||
317 | my $chown = &getGlobal("BIN","chown"); | ||
318 | my @files = glob($file_expr); | ||
319 | my $retval = 1; | ||
320 | |||
321 | foreach my $file (@files) { | ||
322 | # Prepend prefix, but save original filename | ||
323 | my $original_file=$file; | ||
324 | my $oldown=(stat $file)[4]; | ||
325 | my $oldgown=(stat $file)[5]; | ||
326 | |||
327 | &B_log("ACTION","change ownership on $original_file from $oldown to $newown\n"); | ||
328 | &B_log("ACTION","chown -h $newown,\"$original_file\";\n"); | ||
329 | if ( -e $file ) { | ||
330 | unless ($GLOBAL_LOGONLY) { | ||
331 | `$chown -h $newown $file`; | ||
332 | $retval = ($? >> 8); | ||
333 | if($retval == 0 ){ | ||
334 | # if the distribution is HP-UX then the modifications should | ||
335 | # also be made to the IPD (installed product database) | ||
336 | if(&GetDistro =~ "^HP-UX"){ | ||
337 | &B_swmodify($file); | ||
338 | } | ||
339 | # making ownership change revert-able | ||
340 | &B_revert_log("$chown -h $oldown $file\n"); | ||
341 | } | ||
342 | } | ||
343 | unless ( ! $retval) { | ||
344 | &B_log("ERROR","Couldn't change ownership to $newown on file $original_file\n"); | ||
345 | } | ||
346 | } | ||
347 | else { | ||
348 | &B_log("ERROR","chown: File $original_file doesn't exist!\n"); | ||
349 | $retval=0; | ||
350 | } | ||
351 | } | ||
352 | } | ||
353 | |||
354 | |||
355 | ########################################################################### | ||
356 | # &B_chgrp ($gid, $file) sets the group owner of $file to $gid, like this: | ||
357 | # | ||
358 | # &B_chgrp ( 0 , "/etc/aliases"); | ||
359 | # | ||
360 | # &B_chgrp respects $GLOBAL_LOGONLY and uses | ||
361 | # &B_revert_log to insert a shell command that will return | ||
362 | # the file/directory group to the pre-Bastille state. | ||
363 | # | ||
364 | # Unlike Perl, we've broken the chown function into B_chown/B_chgrp to | ||
365 | # make error checking simpler. | ||
366 | # | ||
367 | # As of 1.2.0, this now supports file globbing. JJB | ||
368 | # | ||
369 | ########################################################################## | ||
370 | |||
371 | |||
372 | sub B_chgrp($$) { | ||
373 | my ($newgown,$file_expr)=@_; | ||
374 | my $oldown; | ||
375 | my $oldgown; | ||
376 | |||
377 | my $retval=1; | ||
378 | |||
379 | my $file; | ||
380 | my @files = glob($file_expr); | ||
381 | |||
382 | foreach $file (@files) { | ||
383 | |||
384 | # Prepend global prefix, but save original filename for &B_backup_file | ||
385 | my $original_file=$file; | ||
386 | |||
387 | $oldown=(stat $file)[4]; | ||
388 | $oldgown=(stat $file)[5]; | ||
389 | |||
390 | &B_log("ACTION", "Change group ownership on $original_file from $oldgown to $newgown\n"); | ||
391 | &B_log("ACTION", "chown $oldown,$newgown,\"$original_file\";\n"); | ||
392 | if ( -e $file ) { | ||
393 | unless ($GLOBAL_LOGONLY) { | ||
394 | # changing the group for the file/directory | ||
395 | $retval = chown $oldown,$newgown,$file; | ||
396 | if($retval){ | ||
397 | # if the distribution is HP-UX then the modifications should | ||
398 | # also be made to the IPD (installed product database) | ||
399 | if(&GetDistro =~ "^HP-UX"){ | ||
400 | &B_swmodify($file); | ||
401 | } | ||
402 | &B_revert_log(&getGlobal('BIN', "chgrp") . " $oldgown $file\n"); | ||
403 | } | ||
404 | } | ||
405 | unless ($retval) { | ||
406 | &B_log("ERROR","Couldn't change ownership to $newgown on file $original_file\n"); | ||
407 | } | ||
408 | } | ||
409 | else { | ||
410 | &B_log("ERROR","chgrp: File $original_file doesn't exist!\n"); | ||
411 | $retval=0; | ||
412 | } | ||
413 | } | ||
414 | |||
415 | $retval; | ||
416 | } | ||
417 | |||
418 | ########################################################################### | ||
419 | # &B_chgrp_link just like &B_chgrp but one exception: | ||
420 | # if the input file is a link | ||
421 | # it will not change the target's ownship, it only change the link itself's ownship | ||
422 | ########################################################################### | ||
423 | sub B_chgrp_link($$) { | ||
424 | my ($newgown,$file_expr)=@_; | ||
425 | my $chgrp = &getGlobal("BIN","chgrp"); | ||
426 | my @files = glob($file_expr); | ||
427 | my $retval=1; | ||
428 | |||
429 | foreach my $file (@files) { | ||
430 | # Prepend prefix, but save original filename | ||
431 | my $original_file=$file; | ||
432 | my $oldgown=(stat $file)[5]; | ||
433 | |||
434 | &B_log("ACTION","change group ownership on $original_file from $oldgown to $newgown\n"); | ||
435 | &B_log("ACTION","chgrp -h $newgown \"$original_file\";\n"); | ||
436 | if ( -e $file ) { | ||
437 | unless ($GLOBAL_LOGONLY) { | ||
438 | # do not follow link with option -h | ||
439 | `$chgrp -h $newgown $file`; | ||
440 | $retval = ($? >> 8); | ||
441 | if($retval == 0 ){ | ||
442 | # if the distribution is HP-UX then the modifications should | ||
443 | # also be made to the IPD (installed product database) | ||
444 | if(&GetDistro =~ "^HP-UX"){ | ||
445 | &B_swmodify($file); | ||
446 | } | ||
447 | # making ownership change revert-able | ||
448 | &B_revert_log("$chgrp" . " -h $oldgown $file\n"); | ||
449 | } | ||
450 | } | ||
451 | unless (! $retval) { | ||
452 | &B_log("ERROR","Couldn't change group ownership to $newgown on file $original_file\n"); | ||
453 | } | ||
454 | } | ||
455 | else { | ||
456 | &B_log("ERROR","chgrp: File $original_file doesn't exist!\n"); | ||
457 | $retval=0; | ||
458 | } | ||
459 | } | ||
460 | } | ||
461 | |||
462 | ########################################################################### | ||
463 | # B_userdel($user) removes $user from the system, chmoding her home | ||
464 | # directory to 000, root:root owned, and removes the user from all | ||
465 | # /etc/passwd, /etc/shadow and /etc/group lines. | ||
466 | # | ||
467 | # In the future, we may also choose to make a B_lock_account routine. | ||
468 | # | ||
469 | # This routine depends on B:remove_user_from_group. | ||
470 | ########################################################################### | ||
471 | |||
472 | sub B_userdel($) { | ||
473 | |||
474 | my $user_to_remove = $_[0]; | ||
475 | |||
476 | if (&GetDistro =~ /^HP-UX/) { | ||
477 | return 0; | ||
478 | |||
479 | # Not yet suported on HP-UX, where we'd need to support | ||
480 | # the TCB files and such. | ||
481 | } | ||
482 | |||
483 | # | ||
484 | # First, let's chmod/chown/chgrp the user's home directory. | ||
485 | # | ||
486 | |||
487 | # Get the user's home directory from /etc/passwd | ||
488 | if (open PASSWD,&getGlobal('FILE','passwd')) { | ||
489 | my @lines=<PASSWD>; | ||
490 | close PASSWD; | ||
491 | |||
492 | # Get the home directory | ||
493 | my $user_line = grep '^\s*$user_to_remove\s*:',@lines; | ||
494 | my $home_directory = (split /\s*:\s*/,$user_line)[5]; | ||
495 | |||
496 | # Chmod that home dir to 0000,owned by uid 0, gid 0. | ||
497 | if (&B_chmod_if_exists(0000,$home_directory)) { | ||
498 | &B_chown(0,$home_directory); | ||
499 | &B_chgrp(0,$home_directory); | ||
500 | } | ||
501 | } | ||
502 | else { | ||
503 | &B_log('ERROR',"B_userdel couldn't open the passwd file to remove a user."); | ||
504 | return 0; | ||
505 | } | ||
506 | |||
507 | # | ||
508 | # Next find out what groups the user is in, so we can call | ||
509 | # B:remove_user_from_group($user,$group) | ||
510 | # | ||
511 | # TODO: add this to the helper functions for the test suite. | ||
512 | # | ||
513 | |||
514 | my @groups = (); | ||
515 | |||
516 | # Parse /etc/group, looking for our user. | ||
517 | if (open GROUP,&getGlobal('FILE','group')) { | ||
518 | my @lines = <GROUP>; | ||
519 | close GROUP; | ||
520 | |||
521 | foreach my $line (@lines) { | ||
522 | |||
523 | # Parse the line -- first field is group, last is users in group. | ||
524 | if ($line =~ /([^\#^:]+):[^:]+:[^:]+:(.*)/) { | ||
525 | my $group = $1; | ||
526 | my $users_section = $2; | ||
527 | |||
528 | # Get the user list and check if our user is in it. | ||
529 | my @users = split /\s*,\s*/,$users_section; | ||
530 | foreach my $user (@users) { | ||
531 | if ($user_to_remove eq $user) { | ||
532 | push @groups,$group; | ||
533 | last; | ||
534 | } | ||
535 | } | ||
536 | } | ||
537 | } | ||
538 | } | ||
539 | |||
540 | # Now remove the user from each of those groups. | ||
541 | foreach my $group (@groups) { | ||
542 | &B_remove_user_from_group($user_to_remove,$group); | ||
543 | } | ||
544 | |||
545 | # Remove the user's /etc/passwd and /etc/shadow lines | ||
546 | &B_delete_line(&getGlobal('FILE','passwd'),"^$user_to_remove\\s*:"); | ||
547 | &B_delete_line(&getGlobal('FILE','shadow'),"^$user_to_remove\\s*:"); | ||
548 | |||
549 | |||
550 | # | ||
551 | # We should delete the user's group as well, if it's a single-user group. | ||
552 | # | ||
553 | if (open ETCGROUP,&getGlobal('FILE','group')) { | ||
554 | my @group_lines = <ETCGROUP>; | ||
555 | close ETCGROUP; | ||
556 | chomp @group_lines; | ||
557 | |||
558 | if (grep /^$user_to_remove\s*:[^:]*:[^:]*:\s*$/,@group_lines > 0) { | ||
559 | &B_groupdel($user_to_remove); | ||
560 | } | ||
561 | } | ||
562 | |||
563 | } | ||
564 | |||
565 | ########################################################################### | ||
566 | # B_groupdel($group) removes $group from /etc/group. | ||
567 | ########################################################################### | ||
568 | |||
569 | sub B_groupdel($) { | ||
570 | |||
571 | my $group = $_[0]; | ||
572 | |||
573 | # First read /etc/group to make sure the group is in there. | ||
574 | if (open GROUP,&getGlobal('FILE','group')) { | ||
575 | my @lines=<GROUP>; | ||
576 | close GROUP; | ||
577 | |||
578 | # Delete the line in /etc/group if present | ||
579 | if (grep /^$group:/,@lines > 0) { | ||
580 | # The group is named in /etc/group | ||
581 | &B_delete_line(&getGlobal('FILE','group'),"^$group:/"); | ||
582 | } | ||
583 | } | ||
584 | |||
585 | } | ||
586 | |||
587 | |||
588 | ########################################################################### | ||
589 | # B:remove_user_from_group($user,$group) removes $user from $group, | ||
590 | # by modifying $group's /etc/group line, pulling the user out. This | ||
591 | # uses B_chunk_replace thrice to replace these patterns: | ||
592 | # | ||
593 | # ":\s*$user\s*," --> ":" | ||
594 | # ",\s*$user" -> "" | ||
595 | # | ||
596 | ########################################################################### | ||
597 | |||
598 | sub B:remove_user_from_group($$) { | ||
599 | |||
600 | my ($user_to_remove,$group) = @_; | ||
601 | |||
602 | # | ||
603 | # We need to find the line from /etc/group that defines the group, parse | ||
604 | # it, and put it back together without this user. | ||
605 | # | ||
606 | |||
607 | # Open the group file | ||
608 | unless (open GROUP,&getGlobal('FILE','group')) { | ||
609 | &B_log('ERROR',"&B_remove_user_from_group couldn't read /etc/group to remove $user_to_remove from $group.\n"); | ||
610 | return 0; | ||
611 | } | ||
612 | my @lines = <GROUP>; | ||
613 | close GROUP; | ||
614 | chomp @lines; | ||
615 | |||
616 | # | ||
617 | # Read through the lines to find the one we care about. We'll construct a | ||
618 | # replacement and then use B_replace_line to make the switch. | ||
619 | # | ||
620 | |||
621 | foreach my $line (@lines) { | ||
622 | |||
623 | if ($line =~ /^\s*$group\s*:/) { | ||
624 | |||
625 | # Parse this line. | ||
626 | my @group_entries = split ':',$line; | ||
627 | my @users = split ',',($group_entries[3]); | ||
628 | |||
629 | # Now, recreate it. | ||
630 | my $first_user = 1; | ||
631 | my $group_line = $group_entries[0] . ':' . $group_entries[1] . ':' . $group_entries[2] . ':'; | ||
632 | |||
633 | # Add every user except the one we're removing. | ||
634 | foreach my $user (@users) { | ||
635 | |||
636 | # Remove whitespace. | ||
637 | $user =~ s/\s+//g; | ||
638 | |||
639 | if ($user ne $user_to_remove) { | ||
640 | # Add the user to the end of the line, prefacing | ||
641 | # it with a comma if it's not the first user. | ||
642 | |||
643 | if ($first_user) { | ||
644 | $group_line .= "$user"; | ||
645 | $first_user = 0; | ||
646 | } | ||
647 | else { | ||
648 | $group_line .= ",$user"; | ||
649 | } | ||
650 | } | ||
651 | } | ||
652 | |||
653 | # The line is now finished. Replace the original line. | ||
654 | $group_line .= "\n"; | ||
655 | &B_replace_line(&getGlobal('FILE','group'),"^\\s*$group\\s*:",$group_line); | ||
656 | } | ||
657 | |||
658 | } | ||
659 | return 1; | ||
660 | } | ||
661 | |||
662 | ########################################################################### | ||
663 | # &B_check_owner_group($$$) | ||
664 | # | ||
665 | # Checks if the given file has the given owner and/or group. | ||
666 | # If the given owner is "", checks group only. | ||
667 | # If the given group is "", checks owner only. | ||
668 | # | ||
669 | # return values: | ||
670 | # 1: file has the given owner and/or group | ||
671 | # or file exists, and both the given owner and group are "" | ||
672 | # 0: file does not has the given owner or group | ||
673 | # or file does not exists | ||
674 | ############################################################################ | ||
675 | |||
676 | sub B_check_owner_group ($$$){ | ||
677 | my ($fileName, $owner, $group) = @_; | ||
678 | |||
679 | if (-e $fileName) { | ||
680 | my @junk=stat ($fileName); | ||
681 | my $uid=$junk[4]; | ||
682 | my $gid=$junk[5]; | ||
683 | |||
684 | # Check file owner | ||
685 | if ($owner ne "") { | ||
686 | if (getpwnam($owner) != $uid) { | ||
687 | return 0; | ||
688 | } | ||
689 | } | ||
690 | |||
691 | # Check file group | ||
692 | if ($group ne "") { | ||
693 | if (getgrnam($group) != $gid) { | ||
694 | return 0; | ||
695 | } | ||
696 | } | ||
697 | |||
698 | return 1; | ||
699 | } | ||
700 | else { | ||
701 | # Something is wrong if the file not exist | ||
702 | return 0; | ||
703 | } | ||
704 | } | ||
705 | |||
706 | ########################################################################## | ||
707 | # this subroutine will test whether the given file is unowned | ||
708 | ########################################################################## | ||
709 | sub B_is_unowned_file($) { | ||
710 | my $file =$_; | ||
711 | my $uid = (stat($file))[4]; | ||
712 | my $uname = (getpwuid($uid))[0]; | ||
713 | if ( $uname =~ /.+/ ) { | ||
714 | return 1; | ||
715 | } | ||
716 | return 0; | ||
717 | } | ||
718 | |||
719 | ########################################################################## | ||
720 | # this subroutine will test whether the given file is ungrouped | ||
721 | ########################################################################## | ||
722 | sub B_is_ungrouped_file($){ | ||
723 | my $file =$_; | ||
724 | my $gid = (stat($file))[5]; | ||
725 | my $gname = (getgrgid($gid))[0]; | ||
726 | if ( $gname =~ /.+/ ) { | ||
727 | return 1; | ||
728 | } | ||
729 | return 0; | ||
730 | } | ||
731 | |||
732 | |||
733 | |||
734 | |||
735 | ########################################################################### | ||
736 | # &B_check_permissions($$) | ||
737 | # | ||
738 | # Checks if the given file has the given permissions or stronger, where we | ||
739 | # define stronger as "less accessible." The file argument must be fully | ||
740 | # qualified, i.e. contain the absolute path. | ||
741 | # | ||
742 | # return values: | ||
743 | # 1: file has the given permissions or better | ||
744 | # 0: file does not have the given permsssions | ||
745 | # undef: file permissions cannot be determined | ||
746 | ########################################################################### | ||
747 | |||
748 | sub B_check_permissions ($$){ | ||
749 | my ($fileName, $reqdPerms) = @_; | ||
750 | my $filePerms; # actual permissions | ||
751 | |||
752 | |||
753 | if (-e $fileName) { | ||
754 | if (stat($fileName)) { | ||
755 | $filePerms = (stat($fileName))[2] & 07777; | ||
756 | } | ||
757 | else { | ||
758 | &B_log ("ERROR", "Can't stat $fileName.\n"); | ||
759 | return undef; | ||
760 | } | ||
761 | } | ||
762 | else { | ||
763 | # If the file does not exist, permissions are as good as they can get. | ||
764 | return 1; | ||
765 | } | ||
766 | |||
767 | # | ||
768 | # We can check whether the $filePerms are as strong by | ||
769 | # bitwise ANDing them with $reqdPerms and checking if the | ||
770 | # result is still equal to $filePerms. If it is, the | ||
771 | # $filePerms are strong enough. | ||
772 | # | ||
773 | if ( ($filePerms & $reqdPerms) == $filePerms ) { | ||
774 | return 1; | ||
775 | } | ||
776 | else { | ||
777 | return 0; | ||
778 | } | ||
779 | |||
780 | } | ||
781 | |||
782 | ########################################################################## | ||
783 | # B_permission_test($user, $previlege,$file) | ||
784 | # $user can be | ||
785 | # "owner" | ||
786 | # "group" | ||
787 | # "other" | ||
788 | # $previlege can be: | ||
789 | # "r" | ||
790 | # "w" | ||
791 | # "x" | ||
792 | # "suid" | ||
793 | # "sgid" | ||
794 | # "sticky" | ||
795 | # if previlege is set to suid or sgid or sticky, then $user can be empty | ||
796 | # this sub routine test whether the $user has the specified previlige to $file | ||
797 | ########################################################################## | ||
798 | |||
799 | sub B_permission_test($$$){ | ||
800 | my ($user, $previlege, $file) = @_; | ||
801 | |||
802 | if (-e $file ) { | ||
803 | my $mode = (stat($file))[2]; | ||
804 | my $bitpos; | ||
805 | # bitmap is | suid sgid sticky | rwx | rwx | rwx | ||
806 | if ($previlege =~ /suid/ ) { | ||
807 | $bitpos = 11; | ||
808 | } | ||
809 | elsif ($previlege =~ /sgid/ ) { | ||
810 | $bitpos = 10; | ||
811 | } | ||
812 | elsif ($previlege =~ /sticky/ ) { | ||
813 | $bitpos = 9; | ||
814 | } | ||
815 | else { | ||
816 | if ( $user =~ /owner/) { | ||
817 | if ($previlege =~ /r/) { | ||
818 | $bitpos = 8; | ||
819 | } | ||
820 | elsif ($previlege =~ /w/) { | ||
821 | $bitpos =7; | ||
822 | } | ||
823 | elsif ($previlege =~ /x/) { | ||
824 | $bitpos =6; | ||
825 | } | ||
826 | else { | ||
827 | return 0; | ||
828 | } | ||
829 | } | ||
830 | elsif ( $user =~ /group/) { | ||
831 | if ($previlege =~ /r/) { | ||
832 | $bitpos =5; | ||
833 | } | ||
834 | elsif ($previlege =~ /w/) { | ||
835 | $bitpos =4; | ||
836 | } | ||
837 | elsif ($previlege =~ /x/) { | ||
838 | $bitpos =3; | ||
839 | } | ||
840 | else { | ||
841 | return 0; | ||
842 | } | ||
843 | } | ||
844 | elsif ( $user =~ /other/) { | ||
845 | if ($previlege =~ /r/) { | ||
846 | $bitpos =2; | ||
847 | } | ||
848 | elsif ($previlege =~ /w/) { | ||
849 | $bitpos =1; | ||
850 | } | ||
851 | elsif ($previlege =~ /x/) { | ||
852 | $bitpos =0; | ||
853 | } | ||
854 | else { | ||
855 | return 0; | ||
856 | } | ||
857 | } | ||
858 | else { | ||
859 | return 0; | ||
860 | } | ||
861 | } | ||
862 | $mode /= 2**$bitpos; | ||
863 | if ($mode % 2) { | ||
864 | return 1; | ||
865 | } | ||
866 | return 0; | ||
867 | } | ||
868 | } | ||
869 | |||
870 | ########################################################################## | ||
871 | # this subroutine will return a list of home directory | ||
872 | ########################################################################## | ||
873 | sub B_find_homes(){ | ||
874 | # find loginable homes | ||
875 | my $logins = &getGlobal("BIN","logins"); | ||
876 | my @lines = `$logins -ox`; | ||
877 | my @homes; | ||
878 | foreach my $line (@lines) { | ||
879 | chomp $line; | ||
880 | my @data = split /:/, $line; | ||
881 | if ($data[7] =~ /PS/ && $data[5] =~ /home/) { | ||
882 | push @homes, $data[5]; | ||
883 | } | ||
884 | } | ||
885 | return @homes; | ||
886 | } | ||
887 | |||
888 | |||
889 | ########################################################################### | ||
890 | # B_is_executable($) | ||
891 | # | ||
892 | # This routine reports on whether a file is executable by the current | ||
893 | # process' effective UID. | ||
894 | # | ||
895 | # scalar return values: | ||
896 | # 0: file is not executable | ||
897 | # 1: file is executable | ||
898 | # | ||
899 | ########################################################################### | ||
900 | |||
901 | sub B_is_executable($) | ||
902 | { | ||
903 | my $name = shift; | ||
904 | my $executable = 0; | ||
905 | |||
906 | if (-x $name) { | ||
907 | $executable = 1; | ||
908 | } | ||
909 | return $executable; | ||
910 | } | ||
911 | |||
912 | ########################################################################### | ||
913 | # B_is_suid($) | ||
914 | # | ||
915 | # This routine reports on whether a file is Set-UID and owned by root. | ||
916 | # | ||
917 | # scalar return values: | ||
918 | # 0: file is not SUID root | ||
919 | # 1: file is SUID root | ||
920 | # | ||
921 | ########################################################################### | ||
922 | |||
923 | sub B_is_suid($) | ||
924 | { | ||
925 | my $name = shift; | ||
926 | |||
927 | my @FileStatus = stat($name); | ||
928 | my $IsSuid = 0; | ||
929 | |||
930 | if (-u $name) #Checks existence and suid | ||
931 | { | ||
932 | if($FileStatus[4] == 0) { | ||
933 | $IsSuid = 1; | ||
934 | } | ||
935 | } | ||
936 | |||
937 | return $IsSuid; | ||
938 | } | ||
939 | |||
940 | ########################################################################### | ||
941 | # B_is_sgid($) | ||
942 | # | ||
943 | # This routine reports on whether a file is SGID and group owned by | ||
944 | # group root (gid 0). | ||
945 | # | ||
946 | # scalar return values: | ||
947 | # 0: file is not SGID root | ||
948 | # 1: file is SGID root | ||
949 | # | ||
950 | ########################################################################### | ||
951 | |||
952 | sub B_is_sgid($) | ||
953 | { | ||
954 | my $name = shift; | ||
955 | |||
956 | my @FileStatus = stat($name); | ||
957 | my $IsSgid = 0; | ||
958 | |||
959 | if (-g $name) #checks existence and sgid | ||
960 | { | ||
961 | if($FileStatus[5] == 0) { | ||
962 | $IsSgid = 1; | ||
963 | } | ||
964 | } | ||
965 | |||
966 | return $IsSgid; | ||
967 | } | ||
968 | |||
969 | ########################################################################### | ||
970 | # B_get_user_list() | ||
971 | # | ||
972 | # This routine outputs a list of users on the system. | ||
973 | # | ||
974 | ########################################################################### | ||
975 | |||
976 | sub B_get_user_list() | ||
977 | { | ||
978 | my @users; | ||
979 | open(PASSWD,&getGlobal('FILE','passwd')); | ||
980 | while(<PASSWD>) { | ||
981 | #Get the users | ||
982 | if (/^([^:]+):/) | ||
983 | { | ||
984 | push (@users,$1); | ||
985 | } | ||
986 | } | ||
987 | return @users; | ||
988 | } | ||
989 | |||
990 | ########################################################################### | ||
991 | # B_get_group_list() | ||
992 | # | ||
993 | # This routine outputs a list of groups on the system. | ||
994 | # | ||
995 | ########################################################################### | ||
996 | |||
997 | sub B_get_group_list() | ||
998 | { | ||
999 | my @groups; | ||
1000 | open(GROUP,&getGlobal('FILE','group')); | ||
1001 | while(my $group_line = <GROUP>) { | ||
1002 | #Get the groups | ||
1003 | if ($group_line =~ /^([^:]+):/) | ||
1004 | { | ||
1005 | push (@groups,$1); | ||
1006 | } | ||
1007 | } | ||
1008 | return @groups; | ||
1009 | } | ||
1010 | |||
1011 | |||
1012 | ########################################################################### | ||
1013 | # &B_remove_suid ($file) removes the suid bit from $file if it | ||
1014 | # is set and the file exist. If you would like to remove the suid bit | ||
1015 | # from /bin/ping then you need to use: | ||
1016 | # | ||
1017 | # &B_remove_suid("/bin/ping"); | ||
1018 | # | ||
1019 | # &B_remove_suid respects GLOBAL_LOGONLY. | ||
1020 | # &B_remove_suid uses &B_chmod to make the permission changes | ||
1021 | # &B_remove_suid allows for globbing. tyler_e | ||
1022 | # | ||
1023 | ########################################################################### | ||
1024 | |||
1025 | sub B:remove_suid($) { | ||
1026 | my $file_expr = $_[0]; | ||
1027 | |||
1028 | &B_log("ACTION","Removing SUID bit from \"$file_expr\"."); | ||
1029 | unless ($GLOBAL_LOGONLY) { | ||
1030 | my @files = glob($file_expr); | ||
1031 | |||
1032 | foreach my $file (@files) { | ||
1033 | # check file existence | ||
1034 | if(-e $file){ | ||
1035 | # stat current file to get raw permissions | ||
1036 | my $old_perm_raw = (stat $file)[2]; | ||
1037 | # test to see if suidbit is set | ||
1038 | my $suid_bit = (($old_perm_raw/2048) % 2); | ||
1039 | if($suid_bit == 1){ | ||
1040 | # new permission without the suid bit | ||
1041 | my $new_perm = ((($old_perm_raw/512) % 8 ) - 4) . | ||
1042 | (($old_perm_raw/64) % 8 ) . | ||
1043 | (($old_perm_raw/8) % 8 ) . | ||
1044 | (($old_perm_raw) % 8 ); | ||
1045 | if(&B_chmod(oct($new_perm), $file)){ | ||
1046 | &B_log("ACTION","Removed SUID bit from \"$file\"."); | ||
1047 | } | ||
1048 | else { | ||
1049 | &B_log("ERROR","Could not remove SUID bit from \"$file\"."); | ||
1050 | } | ||
1051 | } # No action if SUID bit is not set | ||
1052 | }# No action if file does not exist | ||
1053 | }# Repeat for each file in the file glob | ||
1054 | } # unless Global_log | ||
1055 | } | ||
1056 | |||
1057 | |||
1058 | |||
1059 | 1; | ||
1060 | |||
diff --git a/dynamic-layers/meta-perl/recipes-security/bastille/files/FileContent.pm b/dynamic-layers/meta-perl/recipes-security/bastille/files/FileContent.pm new file mode 100644 index 0000000..1ef89dd --- /dev/null +++ b/dynamic-layers/meta-perl/recipes-security/bastille/files/FileContent.pm | |||
@@ -0,0 +1,1153 @@ | |||
1 | package Bastille::API::FileContent; | ||
2 | use strict; | ||
3 | |||
4 | use Bastille::API; | ||
5 | |||
6 | require Exporter; | ||
7 | our @ISA = qw(Exporter); | ||
8 | our @EXPORT_OK = qw( | ||
9 | B_blank_file | ||
10 | B_insert_line_after | ||
11 | B_insert_line_before | ||
12 | B_insert_line | ||
13 | B:append_line | ||
14 | B:prepend_line | ||
15 | B_replace_line | ||
16 | B_replace_lines | ||
17 | B_replace_pattern | ||
18 | B_match_line | ||
19 | B_match_line_only | ||
20 | B_match_chunk | ||
21 | B_return_matched_lines | ||
22 | B_hash_comment_line | ||
23 | B_hash_uncomment_line | ||
24 | B_delete_line | ||
25 | B_chunk_replace | ||
26 | B_print | ||
27 | B_getValueFromFile | ||
28 | B_getValueFromString | ||
29 | |||
30 | B_TODO | ||
31 | B_TODOFlags | ||
32 | ); | ||
33 | our @EXPORT = @EXPORT_OK; | ||
34 | |||
35 | |||
36 | |||
37 | ########################################################################### | ||
38 | # &B_blank_file ($filename,$pattern) blanks the file $filename, unless the | ||
39 | # pattern $pattern is present in the file. This lets us completely redo | ||
40 | # a file, if it isn't the one we put in place on a previous run... | ||
41 | # | ||
42 | # B_blank_file respects $GLOBAL_LOGONLY and uses B_open_plus and B_close_plus | ||
43 | # so that it makes backups and only modifies files when we're not in "-v" | ||
44 | # mode... | ||
45 | # | ||
46 | # If the file does not exist, the function does nothing, and gives an error | ||
47 | # to the Error Log | ||
48 | # | ||
49 | ########################################################################### | ||
50 | |||
51 | sub B_blank_file($$) { | ||
52 | |||
53 | my ($filename,$pattern) = @_; | ||
54 | my $retval; | ||
55 | |||
56 | # If this variable is true, we won't blank the file... | ||
57 | |||
58 | my $found_pattern=0; | ||
59 | |||
60 | if ($retval=&B_open_plus (*BLANK_NEW,*BLANK_OLD,$filename) ) { | ||
61 | |||
62 | my @lines; | ||
63 | |||
64 | while (my $line = <BLANK_OLD>) { | ||
65 | |||
66 | push @lines,$line; | ||
67 | if ($line =~ $pattern) { | ||
68 | $found_pattern=1; | ||
69 | } | ||
70 | } | ||
71 | |||
72 | # Only copy the old file if the new one didn't match. | ||
73 | if ($found_pattern) { | ||
74 | while ( my $line = shift @lines ) { | ||
75 | &B_print(*BLANK_NEW,$line); | ||
76 | } | ||
77 | } | ||
78 | else { | ||
79 | &B_log("ACTION","Blanked file $filename\n"); | ||
80 | } | ||
81 | &B_close_plus(*BLANK_NEW,*BLANK_OLD,$filename); | ||
82 | } | ||
83 | else { | ||
84 | &B_log("ERROR","Couldn't blank file $filename since we couldn't open it or its replacement\n"); | ||
85 | } | ||
86 | |||
87 | return $retval; | ||
88 | |||
89 | } | ||
90 | |||
91 | ########################################################################### | ||
92 | # &B_insert_line_after ($filename,$pattern,$line_to_insert,$line_to_follow) | ||
93 | # modifies $filename, inserting $line_to_insert unless one or more lines | ||
94 | # in the file matches $pattern. The $line_to_insert will be placed | ||
95 | # immediately after $line_to_follow, if it exists. If said line does not | ||
96 | # exist, the line will not be inserted and this routine will return 0. | ||
97 | # | ||
98 | # B_insert_line uses B_open_plus and B_close_plus, so that the file | ||
99 | # modified is backed up... | ||
100 | # | ||
101 | # Here's examples of where you might use this: | ||
102 | # | ||
103 | # You'd like to insert a line in Apache's configuration file, in a | ||
104 | # particular section. | ||
105 | # | ||
106 | ########################################################################### | ||
107 | |||
108 | sub B_insert_line_after($$$$) { | ||
109 | |||
110 | my ($filename,$pattern,$line_to_insert,$line_to_follow) = @_; | ||
111 | |||
112 | my @lines; | ||
113 | my $found_pattern=0; | ||
114 | my $found_line_to_follow=0; | ||
115 | |||
116 | my $retval=1; | ||
117 | |||
118 | if ( &B_open_plus (*INSERT_NEW,*INSERT_OLD,$filename) ) { | ||
119 | |||
120 | # Read through the file looking for a match both on the $pattern | ||
121 | # and the line we are supposed to be inserting after... | ||
122 | |||
123 | my $ctr=1; | ||
124 | while (my $line=<INSERT_OLD>) { | ||
125 | push (@lines,$line); | ||
126 | if ($line =~ $pattern) { | ||
127 | $found_pattern=1; | ||
128 | } | ||
129 | if ( ($found_line_to_follow < 1) and ($line =~ $line_to_follow)) { | ||
130 | $found_line_to_follow=$ctr; | ||
131 | } | ||
132 | $ctr++; | ||
133 | } | ||
134 | |||
135 | # Log an error if we never found the line we were to insert after | ||
136 | unless ($found_line_to_follow ) { | ||
137 | $retval=0; | ||
138 | &B_log("ERROR","Never found the line that we were supposed to insert after in $filename\n"); | ||
139 | } | ||
140 | |||
141 | # Now print the file back out, inserting our line if we should... | ||
142 | |||
143 | $ctr=1; | ||
144 | while (my $line = shift @lines) { | ||
145 | &B_print(*INSERT_NEW,$line); | ||
146 | if ( ($ctr == $found_line_to_follow) and ($found_pattern == 0) ) { | ||
147 | &B_print(*INSERT_NEW,$line_to_insert); | ||
148 | &B_log("ACTION","Inserted the following line in $filename:\n"); | ||
149 | &B_log("ACTION","$line_to_insert"); | ||
150 | } | ||
151 | $ctr++; | ||
152 | } | ||
153 | |||
154 | &B_close_plus (*INSERT_NEW,*INSERT_OLD,$filename); | ||
155 | |||
156 | } | ||
157 | else { | ||
158 | $retval=0; | ||
159 | &B_log("ERROR","Couldn't insert line to $filename, since open failed."); | ||
160 | } | ||
161 | |||
162 | return $retval; | ||
163 | |||
164 | } | ||
165 | ########################################################################### | ||
166 | # &B_insert_line_before ($filename,$pattern,$line_to_insert,$line_to_preceed) | ||
167 | # modifies $filename, inserting $line_to_insert unless one or more lines | ||
168 | # in the file matches $pattern. The $line_to_insert will be placed | ||
169 | # immediately before $line_to_preceed, if it exists. If said line does not | ||
170 | # exist, the line will not be inserted and this routine will return 0. | ||
171 | # | ||
172 | # B_insert_line uses B_open_plus and B_close_plus, so that the file | ||
173 | # modified is backed up... | ||
174 | # | ||
175 | # Here's examples of where you might use this: | ||
176 | # | ||
177 | # You'd like to insert a line in Apache's configuration file, in a | ||
178 | # particular section. | ||
179 | # | ||
180 | ########################################################################### | ||
181 | |||
182 | sub B_insert_line_before($$$$) { | ||
183 | |||
184 | my ($filename,$pattern,$line_to_insert,$line_to_preceed) = @_; | ||
185 | |||
186 | my @lines; | ||
187 | my $found_pattern=0; | ||
188 | my $found_line_to_preceed=0; | ||
189 | |||
190 | my $retval=1; | ||
191 | |||
192 | if ( &B_open_plus (*INSERT_NEW,*INSERT_OLD,$filename) ) { | ||
193 | |||
194 | # Read through the file looking for a match both on the $pattern | ||
195 | # and the line we are supposed to be inserting after... | ||
196 | |||
197 | my $ctr=1; | ||
198 | while (my $line=<INSERT_OLD>) { | ||
199 | push (@lines,$line); | ||
200 | if ($line =~ $pattern) { | ||
201 | $found_pattern=1; | ||
202 | } | ||
203 | if ( ($found_line_to_preceed < 1) and ($line =~ $line_to_preceed)) { | ||
204 | $found_line_to_preceed=$ctr; | ||
205 | } | ||
206 | $ctr++; | ||
207 | } | ||
208 | |||
209 | # Log an error if we never found the line we were to preceed | ||
210 | unless ($found_line_to_preceed ) { | ||
211 | $retval=0; | ||
212 | &B_log("ERROR","Never found the line that we were supposed to insert before in $filename\n"); | ||
213 | } | ||
214 | |||
215 | # Now print the file back out, inserting our line if we should... | ||
216 | |||
217 | $ctr=1; | ||
218 | while (my $line = shift @lines) { | ||
219 | if ( ($ctr == $found_line_to_preceed) and ($found_pattern == 0) ) { | ||
220 | &B_print(*INSERT_NEW,$line_to_insert); | ||
221 | &B_log("ACTION","Inserted the following line in $filename:\n"); | ||
222 | &B_log("ACTION","$line_to_insert"); | ||
223 | } | ||
224 | &B_print(*INSERT_NEW,$line); | ||
225 | $ctr++; | ||
226 | } | ||
227 | |||
228 | &B_close_plus (*INSERT_NEW,*INSERT_OLD,$filename); | ||
229 | |||
230 | } | ||
231 | else { | ||
232 | $retval=0; | ||
233 | &B_log("ERROR","Couldn't insert line to $filename, since open failed."); | ||
234 | } | ||
235 | |||
236 | return $retval; | ||
237 | |||
238 | } | ||
239 | |||
240 | ########################################################################### | ||
241 | # &B_insert_line ($filename,$pattern,$line_to_insert,$line_to_follow) | ||
242 | # | ||
243 | # has been renamed to B_insert_line_after() | ||
244 | # | ||
245 | # This name will continue to work, as a shim for code that has not been | ||
246 | # transitioned. | ||
247 | ########################################################################### | ||
248 | |||
249 | sub B_insert_line($$$$) { | ||
250 | |||
251 | my $rtn_value = &B_insert_line_after(@_); | ||
252 | |||
253 | return ($rtn_value); | ||
254 | } | ||
255 | |||
256 | |||
257 | ########################################################################### | ||
258 | # &B_append_line ($filename,$pattern,$line_to_append) modifies $filename, | ||
259 | # appending $line_to_append unless one or more lines in the file matches | ||
260 | # $pattern. This is an enhancement to the append_line_if_no_such_line_exists | ||
261 | # idea. | ||
262 | # | ||
263 | # Additionally, if $pattern is set equal to "", the line is always appended. | ||
264 | # | ||
265 | # B:append_line uses B_open_plus and B_close_plus, so that the file | ||
266 | # modified is backed up... | ||
267 | # | ||
268 | # Here's examples of where you might use this: | ||
269 | # | ||
270 | # You'd like to add a root line to /etc/ftpusers if none exists. | ||
271 | # You'd like to add a Options Indexes line to Apache's config. file, | ||
272 | # after you delete all Options lines from said config file. | ||
273 | # | ||
274 | ########################################################################### | ||
275 | |||
276 | sub B:append_line($$$) { | ||
277 | |||
278 | my ($filename,$pattern,$line_to_append) = @_; | ||
279 | |||
280 | my $found_pattern=0; | ||
281 | my $retval=1; | ||
282 | |||
283 | if ( &B_open_plus (*APPEND_NEW,*APPEND_OLD,$filename) ) { | ||
284 | while (my $line=<APPEND_OLD>) { | ||
285 | &B_print(*APPEND_NEW,$line); | ||
286 | if ($line =~ $pattern) { | ||
287 | $found_pattern=1; | ||
288 | } | ||
289 | } | ||
290 | # Changed != 0 to $pattern so that "" works instead of 0 and perl | ||
291 | # does not give the annoying | ||
292 | # Argument "XX" isn't numeric in ne at ... | ||
293 | if ( $pattern eq "" or ! $found_pattern ) { | ||
294 | &B_print(*APPEND_NEW,$line_to_append); | ||
295 | &B_log("ACTION","Appended the following line to $filename:\n"); | ||
296 | &B_log("ACTION","$line_to_append"); | ||
297 | } | ||
298 | &B_close_plus (*APPEND_NEW,*APPEND_OLD,$filename); | ||
299 | } | ||
300 | else { | ||
301 | $retval=0; | ||
302 | &B_log("ERROR","# Couldn't append line to $filename, since open failed."); | ||
303 | } | ||
304 | |||
305 | return $retval; | ||
306 | |||
307 | } | ||
308 | |||
309 | ########################################################################### | ||
310 | # &B_prepend_line ($filename,$pattern,$line_to_prepend) modifies $filename, | ||
311 | # pre-pending $line_to:prepend unless one or more lines in the file matches | ||
312 | # $pattern. This is an enhancement to the prepend_line_if_no_such_line_exists | ||
313 | # idea. | ||
314 | # | ||
315 | # B:prepend_line uses B_open_plus and B_close_plus, so that the file | ||
316 | # modified is backed up... | ||
317 | # | ||
318 | # Here's examples of where you might use this: | ||
319 | # | ||
320 | # You'd like to insert the line "auth required pam_deny.so" to the top | ||
321 | # of the PAM stack file /etc/pam.d/rsh to totally deactivate rsh. | ||
322 | # | ||
323 | ########################################################################### | ||
324 | |||
325 | sub B:prepend_line($$$) { | ||
326 | |||
327 | my ($filename,$pattern,$line_to_prepend) = @_; | ||
328 | |||
329 | my @lines; | ||
330 | my $found_pattern=0; | ||
331 | my $retval=1; | ||
332 | |||
333 | if ( &B_open_plus (*PREPEND_NEW,*PREPEND_OLD,$filename) ) { | ||
334 | while (my $line=<PREPEND_OLD>) { | ||
335 | push (@lines,$line); | ||
336 | if ($line =~ $pattern) { | ||
337 | $found_pattern=1; | ||
338 | } | ||
339 | } | ||
340 | unless ($found_pattern) { | ||
341 | &B_print(*PREPEND_NEW,$line_to_prepend); | ||
342 | } | ||
343 | while (my $line = shift @lines) { | ||
344 | &B_print(*PREPEND_NEW,$line); | ||
345 | } | ||
346 | |||
347 | &B_close_plus (*PREPEND_NEW,*PREPEND_OLD,$filename); | ||
348 | |||
349 | # Log the action | ||
350 | &B_log("ACTION","Pre-pended the following line to $filename:\n"); | ||
351 | &B_log("ACTION","$line_to:prepend"); | ||
352 | } | ||
353 | else { | ||
354 | $retval=0; | ||
355 | &B_log("ERROR","Couldn't prepend line to $filename, since open failed.\n"); | ||
356 | } | ||
357 | |||
358 | return $retval; | ||
359 | |||
360 | } | ||
361 | |||
362 | |||
363 | ########################################################################### | ||
364 | # &B_replace_line ($filename,$pattern,$line_to_switch_in) modifies $filename, | ||
365 | # replacing any lines matching $pattern with $line_to_switch_in. | ||
366 | # | ||
367 | # It returns the number of lines it replaced (or would have replaced, if | ||
368 | # LOGONLY mode wasn't on...) | ||
369 | # | ||
370 | # B_replace_line uses B_open_plus and B_close_plus, so that the file | ||
371 | # modified is backed up... | ||
372 | # | ||
373 | # Here an example of where you might use this: | ||
374 | # | ||
375 | # You'd like to replace any Options lines in Apache's config file with: | ||
376 | # Options Indexes FollowSymLinks | ||
377 | # | ||
378 | ########################################################################### | ||
379 | |||
380 | sub B_replace_line($$$) { | ||
381 | |||
382 | my ($filename,$pattern,$line_to_switch_in) = @_; | ||
383 | my $retval=0; | ||
384 | |||
385 | if ( &B_open_plus (*REPLACE_NEW,*REPLACE_OLD,$filename) ) { | ||
386 | while (my $line=<REPLACE_OLD>) { | ||
387 | unless ($line =~ $pattern) { | ||
388 | &B_print(*REPLACE_NEW,$line); | ||
389 | } | ||
390 | else { | ||
391 | # Don't replace the line if it's already there. | ||
392 | unless ($line eq $line_to_switch_in) { | ||
393 | &B_print(*REPLACE_NEW,$line_to_switch_in); | ||
394 | |||
395 | $retval++; | ||
396 | &B_log("ACTION","File modification in $filename -- replaced line\n" . | ||
397 | "$line\n" . | ||
398 | "with:\n" . | ||
399 | "$line_to_switch_in"); | ||
400 | } | ||
401 | # But if it is there, make sure it stays there! (by Paul Allen) | ||
402 | else { | ||
403 | &B_print(*REPLACE_NEW,$line); | ||
404 | } | ||
405 | } | ||
406 | } | ||
407 | &B_close_plus (*REPLACE_NEW,*REPLACE_OLD,$filename); | ||
408 | } | ||
409 | else { | ||
410 | $retval=0; | ||
411 | &B_log("ERROR","Couldn't replace line(s) in $filename because open failed.\n"); | ||
412 | } | ||
413 | |||
414 | return $retval; | ||
415 | } | ||
416 | |||
417 | ########################################################################### | ||
418 | # &B_replace_lines ($filename,$patterns_and_substitutes) modifies $filename, | ||
419 | # replacing the line matching the nth $pattern specified in $patterns_and_substitutes->[n]->[0] | ||
420 | # with the corresponding substitutes in $patterns_and_substitutes->[n]->-[1] | ||
421 | # | ||
422 | # It returns the number of lines it replaced (or would have replaced, if | ||
423 | # LOGONLY mode wasn't on...) | ||
424 | # | ||
425 | # B_replace_lines uses B_open_plus and B_close_plus, so that the file | ||
426 | # modified is backed up... | ||
427 | # | ||
428 | # Here an example of where you might use this: | ||
429 | # | ||
430 | # You'd like to replace /etc/opt/ssh/sshd_config file | ||
431 | # (^#|^)Protocol\s+(.*)\s*$ ==> Protocol 2 | ||
432 | # (^#|^)X11Forwarding\s+(.*)\s*$ ==> X11Forwarding yes | ||
433 | # (^#|^)IgnoreRhosts\s+(.*)\s*$ ==> gnoreRhosts yes | ||
434 | # (^#|^)RhostsAuthentication\s+(.*)\s*$ ==> RhostsAuthentication no | ||
435 | # (^#|^)RhostsRSAAuthentication\s+(.*)\s*$ ==> RhostsRSAAuthentication no | ||
436 | # (^#|^)PermitRootLogin\s+(.*)\s*$ ==> PermitRootLogin no | ||
437 | # (^#|^)PermitEmptyPasswords\s+(.*)\s*$ ==> PermitEmptyPasswords no | ||
438 | # my $patterns_and_substitutes = [ | ||
439 | # [ '(^#|^)Protocol\s+(.*)\s*$' => 'Protocol 2'], | ||
440 | # ['(^#|^)X11Forwarding\s+(.*)\s*$' => 'X11Forwarding yes'], | ||
441 | # ['(^#|^)IgnoreRhosts\s+(.*)\s*$' => 'gnoreRhosts yes'], | ||
442 | # ['(^#|^)RhostsAuthentication\s+(.*)\s*$' => 'RhostsAuthentication no'], | ||
443 | # ['(^#|^)RhostsRSAAuthentication\s+(.*)\s*$' => 'RhostsRSAAuthentication no'], | ||
444 | # ['(^#|^)PermitRootLogin\s+(.*)\s*$' => 'PermitRootLogin no'], | ||
445 | # ['(^#|^)PermitEmptyPasswords\s+(.*)\s*$' => 'PermitEmptyPasswords no'] | ||
446 | #] | ||
447 | # B_replaces_lines($sshd_config,$patterns_and_substitutes); | ||
448 | ########################################################################### | ||
449 | |||
450 | sub B_replace_lines($$){ | ||
451 | my ($filename, $pairs) = @_; | ||
452 | my $retval = 0; | ||
453 | if ( &B_open_plus (*REPLACE_NEW,*REPLACE_OLD,$filename) ) { | ||
454 | while (my $line = <REPLACE_OLD>) { | ||
455 | my $switch; | ||
456 | my $switch_before = $line; | ||
457 | chomp($line); | ||
458 | foreach my $pair (@$pairs) { | ||
459 | $switch = 0; | ||
460 | |||
461 | my $pattern = $pair->[0] ; | ||
462 | my $replace = $pair->[1]; | ||
463 | my $evalstr = '$line' . "=~ s/$pattern/$replace/"; | ||
464 | eval $evalstr; | ||
465 | if ($@) { | ||
466 | &B_log("ERROR", "eval $evalstr failed.\n"); | ||
467 | } | ||
468 | #if ( $line =~ s/$pair->[0]/$pair->[1]/) { | ||
469 | # $switch = 1; | ||
470 | # last; | ||
471 | #} | ||
472 | } | ||
473 | &B_print(*REPLACE_NEW,"$line\n"); | ||
474 | if ($switch) { | ||
475 | $retval++; | ||
476 | B_log("ACTION","File modification in $filename -- replaced line\n" . | ||
477 | "$switch_before\n" . | ||
478 | "with:\n" . | ||
479 | "$line\n"); | ||
480 | } | ||
481 | } | ||
482 | &B_close_plus (*REPLACE_NEW,*REPLACE_OLD,$filename); | ||
483 | return 1; | ||
484 | } | ||
485 | else { | ||
486 | $retval=0; | ||
487 | &B_log("ERROR","Couldn't replace line(s) in $filename because open failed.\n"); | ||
488 | } | ||
489 | } | ||
490 | |||
491 | ################################################################################################ | ||
492 | # &B_replace_pattern ($filename,$pattern,$pattern_to_remove,$text_to_switch_in) | ||
493 | # modifies $filename, acting on only lines that match $pattern, replacing a | ||
494 | # string that matches $pattern_to_remove with $text_to_switch_in. | ||
495 | # | ||
496 | # Ex: | ||
497 | # B_replace_pattern('/etc/httpd.conf','^\s*Options.*\bIncludes\b','Includes','IncludesNoExec') | ||
498 | # | ||
499 | # replaces all "Includes" with "IncludesNoExec" on Apache Options lines. | ||
500 | # | ||
501 | # It returns the number of lines it altered (or would have replaced, if | ||
502 | # LOGONLY mode wasn't on...) | ||
503 | # | ||
504 | # B_replace_pattern uses B_open_plus and B_close_plus, so that the file | ||
505 | # modified is backed up... | ||
506 | # | ||
507 | ################################################################################################# | ||
508 | |||
509 | sub B_replace_pattern($$$$) { | ||
510 | |||
511 | my ($filename,$pattern,$pattern_to_remove,$text_to_switch_in) = @_; | ||
512 | my $retval=0; | ||
513 | |||
514 | if ( &B_open_plus (*REPLACE_NEW,*REPLACE_OLD,$filename) ) { | ||
515 | while (my $line=<REPLACE_OLD>) { | ||
516 | unless ($line =~ $pattern) { | ||
517 | &B_print(*REPLACE_NEW,$line); | ||
518 | } | ||
519 | else { | ||
520 | my $orig_line =$line; | ||
521 | $line =~ s/$pattern_to_remove/$text_to_switch_in/; | ||
522 | |||
523 | &B_print(*REPLACE_NEW,$line); | ||
524 | |||
525 | $retval++; | ||
526 | &B_log("ACTION","File modification in $filename -- replaced line\n" . | ||
527 | "$orig_line\n" . | ||
528 | "via pattern with:\n" . | ||
529 | "$line\n\n"); | ||
530 | } | ||
531 | } | ||
532 | &B_close_plus (*REPLACE_NEW,*REPLACE_OLD,$filename); | ||
533 | } | ||
534 | else { | ||
535 | $retval=0; | ||
536 | &B_log("ERROR","Couldn't pattern-replace line(s) in $filename because open failed.\n"); | ||
537 | } | ||
538 | |||
539 | return $retval; | ||
540 | } | ||
541 | |||
542 | |||
543 | ########################################################################### | ||
544 | # &B_match_line($file,$pattern); | ||
545 | # | ||
546 | # This subroutine will return a 1 if the pattern specified can be matched | ||
547 | # against the file specified. It will return a 0 otherwise. | ||
548 | # | ||
549 | # return values: | ||
550 | # 0: pattern not in file or the file is not readable | ||
551 | # 1: pattern is in file | ||
552 | ########################################################################### | ||
553 | sub B_match_line($$) { | ||
554 | # file to be checked and pattern to check for. | ||
555 | my ($file,$pattern) = @_; | ||
556 | # if the file is readable then | ||
557 | if(-r $file) { | ||
558 | # if the file can be opened then | ||
559 | if(open FILE,"<$file") { | ||
560 | # look at each line in the file | ||
561 | while (my $line = <FILE>) { | ||
562 | # if a line matches the pattern provided then | ||
563 | if($line =~ $pattern) { | ||
564 | # return the pattern was found | ||
565 | B_log('DEBUG','Pattern: ' . $pattern . ' matched in file: ' . | ||
566 | $file . "\n"); | ||
567 | return 1; | ||
568 | } | ||
569 | } | ||
570 | } | ||
571 | # if the file cann't be opened then | ||
572 | else { | ||
573 | # send a note to that affect to the errorlog | ||
574 | &B_log("ERROR","Unable to open file for read.\n$file\n$!\n"); | ||
575 | } | ||
576 | } | ||
577 | B_log('DEBUG','Pattern: ' . $pattern . ' not matched in file: ' . | ||
578 | $file . "\n"); | ||
579 | # the provided pattern was not matched against a line in the file | ||
580 | return 0; | ||
581 | } | ||
582 | |||
583 | ########################################################################### | ||
584 | # &B_match_line_only($file,$pattern); | ||
585 | # | ||
586 | # This subroutine checks if the specified pattern can be matched and if | ||
587 | # it's the only content in the file. The only content means it's only but | ||
588 | # may have several copies in the file. | ||
589 | # | ||
590 | # return values: | ||
591 | # 0: pattern not in file or pattern is not the only content | ||
592 | # or the file is not readable | ||
593 | # 1: pattern is in file and it's the only content | ||
594 | ############################################################################ | ||
595 | sub B_match_line_only($$) { | ||
596 | my ($file,$pattern) = @_; | ||
597 | |||
598 | # if matched, set to 1 later | ||
599 | my $retval = 0; | ||
600 | |||
601 | # if the file is readable then | ||
602 | if(-r $file) { | ||
603 | # if the file can be opened then | ||
604 | if(&B_open(*FILED, $file)) { | ||
605 | # pattern should be matched at least once | ||
606 | # pattern can not be mismatched | ||
607 | while (my $line = <FILED>) { | ||
608 | if ($line =~ $pattern) { | ||
609 | $retval = 1; | ||
610 | } | ||
611 | else { | ||
612 | &B_close(*FILED); | ||
613 | return 0; | ||
614 | } | ||
615 | } | ||
616 | } | ||
617 | &B_close(*FILED); | ||
618 | } | ||
619 | |||
620 | return $retval; | ||
621 | } | ||
622 | |||
623 | ########################################################################### | ||
624 | # &B_return_matched_lines($file,$pattern); | ||
625 | # | ||
626 | # This subroutine returns lines in a file matching a given regular | ||
627 | # expression, when called in the default list mode. When called in scalar | ||
628 | # mode, returns the number of elements found. | ||
629 | ########################################################################### | ||
630 | sub B_return_matched_lines($$) | ||
631 | { | ||
632 | my ($filename,$pattern) = @_; | ||
633 | my @lines = (); | ||
634 | |||
635 | open(READFILE, $filename); | ||
636 | while (<READFILE>) { | ||
637 | chomp; | ||
638 | next unless /$pattern/; | ||
639 | push(@lines, $_); | ||
640 | } | ||
641 | if (wantarray) | ||
642 | { | ||
643 | return @lines; | ||
644 | } | ||
645 | else | ||
646 | { | ||
647 | return scalar (@lines); | ||
648 | } | ||
649 | } | ||
650 | |||
651 | ########################################################################### | ||
652 | # &B_match_chunk($file,$pattern); | ||
653 | # | ||
654 | # This subroutine will return a 1 if the pattern specified can be matched | ||
655 | # against the file specified on a line-agnostic form. This allows for | ||
656 | # patterns which by necessity must match against a multi-line pattern. | ||
657 | # This is the natural analogue to B_replace_chunk, which was created to | ||
658 | # provide multi-line capability not provided by B_replace_line. | ||
659 | # | ||
660 | # return values: | ||
661 | # 0: pattern not in file or the file is not readable | ||
662 | # 1: pattern is in file | ||
663 | ########################################################################### | ||
664 | |||
665 | sub B_match_chunk($$) { | ||
666 | |||
667 | my ($file,$pattern) = @_; | ||
668 | my @lines; | ||
669 | my $big_long_line; | ||
670 | my $retval=1; | ||
671 | |||
672 | open CHUNK_FILE,$file; | ||
673 | |||
674 | # Read all lines into one scalar. | ||
675 | @lines = <CHUNK_FILE>; | ||
676 | close CHUNK_FILE; | ||
677 | |||
678 | foreach my $line ( @lines ) { | ||
679 | $big_long_line .= $line; | ||
680 | } | ||
681 | |||
682 | # Substitution routines get weird unless last line is terminated with \n | ||
683 | chomp $big_long_line; | ||
684 | $big_long_line .= "\n"; | ||
685 | |||
686 | # Exit if we don't find a match | ||
687 | unless ($big_long_line =~ $pattern) { | ||
688 | $retval = 0; | ||
689 | } | ||
690 | |||
691 | return $retval; | ||
692 | } | ||
693 | |||
694 | ########################################################################### | ||
695 | # &B_hash_comment_line ($filename,$pattern) modifies $filename, replacing | ||
696 | # any lines matching $pattern with a "hash-commented" version, like this: | ||
697 | # | ||
698 | # | ||
699 | # finger stream tcp nowait nobody /usr/sbin/tcpd in.fingerd | ||
700 | # becomes: | ||
701 | # #finger stream tcp nowait nobody /usr/sbin/tcpd in.fingerd | ||
702 | # | ||
703 | # Also: | ||
704 | # tftp dgram udp wait root /usr/lbin/tftpd tftpd\ | ||
705 | # /opt/ignite\ | ||
706 | # /var/opt/ignite | ||
707 | # becomes: | ||
708 | # #tftp dgram udp wait root /usr/lbin/tftpd tftpd\ | ||
709 | # # /opt/ignite\ | ||
710 | # # /var/opt/ignite | ||
711 | # | ||
712 | # | ||
713 | # B_hash_comment_line uses B_open_plus and B_close_plus, so that the file | ||
714 | # modified is backed up... | ||
715 | # | ||
716 | ########################################################################### | ||
717 | |||
718 | sub B_hash_comment_line($$) { | ||
719 | |||
720 | my ($filename,$pattern) = @_; | ||
721 | my $retval=1; | ||
722 | |||
723 | if ( &B_open_plus (*HASH_NEW,*HASH_OLD,$filename) ) { | ||
724 | my $line; | ||
725 | while ($line=<HASH_OLD>) { | ||
726 | unless ( ($line =~ $pattern) and ($line !~ /^\s*\#/) ) { | ||
727 | &B_print(*HASH_NEW,$line); | ||
728 | } | ||
729 | else { | ||
730 | &B_print(*HASH_NEW,"#$line"); | ||
731 | &B_log("ACTION","File modification in $filename -- hash commented line\n" . | ||
732 | "$line\n" . | ||
733 | "like this:\n" . | ||
734 | "#$line\n\n"); | ||
735 | # while the line has a trailing \ then we should also comment out the line below | ||
736 | while($line =~ m/\\\n$/) { | ||
737 | if($line=<HASH_OLD>) { | ||
738 | &B_print(*HASH_NEW,"#$line"); | ||
739 | &B_log("ACTION","File modification in $filename -- hash commented line\n" . | ||
740 | "$line\n" . | ||
741 | "like this:\n" . | ||
742 | "#$line\n\n"); | ||
743 | } | ||
744 | else { | ||
745 | $line = ""; | ||
746 | } | ||
747 | } | ||
748 | |||
749 | } | ||
750 | } | ||
751 | &B_close_plus (*HASH_NEW,*HASH_OLD,$filename); | ||
752 | } | ||
753 | else { | ||
754 | $retval=0; | ||
755 | &B_log("ERROR","Couldn't hash-comment line(s) in $filename because open failed.\n"); | ||
756 | } | ||
757 | |||
758 | return $retval; | ||
759 | } | ||
760 | |||
761 | |||
762 | ########################################################################### | ||
763 | # &B_hash_uncomment_line ($filename,$pattern) modifies $filename, | ||
764 | # removing any commenting from lines that match $pattern. | ||
765 | # | ||
766 | # #finger stream tcp nowait nobody /usr/sbin/tcpd in.fingerd | ||
767 | # becomes: | ||
768 | # finger stream tcp nowait nobody /usr/sbin/tcpd in.fingerd | ||
769 | # | ||
770 | # | ||
771 | # B_hash_uncomment_line uses B_open_plus and B_close_plus, so that the file | ||
772 | # modified is backed up... | ||
773 | # | ||
774 | ########################################################################### | ||
775 | |||
776 | sub B_hash_uncomment_line($$) { | ||
777 | |||
778 | my ($filename,$pattern) = @_; | ||
779 | my $retval=1; | ||
780 | |||
781 | if ( &B_open_plus (*HASH_NEW,*HASH_OLD,$filename) ) { | ||
782 | my $line; | ||
783 | while ($line=<HASH_OLD>) { | ||
784 | unless ( ($line =~ $pattern) and ($line =~ /^\s*\#/) ) { | ||
785 | &B_print(*HASH_NEW,$line); | ||
786 | } | ||
787 | else { | ||
788 | $line =~ /^\s*\#+(.*)$/; | ||
789 | $line = "$1\n"; | ||
790 | |||
791 | &B_print(*HASH_NEW,"$line"); | ||
792 | &B_log("ACTION","File modification in $filename -- hash uncommented line\n"); | ||
793 | &B_log("ACTION",$line); | ||
794 | # while the line has a trailing \ then we should also uncomment out the line below | ||
795 | while($line =~ m/\\\n$/) { | ||
796 | if($line=<HASH_OLD>) { | ||
797 | $line =~ /^\s*\#+(.*)$/; | ||
798 | $line = "$1\n"; | ||
799 | &B_print(*HASH_NEW,"$line"); | ||
800 | &B_log("ACTION","File modification in $filename -- hash uncommented line\n"); | ||
801 | &B_log("ACTION","#$line"); | ||
802 | &B_log("ACTION","like this:\n"); | ||
803 | &B_log("ACTION","$line"); | ||
804 | } | ||
805 | else { | ||
806 | $line = ""; | ||
807 | } | ||
808 | } | ||
809 | } | ||
810 | } | ||
811 | &B_close_plus (*HASH_NEW,*HASH_OLD,$filename); | ||
812 | } | ||
813 | else { | ||
814 | $retval=0; | ||
815 | &B_log("ERROR","Couldn't hash-uncomment line(s) in $filename because open failed.\n"); | ||
816 | } | ||
817 | |||
818 | return $retval; | ||
819 | } | ||
820 | |||
821 | |||
822 | |||
823 | ########################################################################### | ||
824 | # &B_delete_line ($filename,$pattern) modifies $filename, deleting any | ||
825 | # lines matching $pattern. It uses B_replace_line to do this. | ||
826 | # | ||
827 | # B_replace_line uses B_open_plus and B_close_plus, so that the file | ||
828 | # modified is backed up... | ||
829 | # | ||
830 | # Here an example of where you might use this: | ||
831 | # | ||
832 | # You'd like to remove any timeout= lines in /etc/lilo.conf, so that your | ||
833 | # delay=1 modification will work. | ||
834 | |||
835 | # | ||
836 | ########################################################################### | ||
837 | |||
838 | |||
839 | sub B_delete_line($$) { | ||
840 | |||
841 | my ($filename,$pattern)=@_; | ||
842 | my $retval=&B_replace_line($filename,$pattern,""); | ||
843 | |||
844 | return $retval; | ||
845 | } | ||
846 | |||
847 | |||
848 | ########################################################################### | ||
849 | # &B_chunk_replace ($file,$pattern,$replacement) reads $file replacing the | ||
850 | # first occurrence of $pattern with $replacement. | ||
851 | # | ||
852 | ########################################################################### | ||
853 | |||
854 | sub B_chunk_replace($$$) { | ||
855 | |||
856 | my ($file,$pattern,$replacement) = @_; | ||
857 | |||
858 | my @lines; | ||
859 | my $big_long_line; | ||
860 | my $retval=1; | ||
861 | |||
862 | &B_open (*OLDFILE,$file); | ||
863 | |||
864 | # Read all lines into one scalar. | ||
865 | @lines = <OLDFILE>; | ||
866 | &B_close (*OLDFILE); | ||
867 | foreach my $line ( @lines ) { | ||
868 | $big_long_line .= $line; | ||
869 | } | ||
870 | |||
871 | # Substitution routines get weird unless last line is terminated with \n | ||
872 | chomp $big_long_line; | ||
873 | $big_long_line .= "\n"; | ||
874 | |||
875 | # Exit if we don't find a match | ||
876 | unless ($big_long_line =~ $pattern) { | ||
877 | return 0; | ||
878 | } | ||
879 | |||
880 | $big_long_line =~ s/$pattern/$replacement/s; | ||
881 | |||
882 | $retval=&B_open_plus (*NEWFILE,*OLDFILE,$file); | ||
883 | if ($retval) { | ||
884 | &B_print (*NEWFILE,$big_long_line); | ||
885 | &B_close_plus (*NEWFILE,*OLDFILE,$file); | ||
886 | } | ||
887 | |||
888 | return $retval; | ||
889 | } | ||
890 | |||
891 | ########################################################################### | ||
892 | # &B_print ($handle,@list) prints the items of @list to the file handle | ||
893 | # $handle. It logs the action and respects the $GLOBAL_LOGONLY variable. | ||
894 | # | ||
895 | ########################################################################### | ||
896 | |||
897 | sub B_print { | ||
898 | my $handle=shift @_; | ||
899 | |||
900 | my $result=1; | ||
901 | |||
902 | unless ($GLOBAL_LOGONLY) { | ||
903 | $result=print $handle @_; | ||
904 | } | ||
905 | |||
906 | ($handle) = "$handle" =~ /[^:]+::[^:]+::([^:]+)/; | ||
907 | |||
908 | $result; | ||
909 | } | ||
910 | |||
911 | |||
912 | ########################################################################## | ||
913 | # &B_getValueFromFile($regex,$file); | ||
914 | # Takes a regex with a single group "()" and returns the unique value | ||
915 | # on any non-commented lines | ||
916 | # This (and B_return_matched_lines are only used in this file, though are | ||
917 | # probably more generally useful. For now, leaving these here serve the following | ||
918 | #functions: | ||
919 | # a) still gets exported/associated as part of the Test_API package, and | ||
920 | # is still availble for a couple operations that can't be deferred to the | ||
921 | # main test loop, as they save values so that individual tests don't have to | ||
922 | # recreate (copy / paste) the logic to get them. | ||
923 | # | ||
924 | # It also avoids the circular "use" if we incldued "use Test API" at the top | ||
925 | # of this file (Test API "uses" this file. | ||
926 | # Returns the uncommented, unique values of a param=value pair. | ||
927 | # | ||
928 | # Return values: | ||
929 | # 'Not Defined' if the value is not present or not uniquely defined. | ||
930 | # $value if the value is present and unique | ||
931 | # | ||
932 | ########################################################################### | ||
933 | sub B_getValueFromFile ($$){ | ||
934 | my $inputRegex=$_[0]; | ||
935 | my $file=$_[1]; | ||
936 | my ($lastvalue,$value)=''; | ||
937 | |||
938 | my @lines=&B_return_matched_lines($file, $inputRegex); | ||
939 | |||
940 | return &B_getValueFromString($inputRegex,join('/n',@lines)); | ||
941 | } | ||
942 | |||
943 | ########################################################################## | ||
944 | # &B_getValueFromString($param,$string); | ||
945 | # Takes a regex with a single group "()" and returns the unique value | ||
946 | # on any non-commented lines | ||
947 | # This (and B_return_matched_lines are only used in this file, though are | ||
948 | # probably more generally useful. For now, leaving these here serve the following | ||
949 | #functions: | ||
950 | # a) still gets exported/associated as part of the Test_API package, and | ||
951 | # is still availble for a couple operations that can't be deferred to the | ||
952 | # main test loop, as they save values so that individual tests don't have to | ||
953 | # recreate (copy / paste) the logic to get them. | ||
954 | # | ||
955 | # It also avoids the circular "use" if we incldued "use Test API" at the top | ||
956 | # of this file (Test API "uses" this file. | ||
957 | # Returns the uncommented, unique values of a param=value pair. | ||
958 | # | ||
959 | # Return values: | ||
960 | # 'Not Unique' if the value is not uniquely defined. | ||
961 | # undef if the value isn't defined at all | ||
962 | # $value if the value is present and unique | ||
963 | # | ||
964 | ########################################################################### | ||
965 | sub B_getValueFromString ($$){ | ||
966 | my $inputRegex=$_[0]; | ||
967 | my $inputString=$_[1]; | ||
968 | my $lastValue=''; | ||
969 | my $value=''; | ||
970 | |||
971 | my @lines=split(/\n/,$inputString); | ||
972 | |||
973 | &B_log("DEBUG","B_getvaluefromstring called with regex: $inputRegex and input: " . | ||
974 | $inputString); | ||
975 | foreach my $line (grep(/$inputRegex/,@lines)) { | ||
976 | $line =~ /$inputRegex/; | ||
977 | $value=$1; | ||
978 | if (($lastValue eq '') and ($value ne '')) { | ||
979 | $lastValue = $value; | ||
980 | } elsif (($lastValue ne $value) and ($value ne '')) { | ||
981 | B_log("DEBUG","getvaluefromstring returned Not Unique"); | ||
982 | return 'Not Unique'; | ||
983 | } | ||
984 | } | ||
985 | if ((not(defined($value))) or ($value eq '')) { | ||
986 | &B_log("DEBUG","Could not find regex match in string"); | ||
987 | return undef; | ||
988 | } else { | ||
989 | &B_log("DEBUG","B_getValueFromString Found: $value ; using: $inputRegex"); | ||
990 | return $value; | ||
991 | } | ||
992 | } | ||
993 | |||
994 | ############################################################### | ||
995 | # This function adds something to the To Do List. | ||
996 | # Arguments: | ||
997 | # 1) The string you want to add to the To Do List. | ||
998 | # 2) Optional: Question whose TODOFlag should be set to indicate | ||
999 | # A pending manual action in subsequent reports. Only skip this | ||
1000 | # If there's no security-audit relevant action you need the user to | ||
1001 | # accomplish | ||
1002 | # Ex: | ||
1003 | # &B_TODO("------\nInstalling IPFilter\n----\nGo get Ipfilter","IPFilter.install_ipfilter"); | ||
1004 | # | ||
1005 | # | ||
1006 | # Returns: | ||
1007 | # 0 - If error condition | ||
1008 | # True, if sucess, specifically: | ||
1009 | # "appended" if the append operation was successful | ||
1010 | # "exists" if no change was made since the entry was already present | ||
1011 | ############################################################### | ||
1012 | sub B_TODO ($;$) { | ||
1013 | my $text = $_[0]; | ||
1014 | my $FlaggedQuestion = $_[1]; | ||
1015 | my $multilineString = ""; | ||
1016 | |||
1017 | # trim off any leading and trailing new lines, regexes separated for "clarity" | ||
1018 | $text =~ s/^\n+(.*)/$1/; | ||
1019 | $text =~ s/(.*)\n+$/$1/; | ||
1020 | |||
1021 | if ( ! -e &getGlobal('BFILE',"TODO") ) { | ||
1022 | # Make the TODO list file for HP-UX Distro | ||
1023 | &B_create_file(&getGlobal('BFILE', "TODO")); | ||
1024 | &B_append_line(&getGlobal('BFILE', "TODO"),'a$b', | ||
1025 | "Please take the steps below to make your system more secure,\n". | ||
1026 | "then delete the item from this file and record what you did along\n". | ||
1027 | "with the date and time in your system administration log. You\n". | ||
1028 | "will need that information in case you ever need to revert your\n". | ||
1029 | "changes.\n\n"); | ||
1030 | } | ||
1031 | |||
1032 | |||
1033 | if (open(TODO,"<" . &getGlobal('BFILE', "TODO"))) { | ||
1034 | while (my $line = <TODO>) { | ||
1035 | # getting rid of all meta characters. | ||
1036 | $line =~ s/(\\|\||\(|\)|\[|\]|\{|\}|\^|\$|\*|\+|\?|\.)//g; | ||
1037 | $multilineString .= $line; | ||
1038 | } | ||
1039 | chomp $multilineString; | ||
1040 | $multilineString .= "\n"; | ||
1041 | |||
1042 | close(TODO); | ||
1043 | } | ||
1044 | else { | ||
1045 | &B_log("ERROR","Unable to read TODO.txt file.\n" . | ||
1046 | "The following text could not be appended to the TODO list:\n" . | ||
1047 | $text . | ||
1048 | "End of TODO text\n"); | ||
1049 | return 0; #False | ||
1050 | } | ||
1051 | |||
1052 | my $textPattern = $text; | ||
1053 | |||
1054 | # getting rid of all meta characters. | ||
1055 | $textPattern =~ s/(\\|\||\(|\)|\[|\]|\{|\}|\^|\$|\*|\+|\?|\.)//g; | ||
1056 | |||
1057 | if( $multilineString !~ "$textPattern") { | ||
1058 | my $datestamp = "{" . localtime() . "}"; | ||
1059 | unless ( &B_append_line(&getGlobal('BFILE', "TODO"), "", $datestamp . "\n" . $text . "\n\n\n") ) { | ||
1060 | &B_log("ERROR","TODO Failed for text: " . $text ); | ||
1061 | } | ||
1062 | #Note that we only set the flag on the *initial* entry in the TODO File | ||
1063 | #Not on subsequent detection. This is to avoid the case where Bastille | ||
1064 | #complains on a subsequent Bastille run of an already-performed manual | ||
1065 | #action that the user neglected to delete from the TODO file. | ||
1066 | # It does, however lead to a report of "nonsecure" when the user | ||
1067 | #asked for the TODO item, performed it, Bastille detected that and cleared the | ||
1068 | # Item, and then the user unperformed the action. I think this is proper behavior. | ||
1069 | # rwf 06/06 | ||
1070 | |||
1071 | if (defined($FlaggedQuestion)) { | ||
1072 | &B_TODOFlags("set",$FlaggedQuestion); | ||
1073 | } | ||
1074 | return "appended"; #evals to true, and also notes what happened | ||
1075 | } else { | ||
1076 | return "exists"; #evals to true, and also | ||
1077 | } | ||
1078 | |||
1079 | } | ||
1080 | |||
1081 | |||
1082 | ##################################################################### | ||
1083 | # &B_TODOFlags() | ||
1084 | # | ||
1085 | # This is the interface to the TODO flags. Test functions set these when they | ||
1086 | # require a TODO item to be completed to get to a "secure" state. | ||
1087 | # The prune/reporting function checks these to ensure no flags are set before | ||
1088 | # reporting an item "secure" | ||
1089 | # "Methods" are load | save | isSet <Question> | set <Question> | unset <Question> | ||
1090 | # | ||
1091 | ###################################################################### | ||
1092 | |||
1093 | sub B_TODOFlags($;$) { | ||
1094 | my $action = $_[0]; | ||
1095 | my $module = $_[1]; | ||
1096 | |||
1097 | use File::Spec; | ||
1098 | |||
1099 | my $todo_flag = &getGlobal("BFILE","TODOFlag"); | ||
1100 | |||
1101 | &B_log("DEBUG","B_TODOFlags action: $action , module: $module"); | ||
1102 | |||
1103 | if ($action eq "load") { | ||
1104 | if (-e $todo_flag ) { | ||
1105 | &B_open(*TODO_FLAGS, $todo_flag); | ||
1106 | my @lines = <TODO_FLAGS>; | ||
1107 | foreach my $line (@lines) { | ||
1108 | chomp($line); | ||
1109 | $GLOBAL_CONFIG{"$line"}{"TODOFlag"}="yes"; | ||
1110 | } | ||
1111 | return (&B_close(*TODO_FLAGS)); #return success of final close | ||
1112 | } else { | ||
1113 | return 1; #No-op is okay | ||
1114 | } | ||
1115 | } elsif ($action eq "save") { | ||
1116 | # Make sure the file exists, else create | ||
1117 | #Note we use open_plus and and create file, so if Bastille is | ||
1118 | #reverted, all the flags will self-clear (file deleted) | ||
1119 | my $flagNumber = 0; | ||
1120 | my $flagData = ''; | ||
1121 | foreach my $key (keys %GLOBAL_CONFIG) { | ||
1122 | if ($GLOBAL_CONFIG{$key}{"TODOFlag"} eq "yes") { | ||
1123 | ++$flagNumber; | ||
1124 | $flagData .= "$key\n"; | ||
1125 | } | ||
1126 | } | ||
1127 | if (not( -e $todo_flag)) { | ||
1128 | &B_log("DEBUG","Initializing TODO Flag file: $todo_flag"); | ||
1129 | &B_create_file($todo_flag); # Make sure it exists | ||
1130 | } | ||
1131 | &B_blank_file($todo_flag, | ||
1132 | "This will not appear in the file; ensures blanking"); | ||
1133 | return &B_append_line($todo_flag, "", "$flagData"); #return success of save | ||
1134 | } elsif (($action eq "isSet") and ($module ne "")) { | ||
1135 | if ($GLOBAL_CONFIG{"$module"}{"TODOFlag"} eq "yes") { | ||
1136 | return 1; #TRUE | ||
1137 | } else { | ||
1138 | return 0; #FALSE | ||
1139 | } | ||
1140 | } elsif (($action eq "set") and ($module ne "")) { | ||
1141 | $GLOBAL_CONFIG{"$module"}{"TODOFlag"} = "yes"; | ||
1142 | } elsif (($action eq "clear") and ($module ne "")) { | ||
1143 | $GLOBAL_CONFIG{"$module"}{"TODOFlag"} = ""; | ||
1144 | } else { | ||
1145 | &B_log("ERROR","TODO_Flag Called with invalid parameters: $action , $module". | ||
1146 | "audit report may be incorrect."); | ||
1147 | return 0; #FALSE | ||
1148 | } | ||
1149 | } | ||
1150 | |||
1151 | 1; | ||
1152 | |||
1153 | |||
diff --git a/dynamic-layers/meta-perl/recipes-security/bastille/files/HPSpecific.pm b/dynamic-layers/meta-perl/recipes-security/bastille/files/HPSpecific.pm new file mode 100644 index 0000000..7e7d709 --- /dev/null +++ b/dynamic-layers/meta-perl/recipes-security/bastille/files/HPSpecific.pm | |||
@@ -0,0 +1,1983 @@ | |||
1 | package Bastille::API::HPSpecific; | ||
2 | |||
3 | use strict; | ||
4 | use Bastille::API; | ||
5 | use Bastille::API::FileContent; | ||
6 | |||
7 | require Exporter; | ||
8 | our @ISA = qw(Exporter); | ||
9 | our @EXPORT_OK = qw( | ||
10 | getIPFLocation | ||
11 | getGlobalSwlist | ||
12 | B_check_system | ||
13 | B_swmodify | ||
14 | B_load_ipf_rules | ||
15 | B_Schedule | ||
16 | B_ch_rc | ||
17 | B_set_value | ||
18 | B_chperm | ||
19 | B_install_jail | ||
20 | B_list_processes | ||
21 | B_list_full_processes | ||
22 | B_deactivate_inetd_service | ||
23 | B_get_rc | ||
24 | B_set_rc | ||
25 | B_chrootHPapache | ||
26 | isSystemTrusted | ||
27 | isTrustedMigrationAvailable | ||
28 | checkServiceOnHPUX | ||
29 | B_get_path | ||
30 | convertToTrusted | ||
31 | isOKtoConvert | ||
32 | convertToShadow | ||
33 | getSupportedSettings | ||
34 | B_get_sec_value | ||
35 | secureIfNoNameService | ||
36 | isUsingRemoteNameService | ||
37 | remoteServiceCheck | ||
38 | remoteNISPlusServiceCheck | ||
39 | B_create_nsswitch_file | ||
40 | B_combine_service_results | ||
41 | |||
42 | %priorBastilleNDD | ||
43 | %newNDD | ||
44 | ); | ||
45 | our @EXPORT = @EXPORT_OK; | ||
46 | |||
47 | |||
48 | |||
49 | # "Constants" for use both in testing and in lock-down | ||
50 | our %priorBastilleNDD = ( | ||
51 | "ip_forward_directed_broadcasts" =>["ip", "0"], | ||
52 | "ip_forward_src_routed" =>["ip", "0"], | ||
53 | "ip_forwarding" =>["ip", "0"], | ||
54 | "ip_ire_gw_probe" =>["ip", "0"], | ||
55 | "ip_pmtu_strategy" =>["ip", "1"], | ||
56 | "ip_respond_to_echo_broadcast" =>["ip", "0"], | ||
57 | "ip_send_redirects" =>["ip", "0"], | ||
58 | "ip_send_source_quench" =>["ip", "0"], | ||
59 | "tcp_syn_rcvd_max" =>["tcp","1000"], | ||
60 | "tcp_conn_request_max" =>["tcp","4096"] ); | ||
61 | |||
62 | our %newNDD = ( | ||
63 | "ip_forward_directed_broadcasts" =>["ip", "0"], | ||
64 | "ip_forward_src_routed" =>["ip", "0"], | ||
65 | "ip_forwarding" =>["ip", "0"], | ||
66 | "ip_ire_gw_probe" =>["ip", "0"], | ||
67 | "ip_pmtu_strategy" =>["ip", "1"], | ||
68 | "ip_respond_to_echo_broadcast" =>["ip", "0"], | ||
69 | "ip_send_redirects" =>["ip", "0"], | ||
70 | "ip_send_source_quench" =>["ip", "0"], | ||
71 | "tcp_syn_rcvd_max" =>["tcp","4096"], | ||
72 | "tcp_conn_request_max" =>["tcp","4096"], | ||
73 | "arp_cleanup_interval" =>["arp","60000"], | ||
74 | "ip_respond_to_timestamp" =>["ip", "0"], | ||
75 | "ip_respond_to_timestamp_broadcast" => ["ip","0"] ); | ||
76 | |||
77 | |||
78 | #################################################################### | ||
79 | # | ||
80 | # This module makes up the HP-UX specific API routines. | ||
81 | # | ||
82 | #################################################################### | ||
83 | # | ||
84 | # Subroutine Listing: | ||
85 | # &HP_ConfigureForDistro: adds all used file names to global | ||
86 | # hashes and generates a global IPD | ||
87 | # hash for SD modification lookup. | ||
88 | # | ||
89 | # &getGlobalSwlist($): Takes a fully qualified file name | ||
90 | # and returns product:filset info | ||
91 | # for that file. returns undef if | ||
92 | # the file is not present in the IPD | ||
93 | # | ||
94 | # &B_check_system: Runs a series of system queries to | ||
95 | # determine if Bastille can be safely | ||
96 | # ran on the current system. | ||
97 | # | ||
98 | # &B_swmodify($): Takes a file name and runs the | ||
99 | # swmodify command on it so that the | ||
100 | # IPD is updated after changes | ||
101 | # | ||
102 | # &B_System($$): Takes a system command and the system | ||
103 | # command that should be used to revert | ||
104 | # whatever was done. Returns 1 on | ||
105 | # success and 0 on failure | ||
106 | # | ||
107 | # &B_Backtick($) Takes a command to run and returns its stdout | ||
108 | # to be used in place of the prior prevelent use | ||
109 | # of un-error-handled backticks | ||
110 | # | ||
111 | # &B_load_ipf_rules($): Loads a set of ipfrules into ipf, storing | ||
112 | # current rules for later reversion. | ||
113 | # | ||
114 | # &B_Schedule($$): Takes a pattern and a crontab line. | ||
115 | # Adds or replaces the crontab line to | ||
116 | # the crontab file, depending on if a | ||
117 | # line matches the pattern | ||
118 | # | ||
119 | # &B_ch_rc($$): Takes a the rc.config.d flag name and | ||
120 | # new value as well as the init script | ||
121 | # location. This will stop a services | ||
122 | # and set the service so that it will | ||
123 | # not be restarted. | ||
124 | # | ||
125 | # &B_set_value($$$): Takes a param, value, and a filename | ||
126 | # and sets the given value in the file. | ||
127 | # Uses ch_rc, but could be rewritten using | ||
128 | # Bastille API calls to make it work on Linux | ||
129 | # | ||
130 | # &B_TODO($): Appends the give string to the TODO.txt | ||
131 | # file. | ||
132 | # | ||
133 | # &B_chperm($$$$): Takes new perm owner and group of given | ||
134 | # file. TO BE DEPRECATED!!! | ||
135 | # | ||
136 | # &B_install_jail($$): Takes the jail name and the jail config | ||
137 | # script location for a give jail... | ||
138 | # These scripts can be found in the main | ||
139 | # directory e.g. jail.bind.hpux | ||
140 | # | ||
141 | ##################################################################### | ||
142 | |||
143 | ############################################################################## | ||
144 | # | ||
145 | # HP-UX Bastille directory structure | ||
146 | # | ||
147 | ############################################################################## | ||
148 | # | ||
149 | # /opt/sec_mgmt/bastille/bin/ -- location of Bastille binaries | ||
150 | # /opt/sec_mgmt/bastille/lib/ -- location of Bastille modules | ||
151 | # /opt/sec_mgmt/bastille/doc/ -- location of Bastille doc files | ||
152 | # | ||
153 | # /etc/opt/sec_mgmt/bastille/ -- location of Bastille config files | ||
154 | # | ||
155 | # /var/opt/sec_mgmt/bastille/log -- location of Bastille log files | ||
156 | # /var/opt/sec_mgmt/bastille/revert -- directory holding all Bastille- | ||
157 | # created revert scripts | ||
158 | # /var/opt/sec_mgmt/bastille/revert/backup -- directory holding the original | ||
159 | # files that Bastille modifies, | ||
160 | # with permissions intact | ||
161 | # | ||
162 | ############################################################################## | ||
163 | |||
164 | sub getIPFLocation () { # Temporary until we get defined search space support | ||
165 | my $ipf=&getGlobal('BIN','ipf_new'); | ||
166 | my $ipfstat=&getGlobal('BIN','ipfstat_new'); | ||
167 | if (not(-e $ipf)) { # Detect if the binaries moved | ||
168 | $ipf = &getGlobal('BIN','ipf'); | ||
169 | $ipfstat=&getGlobal('BIN','ipfstat'); | ||
170 | } | ||
171 | return ($ipf, $ipfstat); | ||
172 | } | ||
173 | |||
174 | ############################################## | ||
175 | # Given a combination of service results, provided | ||
176 | # in an array, this function combines the result into | ||
177 | # a reasonable aggregate result | ||
178 | ############################################## | ||
179 | |||
180 | sub B_combine_service_results(@){ | ||
181 | my @results = @_; | ||
182 | |||
183 | #TODO: Consider greater sophistication wrt inconsistent, or not installed. | ||
184 | |||
185 | foreach my $result (@results) { | ||
186 | if (not(($result == SECURE_CAN_CHANGE) or | ||
187 | ($result == SECURE_CANT_CHANGE) or | ||
188 | ($result == NOT_INSTALLED()))) { | ||
189 | return NOTSECURE_CAN_CHANGE(); | ||
190 | } | ||
191 | } | ||
192 | return SECURE_CANT_CHANGE(); | ||
193 | } | ||
194 | |||
195 | #################################################################### | ||
196 | # &getGlobalSwlist ($file); | ||
197 | # This function returns the product and fileset information for | ||
198 | # a given file or directory if it exists in the IPD otherwise | ||
199 | # it returns undefined "undef" | ||
200 | # | ||
201 | # uses $GLOBAL_SWLIST{"$FILE"} | ||
202 | #################################################################### | ||
203 | sub getGlobalSwlist($){ | ||
204 | no strict; | ||
205 | my $file = $_[0]; | ||
206 | |||
207 | |||
208 | if(! %GLOBAL_SWLIST) { | ||
209 | # Generating swlist database for swmodify changes that will be required | ||
210 | # The database will be a hash of fully qualified file names that reference | ||
211 | # the files product name and fileset. These values are required to use | ||
212 | # swmodify... | ||
213 | |||
214 | # Files tagged 'is_volatile' in the IPD are not entered in the swlist database | ||
215 | # in order to avoid invoking swmodify if the file is changed later. Attempting to | ||
216 | # swmodify 'volatile' files is both unneccessary and complicated since swverify will | ||
217 | # not evaluate volatile files anyway, and adding another value to the swlist database | ||
218 | # would require complex code changes. | ||
219 | |||
220 | # temp variable to keep swlist command /usr/sbin/swlist | ||
221 | my $swlist = &getGlobal('BIN',"swlist"); | ||
222 | |||
223 | # listing of each directory and file that was installed by SD on the target machine | ||
224 | my @fileList = `$swlist -a is_volatile -l file`; | ||
225 | |||
226 | # listing of each patch and the patches that supersede each. | ||
227 | # hash which is indexed by patch.fileset on the system | ||
228 | my %patchSuperseded; | ||
229 | |||
230 | my @patchList = `${swlist} -l fileset -a superseded_by *.*,c=patch 2>&1`; | ||
231 | # check to see if any patches are present on the system | ||
232 | if(($? >> 8) == 0) { | ||
233 | |||
234 | # determining patch suppression for swmodify. | ||
235 | foreach my $patchState (@patchList) { | ||
236 | # removing empty lines and commented lines. | ||
237 | if($patchState !~ /^\s*\#/ && $patchState !~ /^\s*$/) { | ||
238 | |||
239 | # removing leading white space | ||
240 | $patchState =~ s/^\s+//; | ||
241 | my @patches = split /\s+/, $patchState; | ||
242 | if($#patches == 0){ | ||
243 | # patch is not superseded | ||
244 | $patchSuperseded{$patches[0]} = 0; | ||
245 | } | ||
246 | else { | ||
247 | # patch is superseded | ||
248 | $patchSuperseded{$patches[0]} = 1; | ||
249 | } | ||
250 | } | ||
251 | } | ||
252 | } | ||
253 | else { | ||
254 | &B_log("DEBUG","No patches found on the system.\n"); | ||
255 | } | ||
256 | |||
257 | if($#fileList >= 0){ | ||
258 | # foreach line of swlist output | ||
259 | foreach my $fileEntry ( @fileList ){ | ||
260 | #filter out commented portions | ||
261 | if( $fileEntry !~ /^\s*\#/ ){ | ||
262 | chomp $fileEntry; | ||
263 | # split the output into three fields: product.fileset, filename, flag_isvolatile | ||
264 | my( $productInfo, $file, $is_volatile ) = $fileEntry =~ /^\s*(\S+): (\S+)\t(\S+)/ ; | ||
265 | # do not register volatile files | ||
266 | next if ($is_volatile =~ /true/); # skip to next file entry | ||
267 | $productInfo =~ s/\s+//; | ||
268 | $file =~ s/\s+//; | ||
269 | # if the product is a patch | ||
270 | if($productInfo =~ /PH(CO|KL|NE|SS)/){ | ||
271 | # if the patch is not superseded by another patch | ||
272 | if($patchSuperseded{$productInfo} == 0){ | ||
273 | # add the patch to the list of owner for this file | ||
274 | push @{$GLOBAL_SWLIST{"$file"}}, $productInfo; | ||
275 | } | ||
276 | } | ||
277 | # not a patch. | ||
278 | else { | ||
279 | # add the product to the list of owners for this file | ||
280 | push @{$GLOBAL_SWLIST{"$file"}}, $productInfo; | ||
281 | } | ||
282 | |||
283 | } | ||
284 | } | ||
285 | } | ||
286 | else{ | ||
287 | # defining GLOBAL_SWLIST in error state. | ||
288 | $GLOBAL_SWLIST{"ERROR"} = "ERROR"; | ||
289 | &B_log("ERROR","Could not execute swlist. Swmodifys will not be attempted"); | ||
290 | } | ||
291 | } | ||
292 | |||
293 | if(exists $GLOBAL_SWLIST{"$file"}){ | ||
294 | return $GLOBAL_SWLIST{"$file"}; | ||
295 | } | ||
296 | else { | ||
297 | return undef; | ||
298 | } | ||
299 | } | ||
300 | |||
301 | ################################################################### | ||
302 | # &B_check_system; | ||
303 | # This subroutine is called to validate that bastille may be | ||
304 | # safely run on the current system. It will check to insure | ||
305 | # that there is enough file system space, mounts are rw, nfs | ||
306 | # mounts are not mounted noroot, and swinstall, swremove and | ||
307 | # swmodify are not running | ||
308 | # | ||
309 | # uses ErrorLog | ||
310 | # | ||
311 | ################################################################## | ||
312 | sub B_check_system { | ||
313 | # exitFlag is one if a conflict with the successful execution | ||
314 | # of bastille is found. | ||
315 | my $exitFlag = 0; | ||
316 | |||
317 | my $ignoreCheck = &getGlobal("BDIR","config") . "/.no_system_check"; | ||
318 | if( -e $ignoreCheck ) { | ||
319 | return $exitFlag; | ||
320 | } | ||
321 | |||
322 | # first check for swinstall, swmodify, or swremove processes | ||
323 | my $ps = &getGlobal('BIN',"ps") . " -el"; | ||
324 | my @processTable = `$ps`; | ||
325 | foreach my $process (@processTable) { | ||
326 | if($process =~ /swinstall/ ) { | ||
327 | &B_log("ERROR","Bastille cannot run while a swinstall is in progress.\n" . | ||
328 | "Complete the swinstall operation and then run Bastille.\n\n"); | ||
329 | $exitFlag = 1; | ||
330 | } | ||
331 | |||
332 | if($process =~ /swremove/ ) { | ||
333 | &B_log("ERROR","Bastille cannot run while a swremove is in progress.\n" . | ||
334 | "Complete the swremove operation and then run Bastille.\n\n"); | ||
335 | $exitFlag = 1; | ||
336 | } | ||
337 | |||
338 | if($process =~ /swmodify/ ) { | ||
339 | &B_log("ERROR","Bastille cannot run while a swmodify is in progress.\n" . | ||
340 | "Complete the swmodify operation and then run Bastille.\n\n"); | ||
341 | $exitFlag = 1; | ||
342 | } | ||
343 | |||
344 | } | ||
345 | |||
346 | # check for root read only mounts for /var /etc /stand / | ||
347 | # Bastille is required to make changes to these file systems. | ||
348 | my $mount = &getGlobal('BIN',"mount"); | ||
349 | my $rm = &getGlobal('BIN',"rm"); | ||
350 | my $touch = &getGlobal('BIN',"touch"); | ||
351 | |||
352 | my @mnttab = `$mount`; | ||
353 | |||
354 | if(($? >> 8) != 0) { | ||
355 | &B_log("WARNING","Unable to use $mount to determine if needed partitions\n" . | ||
356 | "are root writable, based on disk mount options.\n" . | ||
357 | "Bastille will continue but note that disk\n" . | ||
358 | "mount checks were skipped.\n\n"); | ||
359 | } | ||
360 | else { | ||
361 | foreach my $record (@mnttab) { | ||
362 | my @fields = split /\s+/, $record; | ||
363 | if ((defined $fields[0]) && (defined $fields[2]) && (defined $fields[3])) { | ||
364 | my $mountPoint = $fields[0]; | ||
365 | my $mountType = $fields[2]; | ||
366 | my $mountOptions = $fields[3]; | ||
367 | |||
368 | # checks for /stand and /var/* removed | ||
369 | if($mountPoint =~ /^\/$|^\/etc|^\/var$/) { | ||
370 | |||
371 | if($mountOptions =~ /^ro,|,ro,|,ro$/) { | ||
372 | &B_log("ERROR","$mountPoint is mounted read-only. Bastille needs to make\n" . | ||
373 | "modifications to this file system. Please remount\n" . | ||
374 | "$mountPoint read-write and then run Bastille again.\n\n"); | ||
375 | $exitFlag = 1; | ||
376 | } | ||
377 | # looking for an nfs mounted file system | ||
378 | if($mountType =~/.+:\//){ | ||
379 | my $fileExisted=0; | ||
380 | if(-e "$mountPoint/.bastille") { | ||
381 | $fileExisted=1; | ||
382 | } | ||
383 | |||
384 | `$touch $mountPoint/.bastille 1>/dev/null 2>&1`; | ||
385 | |||
386 | if( (! -e "$mountPoint/.bastille") || (($? >> 8) != 0) ) { | ||
387 | &B_log("ERROR","$mountPoint is an nfs mounted file system that does\n" . | ||
388 | "not allow root to write to. Bastille needs to make\n" . | ||
389 | "modifications to this file system. Please remount\n" . | ||
390 | "$mountPoint giving root access and then run Bastille\n" . | ||
391 | "again.\n\n"); | ||
392 | |||
393 | $exitFlag = 1; | ||
394 | } | ||
395 | # if the file did not exist befor the touch then remove the generated file | ||
396 | if(! $fileExisted) { | ||
397 | `$rm -f $mountPoint/.bastille 1>/dev/null 2>&1`; | ||
398 | } | ||
399 | } | ||
400 | } | ||
401 | } | ||
402 | else { | ||
403 | &B_log("WARNING","Unable to use $mount to determine if needed partitions\n" . | ||
404 | "are root writable, based on disk mount options.\n" . | ||
405 | "Bastille will continue but note that disk\n" . | ||
406 | "mount checks were skipped.\n\n"); | ||
407 | } | ||
408 | } | ||
409 | |||
410 | } | ||
411 | |||
412 | # checks for enough disk space in directories that Bastille writes to. | ||
413 | my $bdf = &getGlobal('BIN',"bdf"); | ||
414 | #directories that Bastille writes to => required space in kilobytes. | ||
415 | my %bastilleDirs = ( "/etc/opt/sec_mgmt/bastille" => "4", "/var/opt/sec_mgmt/bastille"=> "1000"); | ||
416 | for my $directory (sort keys %bastilleDirs) { | ||
417 | my @diskUsage = `$bdf $directory`; | ||
418 | |||
419 | if(($? >> 8) != 0) { | ||
420 | &B_log("WARNING","Unable to use $bdf to determine disk usage for\n" . | ||
421 | "$directory\n" . | ||
422 | "Bastille will continue but note that disk\n" . | ||
423 | "usage checks were skipped.\n\n"); | ||
424 | |||
425 | } | ||
426 | else { | ||
427 | # removing bdf header line from usage information. | ||
428 | shift @diskUsage; | ||
429 | my $usageString= ""; | ||
430 | |||
431 | foreach my $usageRecord (@diskUsage) { | ||
432 | chomp $usageRecord; | ||
433 | $usageString .= $usageRecord; | ||
434 | } | ||
435 | |||
436 | $usageString =~ s/^\s+//; | ||
437 | |||
438 | my @fields = split /\s+/, $usageString; | ||
439 | if($#fields != 5) { | ||
440 | &B_log("WARNING","Unable to use $bdf to determine disk usage for\n" . | ||
441 | "$directory\n" . | ||
442 | "Bastille will continue but note that disk\n" . | ||
443 | "usage checks were skipped.\n\n"); | ||
444 | } | ||
445 | else { | ||
446 | |||
447 | my $mountPoint = $fields[5]; | ||
448 | my $diskAvail = $fields[3]; | ||
449 | |||
450 | if($diskAvail <= $bastilleDirs{"$directory"}) { | ||
451 | &B_log("ERROR","$mountPoint does not contain enough available space\n" . | ||
452 | "for Bastille to run properly. $directory needs\n" . | ||
453 | "at least $bastilleDirs{$directory} kilobytes of space.\n" . | ||
454 | "Please clear at least that amount of space from\n" . | ||
455 | "$mountPoint and run Bastille again.\n" . | ||
456 | "Current Free Space available = ${diskAvail} k\n\n"); | ||
457 | $exitFlag = 1; | ||
458 | } | ||
459 | } | ||
460 | } | ||
461 | } | ||
462 | |||
463 | # check to make sure that we are in at least run level 2 before we attempt to run | ||
464 | my $who = &getGlobal('BIN', "who") . " -r"; | ||
465 | my $levelInfo = `$who`; | ||
466 | if(($? >> 8) != 0 ) { | ||
467 | &B_log("WARNING","Unable to use \"$who\" to determine system run.\n" . | ||
468 | "level Bastille will continue but note that the run\n" . | ||
469 | "level check was skipped.\n\n"); | ||
470 | } | ||
471 | else { | ||
472 | chomp $levelInfo; | ||
473 | my @runlevel = split /\s+/, $levelInfo; | ||
474 | if ((! defined $runlevel[3]) or ($runlevel[3] < 2)) { | ||
475 | &B_log("WARNING","Bastille requires a run-level of 2 or more to run properly.\n" . | ||
476 | "Please move your system to a higher run level and then\n" . | ||
477 | "run 'bastille -b'.\n\n"); | ||
478 | if(defined $runlevel[3]) { | ||
479 | &B_log("ERROR","Current run-level is '$runlevel[3]'.\n\n"); | ||
480 | $exitFlag=1; | ||
481 | } | ||
482 | else { | ||
483 | &B_log("WARNING","Unable to use \"$who\" to determine system run.\n" . | ||
484 | "level Bastille will continue but note that the run\n" . | ||
485 | "level check was skipped.\n\n"); | ||
486 | } | ||
487 | } | ||
488 | else { | ||
489 | &B_log("DEBUG","System run-level is $runlevel[3]\n"); | ||
490 | } | ||
491 | } | ||
492 | |||
493 | if($exitFlag) { | ||
494 | exit(1); | ||
495 | } | ||
496 | |||
497 | } | ||
498 | |||
499 | ################################################################### | ||
500 | # &B_swmodify($file); | ||
501 | # This subroutine is called after a file is modified. It will | ||
502 | # redefine the file in the IPD with it's new properties. If | ||
503 | # the file is not in the IPD it does nothing. | ||
504 | # | ||
505 | # uses B_System to make the swmodifications. | ||
506 | ################################################################## | ||
507 | sub B_swmodify($){ | ||
508 | my $file = $_[0]; | ||
509 | if(defined &getGlobalSwlist($file)){ | ||
510 | my $swmodify = &getGlobal('BIN',"swmodify"); | ||
511 | my @productsInfo = @{&getGlobalSwlist($file)}; | ||
512 | # running swmodify on files that were altered by this function but | ||
513 | # were created and maintained by SD | ||
514 | foreach my $productInfo (@productsInfo) { | ||
515 | &B_System("$swmodify -x files='$file' $productInfo", | ||
516 | "$swmodify -x files='$file' $productInfo"); | ||
517 | } | ||
518 | } | ||
519 | } | ||
520 | |||
521 | #################################################################### | ||
522 | # &B_load_ipf_rules($ipfruleset); | ||
523 | # This function enables an ipfruleset. It's a little more | ||
524 | # specific than most API functions, but necessary because | ||
525 | # ipf doesn't return correct exit codes (syntax error results | ||
526 | # in a 0 exit code) | ||
527 | # | ||
528 | # uses ActionLog and ErrorLog to log | ||
529 | # calls crontab directly (to list and to read in new jobs) | ||
530 | ################################################################### | ||
531 | sub B_load_ipf_rules ($) { | ||
532 | my $ipfruleset=$_[0]; | ||
533 | |||
534 | &B_log("DEBUG","# sub B_load_ipf_rules"); | ||
535 | |||
536 | # TODO: grab ipf.conf dynamically from the rc.config.d files | ||
537 | my $ipfconf = &getGlobal('FILE','ipf.conf'); | ||
538 | |||
539 | # file system changes - these are straightforward, and the API | ||
540 | # will take care of the revert | ||
541 | &B_create_file($ipfconf); | ||
542 | &B_blank_file($ipfconf, 'a$b'); | ||
543 | &B_append_line($ipfconf, 'a$b', $ipfruleset); | ||
544 | |||
545 | # runtime changes | ||
546 | |||
547 | # define binaries | ||
548 | my $grep = &getGlobal('BIN', 'grep'); | ||
549 | my ($ipf, $ipfstat) = &getIPFLocation; | ||
550 | # create backup rules | ||
551 | # This will exit with a non-zero exit code because of the grep | ||
552 | my @oldrules = `$ipfstat -io 2>&1 | $grep -v empty`; | ||
553 | |||
554 | my @errors=`$ipf -I -Fa -f $ipfconf 2>&1`; | ||
555 | |||
556 | if(($? >> 8) == 0) { | ||
557 | |||
558 | &B_set_rc("IPF_START","1"); | ||
559 | &B_set_rc("IPF_CONF","$ipfconf"); | ||
560 | |||
561 | # swap the rules in | ||
562 | &B_System("$ipf -s","$ipf -s"); | ||
563 | |||
564 | # now create a "here" document with the previous version of | ||
565 | # the rules and put it into the revert-actions script | ||
566 | &B_revert_log("$ipf -I -Fa -f - <<EOF\n@{oldrules}EOF"); | ||
567 | |||
568 | if (@errors) { | ||
569 | &B_log("ERROR","ipfilter produced the following errors when\n" . | ||
570 | " loading $ipfconf. You probably had an invalid\n" . | ||
571 | " rule in ". &getGlobal('FILE','customipfrules') ."\n". | ||
572 | "@errors\n"); | ||
573 | } | ||
574 | |||
575 | } else { | ||
576 | &B_log("ERROR","Unable to run $ipf\n"); | ||
577 | } | ||
578 | |||
579 | } | ||
580 | |||
581 | |||
582 | |||
583 | #################################################################### | ||
584 | # &B_Schedule($pattern,$cronjob); | ||
585 | # This function schedules a cronjob. If $pattern exists in the | ||
586 | # crontab file, that job will be replaced. Otherwise, the job | ||
587 | # will be appended. | ||
588 | # | ||
589 | # uses ActionLog and ErrorLog to log | ||
590 | # calls crontab directly (to list and to read in new jobs) | ||
591 | ################################################################### | ||
592 | sub B_Schedule ($$) { | ||
593 | my ($pattern,$cronjob)=@_; | ||
594 | $cronjob .= "\n"; | ||
595 | |||
596 | &B_log("DEBUG","# sub B_Schedule"); | ||
597 | my $crontab = &getGlobal('BIN','crontab'); | ||
598 | |||
599 | my @oldjobs = `$crontab -l 2>/dev/null`; | ||
600 | my @newjobs; | ||
601 | my $patternfound=0; | ||
602 | |||
603 | foreach my $oldjob (@oldjobs) { | ||
604 | if (($oldjob =~ m/$pattern/ ) and (not($patternfound))) { | ||
605 | push @newjobs, $cronjob; | ||
606 | $patternfound=1; | ||
607 | &B_log("ACTION","changing existing cron job which matches $pattern with\n" . | ||
608 | "$cronjob"); | ||
609 | } elsif ($oldjob !~ m/$pattern/ ) { | ||
610 | &B_log("ACTION","keeping existing cron job $oldjob"); | ||
611 | push @newjobs, $oldjob; | ||
612 | } #implied: else if pattern matches, but we've | ||
613 | #already replaced one, then toss the others. | ||
614 | } | ||
615 | |||
616 | unless ($patternfound) { | ||
617 | &B_log("ACTION","adding cron job\n$cronjob\n"); | ||
618 | push @newjobs, $cronjob; | ||
619 | } | ||
620 | |||
621 | if(open(CRONTAB, "|$crontab - 2> /dev/null")) { | ||
622 | print CRONTAB @newjobs; | ||
623 | |||
624 | # now create a "here" document with the previous version of | ||
625 | # the crontab file and put it into the revert-actions script | ||
626 | &B_revert_log("$crontab <<EOF\n" . "@oldjobs" . "EOF"); | ||
627 | close CRONTAB; | ||
628 | } | ||
629 | |||
630 | # Now check to make sure it happened, since cron will exit happily | ||
631 | # (retval 0) with no changes if there are any syntax errors | ||
632 | my @editedjobs = `$crontab -l 2>/dev/null`; | ||
633 | |||
634 | if (@editedjobs ne @newjobs) { | ||
635 | &B_log("ERROR","failed to add cron job:\n$cronjob\n" . | ||
636 | " You probably had an invalid crontab file to start with."); | ||
637 | } | ||
638 | |||
639 | } | ||
640 | |||
641 | |||
642 | #This function turns off a service, given a service name defined in HP-UX.service | ||
643 | |||
644 | sub B_ch_rc($) { | ||
645 | |||
646 | my ($service_name)=@_; | ||
647 | |||
648 | if (&GetDistro != "^HP-UX") { | ||
649 | &B_log("ERROR","Tried to call ch_rc $service_name on a non-HP-UX\n". | ||
650 | " system! Internal Bastille error."); | ||
651 | return undef; | ||
652 | } | ||
653 | my $configfile=""; | ||
654 | my $command = &getGlobal('BIN', 'ch_rc'); | ||
655 | |||
656 | my $startup_script=&getGlobal('DIR','initd') . "/". $service_name; | ||
657 | my @rc_parameters= @{ &getGlobal('SERVICE',$service_name) }; | ||
658 | my @rcFiles=@{ &getGlobal('RCCONFIG',$service_name) }; | ||
659 | my $rcFile=''; | ||
660 | if (@rcFiles == 1){ | ||
661 | $rcFile=$rcFiles[0]; | ||
662 | } else { | ||
663 | &B_log("FATAL","Multiple RC Files not yet supported... internal error."); | ||
664 | } | ||
665 | |||
666 | # if the service-related process is not run, and the control variable is stilll 1 | ||
667 | # there is a inconsistency. in this case we only need to change the control variable | ||
668 | my @psnames=@{ &getGlobal('PROCESS',$service_name)}; | ||
669 | my @processes; | ||
670 | foreach my $psname (@psnames) { | ||
671 | $psname .= '\b'; # avoid embedded match; anchor search pattern to trailing word boundry | ||
672 | my @procList = &isProcessRunning($psname); | ||
673 | if(@procList >= 0){ | ||
674 | splice @processes,$#processes+1,0,@procList; | ||
675 | } | ||
676 | } | ||
677 | #Actually set the rc variable | ||
678 | foreach my $rcVariable (@rc_parameters){ | ||
679 | my $orig_value = &B_get_rc($rcVariable); | ||
680 | if ($orig_value eq "" ) { #If variable not set, used the defined file | ||
681 | $configfile=&getGlobal("DIR","rc.config.d") . "/" . $rcFile; | ||
682 | if (not( -f $configfile )) { | ||
683 | &B_create_file($configfile); | ||
684 | } | ||
685 | } | ||
686 | &B_log("DEBUG","In B_ch_rc (no procs), setting $rcVariable to 0 in $configfile" . | ||
687 | ", with an original value of $orig_value with rcfile: $rcFile"); | ||
688 | if ( ! @processes) { # IF there are no processes we don't neet to perform a "stop" | ||
689 | &B_set_rc($rcVariable, "0", $configfile); | ||
690 | } else { | ||
691 | if ( $orig_value !~ "1" ) { #If param is not already 1, the "stop" script won't work | ||
692 | &B_set_rc($rcVariable, "1",$configfile); | ||
693 | } | ||
694 | &B_System ($startup_script . " stop", #stop service, then restart if the user runs bastille -r | ||
695 | $startup_script . " start"); | ||
696 | # set parameter, so that service will stay off after reboots | ||
697 | &B_set_rc($rcVariable, "0", $configfile); | ||
698 | } | ||
699 | } | ||
700 | } | ||
701 | |||
702 | |||
703 | # This routine sets a value in a given file | ||
704 | sub B_set_value($$$) { | ||
705 | my ($param, $value, $file)=@_; | ||
706 | |||
707 | &B_log("DEBUG","B_set_value: $param, $value, $file"); | ||
708 | if (! -e $file ) { | ||
709 | &B_create_file("$file"); | ||
710 | } | ||
711 | |||
712 | # If a value is already set to something other than $value then reset it. | ||
713 | #Note that though this tests for "$value ="the whole line gets replaced, so | ||
714 | #any pre-existing values are also replaced. | ||
715 | &B_replace_line($file,"^$param\\s*=\\s*","$param=$value\n"); | ||
716 | # If the value is not already set to something then set it. | ||
717 | &B_append_line($file,"^$param\\s*=\\s*$value","$param=$value\n"); | ||
718 | |||
719 | } | ||
720 | |||
721 | |||
722 | ################################################################################## | ||
723 | # &B_chperm($owner,$group,$mode,$filename(s)) | ||
724 | # This function changes ownership and mode of a list of files. Takes four | ||
725 | # arguments first the owner next the group and third the new mode in oct and | ||
726 | # last a list of files that the permissions changes should take affect on. | ||
727 | # | ||
728 | # uses: &swmodify and &B_revert_log | ||
729 | ################################################################################## | ||
730 | sub B_chperm($$$$) { | ||
731 | my ($newown, $newgrp, $newmode, $file_expr) = @_; | ||
732 | my @files = glob($file_expr); | ||
733 | |||
734 | my $return = 1; | ||
735 | |||
736 | foreach my $file (@files){ | ||
737 | my @filestat = stat $file; | ||
738 | my $oldmode = (($filestat[2]/512) % 8) . | ||
739 | (($filestat[2]/64) % 8) . | ||
740 | (($filestat[2]/8) % 8) . | ||
741 | (($filestat[2]) % 8); | ||
742 | |||
743 | if((chown $newown, $newgrp, $file) != 1 ){ | ||
744 | &B_log("ERROR","Could not change ownership of $file to $newown:$newgrp\n"); | ||
745 | $return = 0; | ||
746 | } | ||
747 | else{ | ||
748 | &B_log("ACTION","Changed ownership of $file to $newown:$newgrp\n"); | ||
749 | # swmodifying file if possible... | ||
750 | &B_swmodify($file); | ||
751 | &B_revert_log(&getGlobal('BIN',"chown") . " $filestat[4]:$filestat[5] $file\n"); | ||
752 | } | ||
753 | |||
754 | my $newmode_formatted=sprintf "%5lo",$newmode; | ||
755 | |||
756 | if((chmod $newmode, $file) != 1){ | ||
757 | &B_log("ERROR","Could not change mode of $file to $newmode_formatted\n"); | ||
758 | $return = 0; | ||
759 | } | ||
760 | else{ | ||
761 | &B_log("ACTION","Changed mode of $file to $newmode_formatted\n"); | ||
762 | &B_revert_log(&getGlobal('BIN',"chmod") . " $oldmode $file\n"); | ||
763 | } | ||
764 | |||
765 | |||
766 | } | ||
767 | return $return; | ||
768 | } | ||
769 | |||
770 | ############################################################################ | ||
771 | # &B_install_jail($jailname, $jailconfigfile); | ||
772 | # This function takes two arguments ( jail_name, jail_config ) | ||
773 | # It's purpose is to take read in config files that define a | ||
774 | # chroot jail and then generate it bases on that specification | ||
775 | ############################################################################ | ||
776 | sub B_install_jail($$) { | ||
777 | |||
778 | my $jailName = $_[0]; # Name of the jail e.g bind | ||
779 | my $jailConfig = $_[1]; # Name of the jails configuration file | ||
780 | # create the root directory of the jail if it does not exist | ||
781 | &B_create_dir( &getGlobal('BDIR','jail')); | ||
782 | &B_chperm(0,0,0555,&getGlobal('BDIR','jail')); | ||
783 | |||
784 | # create the Jail dir if it does not exist | ||
785 | &B_create_dir( &getGlobal('BDIR','jail') . "/" . $jailName); | ||
786 | &B_chperm(0,0,0555,&getGlobal('BDIR','jail') . "/". $jailName); | ||
787 | |||
788 | |||
789 | my $jailPath = &getGlobal('BDIR','jail') . "/" . $jailName; | ||
790 | my @lines; # used to store no commented no empty config file lines | ||
791 | # open configuration file for desired jail and parse in commands | ||
792 | if(open(JAILCONFIG,"< $jailConfig")) { | ||
793 | while(my $line=<JAILCONFIG>){ | ||
794 | if($line !~ /^\s*\#|^\s*$/){ | ||
795 | chomp $line; | ||
796 | push(@lines,$line); | ||
797 | } | ||
798 | } | ||
799 | close JAILCONFIG; | ||
800 | } | ||
801 | else{ | ||
802 | &B_log("ERROR","Open Failed on filename: $jailConfig\n"); | ||
803 | return 0; | ||
804 | } | ||
805 | # read through commands and execute | ||
806 | foreach my $line (@lines){ | ||
807 | &B_log("ACTION","Install jail: $line\n"); | ||
808 | my @confCmd = split /\s+/,$line; | ||
809 | if($confCmd[0] =~ /dir/){ # if the command say to add a directory | ||
810 | if($#confCmd == 4) { # checking dir Cmd form | ||
811 | if(! (-d $jailPath . "/" . $confCmd[1])){ | ||
812 | #add a directory and change its permissions according | ||
813 | #to the conf file | ||
814 | &B_create_dir( $jailPath . "/" . $confCmd[1]); | ||
815 | &B_chperm((getpwnam($confCmd[3]))[2], | ||
816 | (getgrnam($confCmd[4]))[2], | ||
817 | oct($confCmd[2]), | ||
818 | $jailPath . "/" . $confCmd[1]); | ||
819 | } | ||
820 | } | ||
821 | else { | ||
822 | &B_log("ERROR","Badly Formed Configuration Line:\n$line\n\n"); | ||
823 | } | ||
824 | } | ||
825 | elsif($confCmd[0] =~ /file/) { | ||
826 | if($#confCmd == 5) { # checking file cmd form | ||
827 | if(&B_cp($confCmd[1],$jailPath . "/" . $confCmd[2])){ | ||
828 | # for copy command cp file and change perms | ||
829 | &B_chperm($confCmd[4],$confCmd[5],oct($confCmd[3]),$jailPath . "/" . $confCmd[2]); | ||
830 | } | ||
831 | else { | ||
832 | &B_log("ERROR","Could not complete copy on specified files:\n" . | ||
833 | "$line\n"); | ||
834 | } | ||
835 | } | ||
836 | else { | ||
837 | &B_log("ERROR","Badly Formed Configuration Line:\n" . | ||
838 | "$line\n\n"); | ||
839 | } | ||
840 | } | ||
841 | elsif($confCmd[0] =~ /slink/) { | ||
842 | if($#confCmd == 2) { # checking file cmd form | ||
843 | if(!(-e $jailPath . "/" . $confCmd[2])){ | ||
844 | #for symlink command create the symlink | ||
845 | &B_symlink($jailPath . "/" . $confCmd[1], $confCmd[2]); | ||
846 | } | ||
847 | } | ||
848 | else { | ||
849 | &B_log("ERROR","Badly Formed Configuration Line:\n" . | ||
850 | "$line\n\n"); | ||
851 | } | ||
852 | } | ||
853 | else { | ||
854 | &B_log("ERROR","Unrecognized Configuration Line:\n" . | ||
855 | "$line\n\n"); | ||
856 | } | ||
857 | } | ||
858 | return 1; | ||
859 | } | ||
860 | |||
861 | |||
862 | |||
863 | ########################################################################### | ||
864 | # &B_list_processes($service) # | ||
865 | # # | ||
866 | # This subroutine uses the GLOBAL_PROCESS hash to determine if a # | ||
867 | # service's corresponding processes are running on the system. # | ||
868 | # If any of the processes are found to be running then the process # | ||
869 | # name(s) is/are returned by this subroutine in the form of an list # | ||
870 | # If none of the processes that correspond to the service are running # | ||
871 | # then an empty list is returned. # | ||
872 | ########################################################################### | ||
873 | sub B_list_processes($) { | ||
874 | |||
875 | # service name | ||
876 | my $service = $_[0]; | ||
877 | # list of processes related to the service | ||
878 | my @processes=@{ &getGlobal('PROCESS',$service)}; | ||
879 | |||
880 | # current systems process information | ||
881 | my $ps = &getGlobal('BIN',"ps"); | ||
882 | my $psTable = `$ps -elf`; | ||
883 | |||
884 | # the list to be returned from the function | ||
885 | my @running_processes; | ||
886 | |||
887 | # for every process associated with the service | ||
888 | foreach my $process (@processes) { | ||
889 | # if the process is in the process table then | ||
890 | if($psTable =~ m/$process/) { | ||
891 | # add the process to the list, which will be returned | ||
892 | push @running_processes, $process; | ||
893 | } | ||
894 | |||
895 | } | ||
896 | |||
897 | # return the list of running processes | ||
898 | return @running_processes; | ||
899 | |||
900 | } | ||
901 | |||
902 | ############################################################################# | ||
903 | # &B_list_full_processes($service) # | ||
904 | # # | ||
905 | # This subroutine simply grep through the process table for those matching # | ||
906 | # the input argument TODO: Allow B_list process to levereage this code # | ||
907 | # ... Not done this cycle to avoid release risk (late in cycle) # | ||
908 | ############################################################################# | ||
909 | sub B_list_full_processes($) { | ||
910 | |||
911 | # service name | ||
912 | my $procName = $_[0]; | ||
913 | my $ps = &getGlobal('BIN',"ps"); | ||
914 | my @psTable = split(/\n/,`$ps -elf`); | ||
915 | |||
916 | # for every process associated with the service | ||
917 | my @runningProcessLines = grep(/$procName/ , @psTable); | ||
918 | # return the list of running processes | ||
919 | return @runningProcessLines; | ||
920 | } | ||
921 | |||
922 | ################################################################################ | ||
923 | # &B_deactivate_inetd_service($service); # | ||
924 | # # | ||
925 | # This subroutine will disable all inetd services associated with the input # | ||
926 | # service name. Service name must be a reference to the following hashes # | ||
927 | # GLOBAL_SERVICE GLOBAL_SERVTYPE and GLOBAL_PROCESSES. If processes are left # | ||
928 | # running it will note these services in the TODO list as well as instruct the# | ||
929 | # user in how they remaining processes can be disabled. # | ||
930 | ################################################################################ | ||
931 | sub B_deactivate_inetd_service($) { | ||
932 | my $service = $_[0]; | ||
933 | my $servtype = &getGlobal('SERVTYPE',"$service"); | ||
934 | my $inetd_conf = &getGlobal('FILE',"inetd.conf"); | ||
935 | |||
936 | # check the service type to ensure that it can be configured by this subroutine. | ||
937 | if($servtype ne 'inet') { | ||
938 | &B_log("ACTION","The service \"$service\" is not an inet service so it cannot be\n" . | ||
939 | "configured by this subroutine\n"); | ||
940 | return 0; | ||
941 | } | ||
942 | |||
943 | # check for the inetd configuration files existence so it may be configured by | ||
944 | # this subroutine. | ||
945 | if(! -e $inetd_conf ) { | ||
946 | &B_log("ACTION","The file \"$inetd_conf\" cannot be located.\n" . | ||
947 | "Unable to configure inetd\n"); | ||
948 | return 0; | ||
949 | } | ||
950 | |||
951 | # list of service identifiers present in inetd.conf file. | ||
952 | my @inetd_entries = @{ &getGlobal('SERVICE',"$service") }; | ||
953 | |||
954 | foreach my $inetd_entry (@inetd_entries) { | ||
955 | &B_hash_comment_line($inetd_conf, "^\\s*$inetd_entry"); | ||
956 | } | ||
957 | |||
958 | # list of processes associated with this service which are still running | ||
959 | # on the system | ||
960 | my @running_processes = &B_list_processes($service); | ||
961 | |||
962 | if($#running_processes >= 0) { | ||
963 | my $todoString = "\n" . | ||
964 | "---------------------------------------\n" . | ||
965 | "Deactivating Inetd Service: $service\n" . | ||
966 | "---------------------------------------\n" . | ||
967 | "The following process(es) are associated with the inetd service \"$service\".\n" . | ||
968 | "They are most likely associated with a session which was initiated prior to\n" . | ||
969 | "running Bastille. To disable a process see \"kill(1)\" man pages or reboot\n" . | ||
970 | "the system\n" . | ||
971 | "Active Processes:\n" . | ||
972 | "###################################\n"; | ||
973 | foreach my $running_process (@running_processes) { | ||
974 | $todoString .= "\t$running_process\n"; | ||
975 | } | ||
976 | $todoString .= "###################################\n"; | ||
977 | |||
978 | &B_TODO($todoString); | ||
979 | } | ||
980 | |||
981 | } | ||
982 | |||
983 | |||
984 | ################################################################################ | ||
985 | # B_get_rc($key); # | ||
986 | # # | ||
987 | # This subroutine will use the ch_rc binary to get rc.config.d variables # | ||
988 | # values properly escaped and quoted. # | ||
989 | ################################################################################ | ||
990 | sub B_get_rc($) { | ||
991 | |||
992 | my $key=$_[0]; | ||
993 | my $ch_rc = &getGlobal('BIN',"ch_rc"); | ||
994 | |||
995 | # get the current value of the given parameter. | ||
996 | my $currentValue=`$ch_rc -l -p $key`; | ||
997 | chomp $currentValue; | ||
998 | |||
999 | if(($? >> 8) == 0 ) { | ||
1000 | # escape all meta characters. | ||
1001 | # $currentValue =~ s/([\"\`\$\\])/\\$1/g; | ||
1002 | # $currentValue = '"' . $currentValue . '"'; | ||
1003 | } | ||
1004 | else { | ||
1005 | return undef; | ||
1006 | } | ||
1007 | |||
1008 | return $currentValue; | ||
1009 | } | ||
1010 | |||
1011 | |||
1012 | |||
1013 | ################################################################################ | ||
1014 | # B_set_rc($key,$value); # | ||
1015 | # # | ||
1016 | # This subroutine will use the ch_rc binary to set rc.config.d variables. As # | ||
1017 | # well as setting the variable this subroutine will set revert strings. # | ||
1018 | # # | ||
1019 | ################################################################################ | ||
1020 | sub B_set_rc($$;$) { | ||
1021 | |||
1022 | my ($key,$value,$configfile)=@_; | ||
1023 | my $ch_rc = &getGlobal('BIN',"ch_rc"); | ||
1024 | |||
1025 | # get the current value of the given parameter. | ||
1026 | my $currentValue=&B_get_rc($key); | ||
1027 | if(defined $currentValue ) { | ||
1028 | if ($currentValue =~ /^\"(.*)\"$/ ) { | ||
1029 | $currentValue = '"\"' . $1 . '\""'; | ||
1030 | } | ||
1031 | if ($value =~ /^\"(.*)\"$/ ) { | ||
1032 | $value = '"\"' . $1 . '\""'; | ||
1033 | } | ||
1034 | if ( &B_System("$ch_rc -a -p $key=$value $configfile", | ||
1035 | "$ch_rc -a -p $key=$currentValue $configfile") ) { | ||
1036 | #ch_rc success | ||
1037 | return 1; | ||
1038 | } | ||
1039 | else { | ||
1040 | #ch_rc failure. | ||
1041 | return 0; | ||
1042 | } | ||
1043 | } | ||
1044 | else { | ||
1045 | &B_log("ERROR","ch_rc was unable to lookup $key\n"); | ||
1046 | return 0; | ||
1047 | } | ||
1048 | |||
1049 | } | ||
1050 | |||
1051 | |||
1052 | ################################################################################ | ||
1053 | # &ChrootHPApache($chrootScript,$httpd_conf,$httpd_bin, | ||
1054 | # $apachectl,$apacheJailDir,$serverString); | ||
1055 | # | ||
1056 | # This subroutine given an chroot script, supplied by the vendor, a | ||
1057 | # httpd.conf file, the binary location of httpd, the control script, | ||
1058 | # the jail directory, and the servers identification string, descriptive | ||
1059 | # string for TODO etc. It makes modifications to httpd.conf so that when | ||
1060 | # Apache starts it will chroot itself into the jail that the above | ||
1061 | # mentions script creates. | ||
1062 | # | ||
1063 | # uses B_replace_line B_create_dir B_System B_TODO | ||
1064 | # | ||
1065 | ############################################################################### | ||
1066 | sub B_chrootHPapache($$$$$$) { | ||
1067 | |||
1068 | my ($chrootScript,$httpd_conf,$httpd_bin,$apachectl,$apacheJailDir,$serverString)= @_; | ||
1069 | |||
1070 | my $exportpath = "export PATH=/usr/bin;"; | ||
1071 | my $ps = &getGlobal('BIN',"ps"); | ||
1072 | my $isRunning = 0; | ||
1073 | my $todo_header = 0; | ||
1074 | |||
1075 | # checking for a 2.0 version of the apache chroot script. | ||
1076 | if(-e $chrootScript ) { | ||
1077 | |||
1078 | if(open HTTPD, $httpd_conf) { | ||
1079 | while (my $line = <HTTPD>){ | ||
1080 | if($line =~ /^\s*Chroot/) { | ||
1081 | &B_log("DEBUG","Apache is already running in a chroot as specified by the following line:\n$line\n" . | ||
1082 | "which appears in the httpd.conf file. No Apache Chroot action was taken.\n"); | ||
1083 | return; | ||
1084 | } | ||
1085 | } | ||
1086 | close(HTTPD); | ||
1087 | } | ||
1088 | |||
1089 | if(`$ps -ef` =~ $httpd_bin ) { | ||
1090 | $isRunning=1; | ||
1091 | &B_System("$exportpath " . $apachectl . " stop","$exportpath " . $apachectl . " start"); | ||
1092 | } | ||
1093 | &B_replace_line($httpd_conf, '^\s*#\s*Chroot' , | ||
1094 | "Chroot " . $apacheJailDir); | ||
1095 | if(-d &getGlobal('BDIR',"jail")){ | ||
1096 | &B_log("DEBUG","Jail directory already exists. No action taken.\n"); | ||
1097 | } | ||
1098 | else{ | ||
1099 | &B_log("ACTION","Jail directory was created.\n"); | ||
1100 | &B_create_dir( &getGlobal('BDIR','jail')); | ||
1101 | } | ||
1102 | |||
1103 | if(-d $apacheJailDir){ | ||
1104 | &B_log("DEBUG","$serverString jail already exists. No action taken.\n"); | ||
1105 | } | ||
1106 | else{ | ||
1107 | &B_System(&getGlobal('BIN',"umask") . " 022; $exportpath " . $chrootScript, | ||
1108 | &getGlobal('BIN',"echo") . " \"Your $serverString is now running outside of it's\\n" . | ||
1109 | "chroot jail. You must manually migrate your web applications\\n" . | ||
1110 | "back to your Apache server's httpd.conf defined location(s).\\n". | ||
1111 | "After you have completed this, feel free to remove the jail directories\\n" . | ||
1112 | "from your machine. Your apache jail directory is located in\\n" . | ||
1113 | &getGlobal('BDIR',"jail") . "\\n\" >> " . &getGlobal('BFILE',"TOREVERT")); | ||
1114 | |||
1115 | } | ||
1116 | if($isRunning){ | ||
1117 | &B_System("$exportpath " . $apachectl . " start","$exportpath " . $apachectl . " stop"); | ||
1118 | &B_log("ACTION","$serverString is now running in an chroot jail.\n"); | ||
1119 | } | ||
1120 | |||
1121 | &B_log("ACTION","The jail is located in " . $apacheJailDir . "\n"); | ||
1122 | |||
1123 | if ($todo_header !=1){ | ||
1124 | &B_TODO("\n---------------------------------\nApache Chroot:\n" . | ||
1125 | "---------------------------------\n"); | ||
1126 | } | ||
1127 | &B_TODO("$serverString Chroot Jail:\n" . | ||
1128 | "httpd.conf contains the Apache dependencies. You should\n" . | ||
1129 | "review this file to ensure that the dependencies made it\n" . | ||
1130 | "into the jail. Otherwise, you run a risk of your Apache server\n" . | ||
1131 | "not having access to all its modules and functionality.\n"); | ||
1132 | |||
1133 | |||
1134 | } | ||
1135 | |||
1136 | } | ||
1137 | |||
1138 | |||
1139 | sub isSystemTrusted { | ||
1140 | my $getprdef = &getGlobal('BIN',"getprdef"); | ||
1141 | my $definition = &B_Backtick("$getprdef -t 2>&1"); | ||
1142 | if($definition =~ "System is not trusted.") { | ||
1143 | return 0; | ||
1144 | } else { | ||
1145 | return 1; | ||
1146 | } | ||
1147 | } | ||
1148 | |||
1149 | |||
1150 | sub isTrustedMigrationAvailable { | ||
1151 | my $distroVersion=''; | ||
1152 | |||
1153 | if (&GetDistro =~ '^HP-UX11.(\d*)') { | ||
1154 | $distroVersion=$1; | ||
1155 | if ($distroVersion < 23) { # Not available before 11.23 | ||
1156 | return 0; #FALSE | ||
1157 | } elsif ($distroVersion >= 31) { #Bundled with 11.31 and after | ||
1158 | &B_log('DEBUG','isTrustedMigrationAvailable: HP-UX 11.31 always has trusted mode extensions'); | ||
1159 | return 1; | ||
1160 | } elsif ($distroVersion == 23) { # Optional on 11.23 if filesets installed | ||
1161 | if ( -x &getGlobal('BIN',"userdbget") ) { | ||
1162 | &B_log('DEBUG','isTrustedMigrationAvailable: Trusted Extensions Installed'); | ||
1163 | return 1; | ||
1164 | } else { | ||
1165 | &B_log('DEBUG','isTrustedMigrationAvailable: Trusted Extensions Not Installed'); | ||
1166 | return 0; #FALSE | ||
1167 | } | ||
1168 | } else { | ||
1169 | &B_log('DEBUG','isTrustedMigrationAvailable: ' . &GetDistro . | ||
1170 | ' not currently supported for trusted extentions.'); | ||
1171 | return 0; #FALSE | ||
1172 | } | ||
1173 | } else { | ||
1174 | &B_log('WARNING','isTrustedMigrationAvailable: HP-UX routine called on Linux system'); | ||
1175 | return 0; #FALSE | ||
1176 | } | ||
1177 | } | ||
1178 | |||
1179 | |||
1180 | |||
1181 | ########################################################################### | ||
1182 | # &checkServiceOnHPUX($service); | ||
1183 | # | ||
1184 | # Checks if the given service is running on an HP/UX system. This is | ||
1185 | # called by B_is_Service_Off(), which is the function that Bastille | ||
1186 | # modules should call. | ||
1187 | # | ||
1188 | # Return values: | ||
1189 | # NOTSECURE_CAN_CHANGE() if the service is on | ||
1190 | # SECURE_CANT_CHANGE() if the service is off | ||
1191 | # INCONSISTENT() if the state of the service cannot be determined | ||
1192 | # NOT_INSTALLED() if the s/w isn't insalled | ||
1193 | # | ||
1194 | ########################################################################### | ||
1195 | sub checkServiceOnHPUX($) { | ||
1196 | my $service=$_[0]; | ||
1197 | |||
1198 | # get the list of parameters which could be used to initiate the service | ||
1199 | # (could be in /etc/rc.config.d, /etc/inetd.conf, or /etc/inittab, so we | ||
1200 | # check all of them) | ||
1201 | my @params= @{ &getGlobal('SERVICE',$service) }; | ||
1202 | my $grep =&getGlobal('BIN', 'grep'); | ||
1203 | my $inetd=&getGlobal('FILE', 'inetd.conf'); | ||
1204 | my $inittab=&getGlobal('FILE', 'inittab'); | ||
1205 | my $retVals; | ||
1206 | my $startup=&getGlobal('DIR','initd') ; | ||
1207 | my @inet_bins= @{ &getGlobal('PROCESS',$service) }; | ||
1208 | |||
1209 | my $entry_found = 0; | ||
1210 | |||
1211 | &B_log("DEBUG","CheckHPUXservice: $service"); | ||
1212 | my $full_initd_path = $startup . "/" . $service; | ||
1213 | if ($GLOBAL_SERVTYPE{$service} eq "rc") { # look for the init script in /sbin/init.d | ||
1214 | if (not(-e $full_initd_path )) { | ||
1215 | return NOT_INSTALLED(); | ||
1216 | } | ||
1217 | } else { #inet-based service, so look for inetd.conf entries. | ||
1218 | &B_log("DEBUG","Checking inet service $service"); | ||
1219 | my @inet_entries= @{ &getGlobal('SERVICE',$service) }; | ||
1220 | foreach my $service (@inet_entries) { | ||
1221 | &B_log('DEBUG',"Checking for inetd.conf entry of $service in checkService on HPUX"); | ||
1222 | my $service_regex = '^[#\s]*' . $service . '\s+'; | ||
1223 | if ( &B_match_line($inetd, $service_regex) ) { # inet entry search | ||
1224 | &B_log('DEBUG',"$service present, entry exists"); | ||
1225 | $entry_found = 1 ; | ||
1226 | } | ||
1227 | } | ||
1228 | if ($entry_found == 0 ) { | ||
1229 | return NOT_INSTALLED(); | ||
1230 | } | ||
1231 | } | ||
1232 | |||
1233 | foreach my $param (@params) { | ||
1234 | &B_log("DEBUG","Checking to see if service $service is off.\n"); | ||
1235 | if (&getGlobal('SERVTYPE', $service) =~ /rc/) { | ||
1236 | my $ch_rc=&getGlobal('BIN', 'ch_rc'); | ||
1237 | my $on=&B_Backtick("$ch_rc -l -p $param"); | ||
1238 | |||
1239 | $on =~ s/\s*\#.*$//; # remove end-of-line comments | ||
1240 | $on =~ s/^\s*\"(.+)\"\s*$/$1/; # remove surrounding double quotes | ||
1241 | $on =~ s/^\s*\'(.+)\'\s*$/$1/; # remove surrounding single quotes | ||
1242 | $on =~ s/^\s*\"(.+)\"\s*$/$1/; # just in case someone did '"blah blah"' | ||
1243 | |||
1244 | chomp $on; | ||
1245 | &B_log("DEBUG","ch_rc returned: $param=$on in checkServiceOnHPUX"); | ||
1246 | |||
1247 | if ($on =~ /^\d+$/ && $on != 0) { | ||
1248 | # service is on | ||
1249 | &B_log("DEBUG","CheckService found $param service is set to \'on\' in scripts."); | ||
1250 | return NOTSECURE_CAN_CHANGE(); | ||
1251 | } | ||
1252 | elsif($on =~ /^\s*$/) { | ||
1253 | # if the value returned is an empty string return | ||
1254 | # INCONSISTENT(), since we don't know what the hard-coded default is. | ||
1255 | return INCONSISTENT(); | ||
1256 | } | ||
1257 | } else { | ||
1258 | # those files which rely on comments to determine what gets | ||
1259 | # turned on, such as inetd.conf and inittab | ||
1260 | my $inettabs=&B_Backtick("$grep -e '^[[:space:]]*$param' $inetd $inittab"); | ||
1261 | if ($inettabs =~ /.+/) { # . matches anything except newlines | ||
1262 | # service is not off | ||
1263 | &B_log("DEBUG","Checking inetd.conf and inittab; found $inettabs"); | ||
1264 | ########################### BREAK out, don't skip question | ||
1265 | return NOTSECURE_CAN_CHANGE(); | ||
1266 | } | ||
1267 | } | ||
1268 | } # foreach $param | ||
1269 | |||
1270 | # boot-time parameters are not set; check processes | ||
1271 | # checkprocs for services returns INCONSISTENT() if a service is found | ||
1272 | # since a found-service is inconsistent with the above checks. | ||
1273 | B_log("DEBUG","Boot-Parameters not set, checking processes."); | ||
1274 | if (&runlevel < 2) { # Below runlevel 2, it is unlikely that | ||
1275 | #services will be running, so just check "on-disk" state | ||
1276 | &B_log("NOTE","Running during boot sequence, so skipping process checks"); | ||
1277 | return SECURE_CANT_CHANGE(); | ||
1278 | } else { | ||
1279 | return &checkProcsForService($service); | ||
1280 | } | ||
1281 | } | ||
1282 | |||
1283 | sub runlevel { | ||
1284 | my $who = &getGlobal("BIN", "who"); | ||
1285 | my $runlevel = &B_Backtick("$who -r"); | ||
1286 | if ($runlevel =~ s/.* run-level (\S).*/$1/) { | ||
1287 | &B_log("DEBUG","Runlevel is: $runlevel"); | ||
1288 | return $runlevel; | ||
1289 | } else { | ||
1290 | &B_log("WARNING","Can not determine runlevel, assuming runlevel 3"); | ||
1291 | &B_log("DEBUG","Runlevel command output: $runlevel"); | ||
1292 | return "3"; #safer since the who command didn't work, we'll assume | ||
1293 | # runlevel 3 since that provides more checks. | ||
1294 | } | ||
1295 | } | ||
1296 | |||
1297 | # | ||
1298 | # given a profile file, it will return a PATH array set by the file. | ||
1299 | # | ||
1300 | sub B_get_path($) { | ||
1301 | my $file = $_[0]; | ||
1302 | my $sh = &getGlobal("BIN", "sh"); | ||
1303 | # use (``)[0] is becuase, signal 0 maybe trapped which will produce some stdout | ||
1304 | my $path = (`$sh -c '. $file 1>/dev/null 2>&1 < /dev/null ; echo \$PATH'`)[0]; | ||
1305 | my @path_arr = split(":", $path); | ||
1306 | my %tmp_path; | ||
1307 | my %path; | ||
1308 | for my $tmpdir (@path_arr) { | ||
1309 | chomp $tmpdir; | ||
1310 | if ($tmpdir ne "" && ! $tmp_path{$tmpdir}) { | ||
1311 | $tmp_path{$tmpdir}++; | ||
1312 | } | ||
1313 | } | ||
1314 | return keys %tmp_path; | ||
1315 | } | ||
1316 | |||
1317 | # Convert to trusted mode if it's not already | ||
1318 | sub convertToTrusted { | ||
1319 | &B_log("DEBUG","# sub convertToTrusted \n"); | ||
1320 | if( ! &isSystemTrusted) { | ||
1321 | |||
1322 | my ($ok, $message) = &isOKtoConvert; | ||
1323 | |||
1324 | my $ts_header="\n---------------------------------\nTrusted Systems:\n" . | ||
1325 | "---------------------------------\n"; | ||
1326 | |||
1327 | if ($ok) { | ||
1328 | # actually do the conversion | ||
1329 | if(&B_System(&getGlobal('BIN','tsconvert'), &getGlobal('BIN','tsconvert') . " -r")){ | ||
1330 | # adjust change times for user passwords to keep them valid | ||
1331 | # default is to expire them when converting to a trusted system, | ||
1332 | # which can be problematic, especially since some older versions of | ||
1333 | # SecureShell do not allow the user to change the password | ||
1334 | &B_System(&getGlobal('BIN','modprpw') . " -V", ""); | ||
1335 | |||
1336 | my $getprdef = &getGlobal('BIN','getprdef'); | ||
1337 | my $oldsettings = &B_Backtick("$getprdef -m lftm,exptm,mintm,expwarn,umaxlntr"); | ||
1338 | $oldsettings =~ s/ //g; | ||
1339 | |||
1340 | # remove password lifetime and increasing login tries so they | ||
1341 | # don't lock themselves out of the system entirely. | ||
1342 | # set default expiration time and the like. | ||
1343 | my $newsettings="lftm=0,exptm=0,mintm=0,expwarn=0,umaxlntr=10"; | ||
1344 | |||
1345 | &B_System(&getGlobal('BIN','modprdef') . " -m $newsettings", | ||
1346 | &getGlobal('BIN','modprdef') . " -m $oldsettings"); | ||
1347 | |||
1348 | &B_TODO($ts_header . | ||
1349 | "Your system has been converted to a trusted system.\n" . | ||
1350 | "You should review the security settings available on a trusted system.\n". | ||
1351 | "$message"); | ||
1352 | |||
1353 | # to get rid of "Cron: Your job did not contain a valid audit ID." | ||
1354 | # error, we re-read the crontab file after converting to trusted mode | ||
1355 | # Nothing is necessary in "revert" since we won't be in trusted mode | ||
1356 | # at that time. | ||
1357 | # crontab's errors can be spurious, and this will report an 'error' | ||
1358 | # of the crontab file is missing, so we send stderr to the bit bucket | ||
1359 | my $crontab = &getGlobal('BIN',"crontab"); | ||
1360 | &B_System("$crontab -l 2>/dev/null | $crontab",""); | ||
1361 | } | ||
1362 | |||
1363 | } else { | ||
1364 | &B_TODO($ts_header . $message); | ||
1365 | return 0; # not ok to convert, so we didn't | ||
1366 | } | ||
1367 | } | ||
1368 | else { | ||
1369 | &B_log("DEBUG","System is already in trusted mode, no action taken.\n"); | ||
1370 | return 1; | ||
1371 | } | ||
1372 | |||
1373 | # just to make sure | ||
1374 | if( &isSystemTrusted ) { | ||
1375 | return 1; | ||
1376 | } else { | ||
1377 | &B_log("ERROR","Trusted system conversion was unsuccessful for an unknown reason.\n" . | ||
1378 | " You may try using SAM/SMH to do the conversion instead of Bastille.\n"); | ||
1379 | return 0; | ||
1380 | } | ||
1381 | } | ||
1382 | |||
1383 | # isOKtoConvert - check for conflicts between current system state and trusted | ||
1384 | # mode | ||
1385 | # | ||
1386 | # Return values | ||
1387 | # 0 - conflict found, see message for details | ||
1388 | # 1 - no conflicts, see message for further instructions | ||
1389 | # | ||
1390 | sub isOKtoConvert { | ||
1391 | &B_log("DEBUG","# sub isOKtoConvert \n"); | ||
1392 | # initialize text for TODO instructions | ||
1393 | my $specialinstructions=" - convert to trusted mode\n"; | ||
1394 | |||
1395 | # These are somewhat out-of-place, but only affect the text of the message. | ||
1396 | # Each of these messages is repeated in a separate TODO item in the | ||
1397 | # appropriate subroutine. | ||
1398 | if (&getGlobalConfig("AccountSecurity","single_user_password") eq "Y") { | ||
1399 | if (&GetDistro =~ "^HP-UX11.(.*)" and $1<23 ) { | ||
1400 | $specialinstructions .= " - set a single user password\n"; | ||
1401 | } | ||
1402 | } | ||
1403 | |||
1404 | if (&getGlobalConfig("AccountSecurity","passwordpolicies") eq "Y") { | ||
1405 | $specialinstructions .= " - set trusted mode password policies\n"; | ||
1406 | } | ||
1407 | |||
1408 | if (&getGlobalConfig("AccountSecurity", "PASSWORD_HISTORY_DEPTHyn") eq "Y") { | ||
1409 | $specialinstructions .= " - set a password history depth\n"; | ||
1410 | } | ||
1411 | |||
1412 | if (&getGlobalConfig("AccountSecurity","system_auditing") eq "Y") { | ||
1413 | $specialinstructions .= " - enable auditing\n"; | ||
1414 | } | ||
1415 | |||
1416 | my $saminstructions= | ||
1417 | "The security settings can be modified by running SAM as follows:\n" . | ||
1418 | "# sam\n" . | ||
1419 | "Next, go to the \"Auditing and Security Area\" and review\n" . | ||
1420 | "each sub-section. Make sure that you review all of your\n" . | ||
1421 | "settings, as some policies may seem restrictive.\n\n" . | ||
1422 | "On systems using the System Management Homepage, you can\n". | ||
1423 | "change your settings via the Tools:Security Attributes Configuration\n". | ||
1424 | "section. On some systems, you may also have the option of using SMH.\n\n"; | ||
1425 | |||
1426 | # First, check for possible conflicts and corner cases | ||
1427 | |||
1428 | # check nsswitch for possible conflicts | ||
1429 | my $nsswitch = &getGlobal('FILE', 'nsswitch.conf'); | ||
1430 | if ( -e $nsswitch) { | ||
1431 | open(FILE, $nsswitch); | ||
1432 | while (<FILE>) { | ||
1433 | if (/nis/ or /compat/ or /ldap/) { | ||
1434 | my $message = "Bastille found a possible conflict between trusted mode and\n" . | ||
1435 | "$nsswitch. Please remove all references to\n" . | ||
1436 | "\"compat\", \"nis\" and \"ldap\" in $nsswitch\n" . | ||
1437 | "and rerun Bastille, or use SAM/SMH to\n" . | ||
1438 | "$specialinstructions\n". | ||
1439 | "$saminstructions"; | ||
1440 | close(FILE); | ||
1441 | return (0,$message); | ||
1442 | } | ||
1443 | } | ||
1444 | close(FILE); | ||
1445 | } | ||
1446 | |||
1447 | # check the namesvrs config file for possible NIS conflicts | ||
1448 | #Changed to unless "Y AND Y" since question can be skipped when nis is off | ||
1449 | # but corner cases can still exist, so check then too. | ||
1450 | unless ( &getGlobalConfig('MiscellaneousDaemons','nis_client') eq "Y" and | ||
1451 | &getGlobalConfig('MiscellaneousDaemons','nis_server') eq "Y" ) { | ||
1452 | my $namesvrs = &getGlobal('FILE', 'namesvrs'); | ||
1453 | if (open(FILE, $namesvrs)) { | ||
1454 | while (<FILE>) { | ||
1455 | if (/^NIS.*=["]?1["]?$/) { | ||
1456 | my $message= "Possible conflict between trusted mode and NIS found.\n". | ||
1457 | "Please use SAM/SMH to\n" . | ||
1458 | " - turn off NIS\n" . | ||
1459 | "$specialinstructions\n". | ||
1460 | "$saminstructions"; | ||
1461 | close(FILE); | ||
1462 | return (0,$message); | ||
1463 | } | ||
1464 | } | ||
1465 | close(FILE); | ||
1466 | } else { | ||
1467 | &B_log("ERROR","Unable to open $namesvrs for reading."); | ||
1468 | my $message= "Possible conflict between trusted mode and NIS found.\n". | ||
1469 | "Please use SAM/SMH to\n" . | ||
1470 | " - turn off NIS\n" . | ||
1471 | "$specialinstructions\n". | ||
1472 | "$saminstructions"; | ||
1473 | return (0,$message); | ||
1474 | } | ||
1475 | if ( &B_match_line (&getGlobal("FILE","passwd"),"^\+:.*")) { | ||
1476 | my $message= '"+" entry found in passwd file. These are not\n' . | ||
1477 | "compatible with Trusted Mode. Either remove the entries\n" . | ||
1478 | "and re-run Bastille, or re-run Bastille, and direct it to\n" . | ||
1479 | "disable NIS client and server.\n"; | ||
1480 | return (0,$message); | ||
1481 | } | ||
1482 | |||
1483 | } | ||
1484 | |||
1485 | |||
1486 | # check for conflicts with DCE integrated login | ||
1487 | my $authcmd = &getGlobal('BIN','auth.adm'); | ||
1488 | if ( -e $authcmd ) { | ||
1489 | my $retval = system("PATH=/usr/bin $authcmd -q 1>/dev/null 2>&1"); | ||
1490 | if ($retval != 0 and $retval != 1) { | ||
1491 | my $message="It appears that DCE integrated login is configured on this system.\n" . | ||
1492 | "DCE integrated login is incompatible with trusted systems and\n" . | ||
1493 | "auditing. Bastille is unable to\n" . | ||
1494 | "$specialinstructions" . | ||
1495 | "You will need to configure auditing and password policies using DCE.\n\n"; | ||
1496 | return (0,$message); | ||
1497 | } | ||
1498 | } | ||
1499 | |||
1500 | if ( -e &getGlobal('FILE','shadow') ) { | ||
1501 | my $message="This system has already been converted to shadow passwords.\n" . | ||
1502 | "Shadow passwords are incompatible with trusted mode.\n" . | ||
1503 | "Bastille is unable to\n" . | ||
1504 | "$specialinstructions" . | ||
1505 | "If you desire these features, you should use\n". | ||
1506 | "\'pwunconv\' to change back to standard passwords,\n". | ||
1507 | "and then rerun Bastille.\n\n"; | ||
1508 | return (0,$message); | ||
1509 | } | ||
1510 | |||
1511 | return (1,$saminstructions); | ||
1512 | } | ||
1513 | |||
1514 | # This routine allows Bastille to determine trusted-mode extension availability | ||
1515 | |||
1516 | sub convertToShadow { | ||
1517 | |||
1518 | if (&isSystemTrusted) { | ||
1519 | # This is an internal error...Bastille should not call this routine | ||
1520 | # in this case. Error is here for robustness against future changes. | ||
1521 | &B_log("ERROR","This system is already converted to trusted mode.\n" . | ||
1522 | " Converting to shadow passwords will not be attempted.\n"); | ||
1523 | return 0; | ||
1524 | } | ||
1525 | |||
1526 | # configuration files on which shadowed passwords depend | ||
1527 | my $nsswitch_conf = &getGlobal('FILE',"nsswitch.conf"); | ||
1528 | |||
1529 | # binaries used to convert to a shadowed password | ||
1530 | my $pwconv = &getGlobal('BIN',"pwconv"); | ||
1531 | my $echo = &getGlobal('BIN','echo'); # the echo is used to pipe a yes into the pwconv program as | ||
1532 | # pwconv requires user interaction. | ||
1533 | |||
1534 | # the binary used in a system revert. | ||
1535 | my $pwunconv = &getGlobal('BIN',"pwunconv"); | ||
1536 | #check the password file for nis usage and if the nis client | ||
1537 | #or server is running. | ||
1538 | if(-e $nsswitch_conf) { | ||
1539 | # check the file for nis, nis+, compat, or dce usage. | ||
1540 | if(&B_match_line($nsswitch_conf, '^\s*passwd:.+(nis|nisplus|dce|compat)')) { | ||
1541 | my $shadowTODO = "\n---------------------------------\nHide encrypted passwords:\n" . | ||
1542 | "---------------------------------\n" . | ||
1543 | "This version of password shadowing does not support any repository other\n" . | ||
1544 | "than files. In order to convert your password database to shadowed passwords\n" . | ||
1545 | "there can be no mention of nis, nisplus, compat, or dce in the passwd\n" . | ||
1546 | "field of the \"$nsswitch_conf\" file. Please make the necessary edits to\n" . | ||
1547 | "the $nsswitch_conf file and run Bastille again using the command:\n" . | ||
1548 | "\"bastille -b\"\n"; | ||
1549 | # Adding the shadowTODO comment to the TODO list. | ||
1550 | &B_TODO("$shadowTODO"); | ||
1551 | # Notifing the user that the shadowed password coversion has failed. | ||
1552 | &B_log("ERROR","Password Shadowing Conversion Failed\n" . | ||
1553 | "$shadowTODO"); | ||
1554 | # exiting the subroutine. | ||
1555 | return 0; | ||
1556 | } | ||
1557 | |||
1558 | } | ||
1559 | |||
1560 | # convert the password file to a shadowed repository. | ||
1561 | if (( -e $pwconv ) and ( -e $pwunconv ) and | ||
1562 | ( &B_System("$echo \"yes\" | $pwconv","$pwunconv") ) ){ | ||
1563 | &B_TODO( "\n---------------------------------\nShadowing Password File:\n" . | ||
1564 | "---------------------------------\n" . | ||
1565 | "Your password file has been converted to use password shadowing.\n" . | ||
1566 | "This version of password shadowing does not support any repository other\n" . | ||
1567 | "than files. There can be no mention of nis, nisplus, compat, or dce\n" . | ||
1568 | "in the passwd field of the \"$nsswitch_conf\" file.\n\n" ); | ||
1569 | } else { | ||
1570 | &B_log("ERROR","Conversion to shadow mode failed. The system may require ". | ||
1571 | "a patch to be capable of switching to shadow mode, or the ". | ||
1572 | "system my be in a state where conversion is not possible."); | ||
1573 | } | ||
1574 | } | ||
1575 | |||
1576 | |||
1577 | |||
1578 | ########################################################################## | ||
1579 | # &getSupportedSettings(); | ||
1580 | # Manipulates %trustedParameter and %isSupportedSetting, file-scoped variables | ||
1581 | # | ||
1582 | # Reads the password policy support matrix, which in-turn gives Bastille the | ||
1583 | # places it should look for a given password policy setting. | ||
1584 | |||
1585 | # Note the file was created like this so if could be maintained in an Excel(tm) | ||
1586 | # spreadsheet, to optimize reviewability. TODO: consider other formats | ||
1587 | |||
1588 | # File Format: | ||
1589 | # HEADERS:<comment>,[<OS Version> <Mode> <Extensions>,]... | ||
1590 | # [ | ||
1591 | # :<label>:<trusted equivalent>,,,,,,,,,,,,<comment> | ||
1592 | # <action> (comment), [<test value>,]... | ||
1593 | # ] ... | ||
1594 | # Example; | ||
1595 | # HEADERS:Information Source (trusted equiv),11.11 Standard no-SMSE,11.11 Trusted no-SMSE,11.11 Shadow no-SMSE,11.23 Standard no-SMSE,11.23 Trusted no-SMSE,11.23 Shadow no-SMSE,11.23 Standard SMSE,11.23 Shadow SMSE,11.23 Trusted SMSE,11.31 Trusted SMSE,11.31 Shadow SMSE,11.31 Standard SMSE,Other Exceptions | ||
1596 | #:ABORT_LOGIN_ON_MISSING_HOMEDIR,,,,,,,,,,,,,root | ||
1597 | #/etc/security.dsc (search),x,,xx,x,x,x,!,!,!,!,!,!, | ||
1598 | #/etc/default/security(search),y,y,y,y,y,y,y,y,y,y,y,y, | ||
1599 | #getprdef (execute with <Trusted Equiv> argument),x,x,x,x,x,x,x,x,x,x,x,x, | ||
1600 | |||
1601 | ########################################################################### | ||
1602 | our %trustedParameter = (); | ||
1603 | our %isSupportedSetting = (); | ||
1604 | |||
1605 | sub getSupportedSettings() { | ||
1606 | |||
1607 | my $line; # For a config file line | ||
1608 | my $linecount = 0; | ||
1609 | my $currentsetting = ""; | ||
1610 | my @fields; # Fields in a given line | ||
1611 | my @columns; #Column Definitions | ||
1612 | |||
1613 | |||
1614 | &B_open(*SETTINGSFILE,&getGlobal('BFILE','AccountSecSupport')); | ||
1615 | my @settingLines=<SETTINGSFILE>; | ||
1616 | &B_close(*SETTINGSFILE); | ||
1617 | |||
1618 | #Remove blank-lines and comments | ||
1619 | @settingLines = grep(!/^#/,@settingLines); | ||
1620 | @settingLines = grep(!/^(\s*,+)*$/,@settingLines); | ||
1621 | |||
1622 | foreach $line (@settingLines) { | ||
1623 | ++$linecount; | ||
1624 | @fields = split(/,/,$line); | ||
1625 | if ($line =~ /^Information Source:/) { #Sets up colums | ||
1626 | my $fieldcount = 1; #Skipping first field | ||
1627 | while ((defined($fields[$fieldcount])) and | ||
1628 | ($fields[$fieldcount] =~ /\d+\.\d+/)){ | ||
1629 | my @subfields = split(/ /,$fields[$fieldcount]); | ||
1630 | my $fieldsCount = @subfields; | ||
1631 | if ($fieldsCount != 3){ | ||
1632 | &B_log("ERROR","Invalid subfield count: $fieldsCount in:". | ||
1633 | &getGlobal('BFILE','AccountSecSupport') . | ||
1634 | " line: $linecount and field: $fieldcount"); | ||
1635 | } | ||
1636 | $columns[$fieldcount] = {OSVersion => $subfields[0], | ||
1637 | Mode => $subfields[1], | ||
1638 | Extension => $subfields[2] }; | ||
1639 | &B_log("DEBUG","Found Header Column, $columns[$fieldcount]{'OSVersion'}, ". | ||
1640 | $columns[$fieldcount]{'Mode'} ." , " . | ||
1641 | $columns[$fieldcount]{'Extension'}); | ||
1642 | ++$fieldcount; | ||
1643 | } # New Account Seting ex: | ||
1644 | } elsif ($line =~ /^:([^,:]+)(?::([^,]+))?/) { # :PASSWORD_WARNDAYS:expwarn,,,,,,,,,,,, | ||
1645 | $currentsetting = $1; | ||
1646 | if (defined($2)) { | ||
1647 | $trustedParameter{"$currentsetting"}=$2; | ||
1648 | } | ||
1649 | &B_log("DEBUG","Found Current Setting: ". $currentsetting . | ||
1650 | "/" . $trustedParameter{"$currentsetting"}); | ||
1651 | } elsif (($line =~ /(^[^, :\)\(]+)[^,]*,((?:(?:[!y?nx]|!!),)+)/) and #normal line w/ in setting ex: | ||
1652 | ($currentsetting ne "")){ # security.dsc (search),x,x,x,x,x,!,!!,!,!,!,!, | ||
1653 | my $placeToLook = $1; | ||
1654 | my $fieldcount = 1; #Skip the first one, which we used in last line | ||
1655 | while (defined($fields[$fieldcount])) { | ||
1656 | &B_log("DEBUG","Setting $currentsetting : $columns[$fieldcount]{OSVersion} , ". | ||
1657 | "$columns[$fieldcount]{Mode} , ". | ||
1658 | "$columns[$fieldcount]{Extension} , ". | ||
1659 | "$placeToLook, to $fields[$fieldcount]"); | ||
1660 | $isSupportedSetting{"$currentsetting"} | ||
1661 | {"$columns[$fieldcount]{OSVersion}"} | ||
1662 | {"$columns[$fieldcount]{Mode}"} | ||
1663 | {"$columns[$fieldcount]{Extension}"} | ||
1664 | {"$placeToLook"} = | ||
1665 | $fields[$fieldcount]; | ||
1666 | ++$fieldcount; | ||
1667 | } | ||
1668 | } else { | ||
1669 | if ($line !~ /^,*/) { | ||
1670 | &B_log("ERROR","Incorrectly Formatted Line at ". | ||
1671 | &getGlobal('BFILE','AccountSecSupport') . ": $linecount"); | ||
1672 | } | ||
1673 | } | ||
1674 | } | ||
1675 | } | ||
1676 | |||
1677 | ########################################################################## | ||
1678 | # &B_get_sec_value($param); | ||
1679 | # This subroutine finds the value for a given user policy parameter. | ||
1680 | # Specifically, it supports the parameters listed in the internal data structure | ||
1681 | |||
1682 | # Return values: | ||
1683 | # 'Not Defined' if the value is not present or not uniquely defined. | ||
1684 | # $value if the value is present and unique | ||
1685 | # | ||
1686 | ########################################################################### | ||
1687 | sub B_get_sec_value($) { | ||
1688 | my $param=$_[0]; | ||
1689 | |||
1690 | my $os_version; | ||
1691 | if (&GetDistro =~ /^HP-UX\D*(\d+\.\d+)/ ){ | ||
1692 | $os_version=$1; | ||
1693 | } else { | ||
1694 | &B_log("ERROR","B_get_sec_value only supported on HP-UX"); | ||
1695 | return undef; | ||
1696 | } | ||
1697 | # my $sec_dsc = &getGlobal('FILE', 'security.dsc'); | ||
1698 | my $sec_file = &getGlobal('FILE', 'security'); | ||
1699 | my $getprdef = &getGlobal('BIN','getprdef'); | ||
1700 | my $getprpw = &getGlobal('BIN','getprpw'); | ||
1701 | my $userdbget = &getGlobal('BIN','userdbget'); | ||
1702 | my $passwd = &getGlobal('BIN','passwd'); | ||
1703 | |||
1704 | my $sec_flags = ""; | ||
1705 | my @sec_settings=(); | ||
1706 | my $user_sec_setting=""; | ||
1707 | |||
1708 | my $security_mode="Standard"; | ||
1709 | my $security_extension="no-SMSE"; | ||
1710 | |||
1711 | &B_log("DEBUG","Entering get_sec_value for: $param"); | ||
1712 | |||
1713 | sub isok ($) { # Locally-scoped subroutine, takes supported-matrix entry as argument | ||
1714 | my $supportedMatrixEntry = $_[0]; | ||
1715 | |||
1716 | if ($supportedMatrixEntry =~ /!/) { #Matrix Entry for "Documented and/or tested" | ||
1717 | &B_log("DEBUG","isOk TRUE: $supportedMatrixEntry"); | ||
1718 | return 1; | ||
1719 | } else { | ||
1720 | &B_log("DEBUG","isOk FALSE: $supportedMatrixEntry"); | ||
1721 | return 0; #FALSE | ||
1722 | } | ||
1723 | } #end local subroutine | ||
1724 | |||
1725 | #Get Top Array item non-destructively | ||
1726 | sub getTop (@) { | ||
1727 | my @incomingArray = @_; | ||
1728 | my $topval = pop(@incomingArray); | ||
1729 | push(@incomingArray,$topval); #Probably redundant, but left in just in case. | ||
1730 | return $topval; | ||
1731 | } | ||
1732 | |||
1733 | sub ifExistsPushOnSecSettings($$) { | ||
1734 | my $sec_settings = $_[0]; | ||
1735 | my $pushval = $_[1]; | ||
1736 | |||
1737 | if ($pushval ne ""){ | ||
1738 | push (@$sec_settings, $pushval); | ||
1739 | } | ||
1740 | } | ||
1741 | |||
1742 | #prpw and prdef both use "YES" instead of "1" like the other settings. | ||
1743 | sub normalizePolicy($){ | ||
1744 | my $setting = $_[0]; | ||
1745 | |||
1746 | $setting =~ s/YES/1/; | ||
1747 | $setting =~ s/NO/1/; | ||
1748 | |||
1749 | return $setting; | ||
1750 | } | ||
1751 | |||
1752 | |||
1753 | |||
1754 | if ((%trustedParameter == ()) or (%isSupportedSetting == ())) { | ||
1755 | # Manipulates %trustedParameter and %isSupportedSetting | ||
1756 | &getSupportedSettings; | ||
1757 | } | ||
1758 | |||
1759 | #First determine the security mode | ||
1760 | my $shadowFile = &getGlobal("FILE","shadow"); | ||
1761 | my $passwdFile = &getGlobal("FILE","passwd"); | ||
1762 | |||
1763 | if (&isSystemTrusted) { | ||
1764 | $security_mode = 'Trusted'; | ||
1765 | } elsif ((-e $shadowFile) and #check file exist, and that passwd has no non-"locked" accounts | ||
1766 | (not(&B_match_line($passwdFile,'^[^\:]+:[^:]*[^:*x]')))) { | ||
1767 | $security_mode = 'Shadow'; | ||
1768 | } else { | ||
1769 | $security_mode = 'Standard'; | ||
1770 | } | ||
1771 | if (&isTrustedMigrationAvailable) { | ||
1772 | $security_extension = 'SMSE'; | ||
1773 | } else { | ||
1774 | $security_extension = 'no-SMSE'; | ||
1775 | } | ||
1776 | &B_log("DEBUG","Security mode: $security_mode extension: $security_extension"); | ||
1777 | # Now look up the value from each applicable database, from highest precedence | ||
1778 | # to lowest: | ||
1779 | &B_log("DEBUG","Checking $param in userdbget"); | ||
1780 | if (&isok($isSupportedSetting{$param}{$os_version}{$security_mode} | ||
1781 | {$security_extension}{"userdbget_-a"})) { | ||
1782 | &ifExistsPushOnSecSettings(\@sec_settings, | ||
1783 | &B_getValueFromString('\w+\s+\w+=(\S+)', | ||
1784 | &B_Backtick("$userdbget -a $param"))); | ||
1785 | &B_log("DEBUG", $param . ":userdbget setting: ". &getTop(@sec_settings)); | ||
1786 | } | ||
1787 | &B_log("DEBUG","Checking $param in passwd"); | ||
1788 | if (&isok($isSupportedSetting{$param}{$os_version}{$security_mode} | ||
1789 | {$security_extension}{"passwd_-sa"})) { | ||
1790 | if ($param eq "PASSWORD_MINDAYS") { | ||
1791 | &ifExistsPushOnSecSettings(\@sec_settings, | ||
1792 | &B_getValueFromString('(?:\w+\s+){2}[\d\/]+\s+(\d+)\s+\d+', | ||
1793 | &B_Backtick("$passwd -s -a"))); | ||
1794 | } elsif ($param eq "PASSWORD_MAXDAYS") { | ||
1795 | &ifExistsPushOnSecSettings(\@sec_settings, | ||
1796 | &B_getValueFromString('(?:\w+\s+){2}[\d\/]+\s+\d+\s+(\d+)', | ||
1797 | &B_Backtick("$passwd -s -a"))); | ||
1798 | } elsif ($param eq "PASSWORD_WARNDAYS") { | ||
1799 | &ifExistsPushOnSecSettings(\@sec_settings, | ||
1800 | &B_getValueFromString('(?:\w+\s+){2}[\d\/]+(?:\s+\d+){2}\s+(\d+)', | ||
1801 | &B_Backtick("$passwd -s -a"))); | ||
1802 | } | ||
1803 | &B_log("DEBUG", $param . ":passwd -sa setting: ". &getTop(@sec_settings)); | ||
1804 | } | ||
1805 | &B_log("DEBUG","Checking $param in get prpw"); | ||
1806 | if (&isok($isSupportedSetting{$param}{$os_version}{$security_mode} | ||
1807 | {$security_extension}{"getprpw"})) { | ||
1808 | my $logins = &getGlobal("BIN","logins"); | ||
1809 | my @userArray = split(/\n/,`$logins`); | ||
1810 | my $userParamVals = ''; | ||
1811 | foreach my $rawuser (@userArray) { | ||
1812 | $rawuser =~ /^(\S+)/; | ||
1813 | my $user = $1; | ||
1814 | my $nextParamVal=&B_Backtick("$getprpw -l -m $trustedParameter{$param} $user"); | ||
1815 | $nextParamVal =~ s/\w*=(-*[\w\d]*)/$1/; | ||
1816 | if ($nextParamVal != -1) { #Don't count users for which the local DB is undefined | ||
1817 | $userParamVals .= $user . "::::" . $nextParamVal ."\n"; | ||
1818 | } | ||
1819 | } #Note getValueFromStrings deals with duplicates, returning "Not Unigue" | ||
1820 | my $policySetting = &B_getValueFromString('::::(\S+)',"$userParamVals"); | ||
1821 | &ifExistsPushOnSecSettings (\@sec_settings, &normalizePolicy($policySetting)); | ||
1822 | &B_log("DEBUG", $param . ":prpw setting: ". &getTop(@sec_settings)); | ||
1823 | } | ||
1824 | &B_log("DEBUG","Checking $param in get prdef"); | ||
1825 | if (&isok($isSupportedSetting{$param}{$os_version}{$security_mode} | ||
1826 | {$security_extension}{"getprdef"})) { | ||
1827 | $_ = &B_Backtick ("$getprdef -m " . $trustedParameter{$param}); | ||
1828 | /\S+=(\S+)/; | ||
1829 | my $policySetting = $1; | ||
1830 | &ifExistsPushOnSecSettings(\@sec_settings, &normalizePolicy($policySetting)); | ||
1831 | &B_log("DEBUG", $param . ":prdef setting: ". &getTop(@sec_settings)); | ||
1832 | |||
1833 | } | ||
1834 | &B_log("DEBUG","Checking $param in default security"); | ||
1835 | if (&isok($isSupportedSetting{$param}{$os_version}{$security_mode} | ||
1836 | {$security_extension}{"/etc/default/security"})) { | ||
1837 | &ifExistsPushOnSecSettings(\@sec_settings,&B_getValueFromFile('^\s*'. $param . | ||
1838 | '\s*=\s*([^\s#]+)\s*$', $sec_file)); | ||
1839 | &B_log("DEBUG", $param . ":default setting: ". &getTop(@sec_settings)); | ||
1840 | } | ||
1841 | #Commented below code in 3.0 release to avoid implication that bastille | ||
1842 | #had ever set these values explicitly, and the implications to runnable | ||
1843 | #config files where Bastille would then apply the defaults as actual policy | ||
1844 | #with possible conversion to shadow or similar side-effect. | ||
1845 | |||
1846 | # &B_log("DEBUG","Checking $param in security.dsc"); | ||
1847 | #security.dsc, only added in if valid for OS/mode/Extension, and nothing else | ||
1848 | #is defined (ie: @sec_settings=0) | ||
1849 | # if ((&isok($isSupportedSetting{$param}{$os_version}{$security_mode} | ||
1850 | # {$security_extension}{"/etc/security.dsc"})) and (@sec_settings == 0)) { | ||
1851 | # &ifExistsPushOnSecSettings(\@sec_settings, &B_getValueFromFile('^' . $param . | ||
1852 | # ';(?:[-\w/]*;){2}([-\w/]+);', $sec_dsc)); | ||
1853 | # &B_log("DEBUG", $param . ":security.dsc: ". &getTop(@sec_settings)); | ||
1854 | # } | ||
1855 | |||
1856 | # Return what we found | ||
1857 | my $last_setting=undef; | ||
1858 | my $current_setting=undef; | ||
1859 | while (@sec_settings > 0) { | ||
1860 | $current_setting = pop(@sec_settings); | ||
1861 | &B_log("DEBUG","Comparing $param configuration for identity: " . | ||
1862 | $current_setting); | ||
1863 | if ((defined($current_setting)) and ($current_setting ne '')) { | ||
1864 | if (not(defined($last_setting))){ | ||
1865 | $last_setting=$current_setting; | ||
1866 | } elsif (($last_setting ne $current_setting) or | ||
1867 | ($current_setting eq 'Not Unique')){ | ||
1868 | &B_log("DEBUG","$param setting not unique."); | ||
1869 | return 'Not Unique'; # Inconsistent state found, return 'Not Unique' | ||
1870 | } | ||
1871 | } | ||
1872 | } | ||
1873 | if ((not(defined($last_setting))) or ($last_setting eq '')) { | ||
1874 | return undef; | ||
1875 | } else { | ||
1876 | return $last_setting; | ||
1877 | } | ||
1878 | |||
1879 | } #End B_get_sec_value | ||
1880 | |||
1881 | sub secureIfNoNameService($){ | ||
1882 | my $retval = $_[0]; | ||
1883 | |||
1884 | if (&isUsingRemoteNameService) { | ||
1885 | return MANUAL(); | ||
1886 | } else { | ||
1887 | return $retval; | ||
1888 | } | ||
1889 | } | ||
1890 | |||
1891 | #Specifically for cleartext protocols like NIS, which are not "secure" | ||
1892 | sub isUsingRemoteNameService(){ | ||
1893 | |||
1894 | if (&remoteServiceCheck('nis|nisplus|dce') == SECURE_CAN_CHANGE()){ | ||
1895 | return 0; #false | ||
1896 | } else { | ||
1897 | return 1; | ||
1898 | } | ||
1899 | } | ||
1900 | |||
1901 | |||
1902 | |||
1903 | ########################################### | ||
1904 | ## This is a wrapper for two functions that | ||
1905 | ## test the existence of nis-like configurations | ||
1906 | ## It is used by both the front end test and the back-end run | ||
1907 | ############################################## | ||
1908 | sub remoteServiceCheck($){ | ||
1909 | my $regex = $_[0]; | ||
1910 | |||
1911 | my $nsswitch_conf = &getGlobal('FILE',"nsswitch.conf"); | ||
1912 | my $passwd = &getGlobal('FILE',"passwd"); | ||
1913 | |||
1914 | # check the file for nis usage. | ||
1915 | if (-e $nsswitch_conf) { | ||
1916 | if (&B_match_line($nsswitch_conf, '^\s*passwd:.*('. $regex . ')')) { | ||
1917 | return NOTSECURE_CAN_CHANGE(); | ||
1918 | } elsif ((&B_match_line($nsswitch_conf, '^\s*passwd:.*(compat)')) and | ||
1919 | (&B_match_line($passwd, '^\s*\+'))) { | ||
1920 | return NOTSECURE_CAN_CHANGE(); # true | ||
1921 | } | ||
1922 | } elsif ((&B_match_line($passwd, '^\s*\+'))) { | ||
1923 | return NOTSECURE_CAN_CHANGE(); | ||
1924 | } | ||
1925 | |||
1926 | my $oldnisdomain=&B_get_rc("NIS_DOMAIN"); | ||
1927 | if ((($oldnisdomain eq "") or ($oldnisdomain eq '""')) and (&checkServiceOnHPUX('nis.client'))){ | ||
1928 | return SECURE_CAN_CHANGE(); | ||
1929 | } | ||
1930 | return NOTSECURE_CAN_CHANGE(); | ||
1931 | } | ||
1932 | |||
1933 | ############################################# | ||
1934 | # remoteNISPlusServiceCheck | ||
1935 | # test the existence of nis+ configuration | ||
1936 | ############################################# | ||
1937 | sub remoteNISPlusServiceCheck () { | ||
1938 | |||
1939 | my $nsswitch_conf = &getGlobal('FILE',"nsswitch.conf"); | ||
1940 | |||
1941 | # check the file for nis+ usage. | ||
1942 | if (-e $nsswitch_conf) { | ||
1943 | if (&B_match_line($nsswitch_conf, 'nisplus')) { | ||
1944 | return NOTSECURE_CAN_CHANGE(); | ||
1945 | } | ||
1946 | } | ||
1947 | |||
1948 | return &checkServiceOnHPUX('nisp.client'); | ||
1949 | } | ||
1950 | |||
1951 | |||
1952 | ########################################################################## | ||
1953 | # This subroutine creates nsswitch.conf file if the file not exists, | ||
1954 | # and then append serveral services into the file if the service not | ||
1955 | # exists in the file. | ||
1956 | ########################################################################## | ||
1957 | sub B_create_nsswitch_file ($) { | ||
1958 | my $regex = $_[0]; | ||
1959 | |||
1960 | my $nsswitch = &getGlobal('FILE',"nsswitch.conf"); | ||
1961 | |||
1962 | if( ! -f $nsswitch ) { | ||
1963 | &B_create_file($nsswitch); | ||
1964 | # we don't need to revert the permissions change because we just | ||
1965 | # created the file | ||
1966 | chmod(0444, $nsswitch); | ||
1967 | |||
1968 | &B_append_line($nsswitch,'\s*passwd:', "passwd: $regex\n"); | ||
1969 | &B_append_line($nsswitch,'\s*group:', "group: $regex\n"); | ||
1970 | &B_append_line($nsswitch,'\s*hosts:', "hosts: $regex\n"); | ||
1971 | &B_append_line($nsswitch,'\s*networks:', "networks: $regex\n"); | ||
1972 | &B_append_line($nsswitch,'\s*protocols:', "protocols: $regex\n"); | ||
1973 | &B_append_line($nsswitch,'\s*rpc:', "rpc: $regex\n"); | ||
1974 | &B_append_line($nsswitch,'\s*publickey:', "publickey: $regex\n"); | ||
1975 | &B_append_line($nsswitch,'\s*netgroup:', "netgroup: $regex\n"); | ||
1976 | &B_append_line($nsswitch,'\s*automount:', "automount: $regex\n"); | ||
1977 | &B_append_line($nsswitch,'\s*aliases:', "aliases: $regex\n"); | ||
1978 | &B_append_line($nsswitch,'\s*services:', "services: $regex\n"); | ||
1979 | } | ||
1980 | } | ||
1981 | |||
1982 | 1; | ||
1983 | |||
diff --git a/dynamic-layers/meta-perl/recipes-security/bastille/files/Miscellaneous.pm b/dynamic-layers/meta-perl/recipes-security/bastille/files/Miscellaneous.pm new file mode 100644 index 0000000..b3bdf10 --- /dev/null +++ b/dynamic-layers/meta-perl/recipes-security/bastille/files/Miscellaneous.pm | |||
@@ -0,0 +1,166 @@ | |||
1 | package Bastille::API::Miscellaneous; | ||
2 | use strict; | ||
3 | |||
4 | use File::Path; | ||
5 | use Bastille::API; | ||
6 | use Bastille::API::HPSpecific; | ||
7 | use Bastille::API::FileContent; | ||
8 | |||
9 | require Exporter; | ||
10 | our @ISA = qw(Exporter); | ||
11 | our @EXPORT_OK = qw( | ||
12 | PrepareToRun | ||
13 | B_is_package_installed | ||
14 | ); | ||
15 | our @EXPORT = @EXPORT_OK; | ||
16 | |||
17 | |||
18 | ########################################################################### | ||
19 | # | ||
20 | # PrepareToRun sets up Bastille to run. It checks the ARGV array for | ||
21 | # special options and runs ConfigureForDistro to set necessary file | ||
22 | # locations and other global variables. | ||
23 | # | ||
24 | ########################################################################### | ||
25 | |||
26 | sub PrepareToRun { | ||
27 | |||
28 | # Make sure we're root! | ||
29 | if ( $> != 0 ) { | ||
30 | &B_log("ERROR","Bastille must run as root!\n"); | ||
31 | exit(1); | ||
32 | } | ||
33 | |||
34 | |||
35 | # Make any directories that don't exist... | ||
36 | foreach my $dir (keys %GLOBAL_BDIR) { | ||
37 | my $BdirPath = $GLOBAL_BDIR{$dir}; | ||
38 | if ( $BdirPath =~ /^\s*\// ) { #Don't make relative directories | ||
39 | mkpath ($BdirPath,0,0700); | ||
40 | } | ||
41 | } | ||
42 | |||
43 | if(&GetDistro =~ "^HP-UX") { | ||
44 | &B_check_system; | ||
45 | } | ||
46 | |||
47 | &B_log("ACTION","\n########################################################\n" . | ||
48 | "# Begin Bastille Run #\n" . | ||
49 | "########################################################\n\n"); | ||
50 | |||
51 | #read sum file if it exists. | ||
52 | &B_read_sums; | ||
53 | |||
54 | |||
55 | # No longer necessary as flags are no longer in sum file, and sums are | ||
56 | # are now checked "real time" | ||
57 | |||
58 | # check the integrity of the files listed | ||
59 | # for my $file (sort keys %GLOBAL_SUM) { | ||
60 | # &B_check_sum($file); | ||
61 | # } | ||
62 | # write out the newly flagged sums | ||
63 | # &B_write_sums; | ||
64 | |||
65 | |||
66 | } | ||
67 | |||
68 | |||
69 | |||
70 | ########################################################################### | ||
71 | # &B_is_package_installed($package); | ||
72 | # | ||
73 | # This function checks for the existence of the package named. | ||
74 | # | ||
75 | # TODO: Allow $package to be an expression. | ||
76 | # TODO: Allow optional $version, $release, $epoch arguments so we can | ||
77 | # make sure that the given package is at least as recent as some | ||
78 | # given version number. | ||
79 | # | ||
80 | # scalar return values: | ||
81 | # 0: $package is not installed | ||
82 | # 1: $package is installed | ||
83 | ########################################################################### | ||
84 | |||
85 | sub B_is_package_installed($) { | ||
86 | no strict; | ||
87 | my $package = $_[0]; | ||
88 | # Create a "global" variable with values scoped to this function | ||
89 | # We do this to avoid having to repeatedly swlist/rpm | ||
90 | # when we run B_is_package_installed | ||
91 | local %INSTALLED_PACKAGE_LIST; | ||
92 | |||
93 | my $distro = &GetDistro; | ||
94 | if ($distro =~ /^HP-UX/) { | ||
95 | if (&checkProcsForService('swagent','ignore_warning') == SECURE_CANT_CHANGE()) { | ||
96 | &B_log("WARNING","Software Distributor Agent(swagent) is not running. Can not tell ". | ||
97 | "if package: $package is installed or not. Bastille will assume not. ". | ||
98 | "If the package is actually installed, Bastille may report or configure incorrectly.". | ||
99 | "To use Bastille-results as-is, please check to ensure $package is not installed, ". | ||
100 | "or re-run with the swagent running to get correct results."); | ||
101 | return 0; #FALSE | ||
102 | } | ||
103 | my $swlist=&getGlobal('BIN','swlist'); | ||
104 | if (%INSTALLED_PACKAGE_LIST == () ) { # re-use prior results | ||
105 | if (open(SWLIST, "$swlist -a state -l fileset |")) { | ||
106 | while (my $line = <SWLIST>){ | ||
107 | if ($line =~ /^ {2}\S+\.(\S+)\s*(\w+)/) { | ||
108 | $INSTALLED_PACKAGE_LIST{$1} = $2; | ||
109 | } | ||
110 | } | ||
111 | close SWLIST; | ||
112 | } else { | ||
113 | &B_log("ERROR","B_is_package_installed was unable to run the swlist command: $swlist,\n"); | ||
114 | return FALSE; | ||
115 | } | ||
116 | } | ||
117 | # Now find the entry | ||
118 | if ($INSTALLED_PACKAGE_LIST{$package} == 'configured') { | ||
119 | return TRUE; | ||
120 | } else { | ||
121 | return FALSE; | ||
122 | } | ||
123 | } #End HP-UX Section | ||
124 | # This routine only works on RPM-based distros: Red Hat, Fedora, Mandrake and SuSE | ||
125 | elsif ( ($distro !~ /^RH/) and ($distro !~ /^MN/) and($distro !~ /^SE/) ) { | ||
126 | return 0; | ||
127 | } else { #This is a RPM-based distro | ||
128 | # Run an rpm command -- librpm is extremely messy, dynamic and not | ||
129 | # so much a perl thing. It's actually barely a C/C++ thing... | ||
130 | if (open RPM,"rpm -q $package") { | ||
131 | # We should get only one line back, but let's parse a few | ||
132 | # just in case. | ||
133 | my @lines = <RPM>; | ||
134 | close RPM; | ||
135 | # | ||
136 | # This is what we're trying to parse: | ||
137 | # $ rpm -q jay | ||
138 | # package jay is not installed | ||
139 | # $ rpm -q bash | ||
140 | # bash-2.05b-305.1 | ||
141 | # | ||
142 | |||
143 | foreach $line (@lines) { | ||
144 | if ($line =~ /^package\s$package\sis\snot\sinstalled/) { | ||
145 | return 0; | ||
146 | } | ||
147 | elsif ($line =~ /^$package\-/) { | ||
148 | return 1; | ||
149 | } | ||
150 | } | ||
151 | |||
152 | # If we've read every line without finding one of these, then | ||
153 | # our parsing is broken | ||
154 | &B_log("ERROR","B_is_package_installed was unable to find a definitive RPM present or not present line.\n"); | ||
155 | return 0; | ||
156 | } else { | ||
157 | &B_log("ERROR","B_is_package_installed was unable to run the RPM command,\n"); | ||
158 | return 0; | ||
159 | } | ||
160 | } | ||
161 | } | ||
162 | |||
163 | |||
164 | |||
165 | 1; | ||
166 | |||
diff --git a/dynamic-layers/meta-perl/recipes-security/bastille/files/ServiceAdmin.pm b/dynamic-layers/meta-perl/recipes-security/bastille/files/ServiceAdmin.pm new file mode 100644 index 0000000..879223a --- /dev/null +++ b/dynamic-layers/meta-perl/recipes-security/bastille/files/ServiceAdmin.pm | |||
@@ -0,0 +1,690 @@ | |||
1 | package Bastille::API::ServiceAdmin; | ||
2 | use strict; | ||
3 | |||
4 | use Bastille::API; | ||
5 | |||
6 | use Bastille::API::HPSpecific; | ||
7 | use Bastille::API::FileContent; | ||
8 | |||
9 | require Exporter; | ||
10 | our @ISA = qw(Exporter); | ||
11 | our @EXPORT_OK = qw( | ||
12 | B_chkconfig_on | ||
13 | B_chkconfig_off | ||
14 | B_service_start | ||
15 | B_service_stop | ||
16 | B_service_restart | ||
17 | B_is_service_off | ||
18 | checkServiceOnLinux | ||
19 | remoteServiceCheck | ||
20 | remoteNISPlusServiceCheck | ||
21 | B_create_nsswitch_file | ||
22 | ); | ||
23 | our @EXPORT = @EXPORT_OK; | ||
24 | |||
25 | |||
26 | ####### | ||
27 | # &B_chkconfig_on and &B_chkconfig_off() are great for systems that didn't use | ||
28 | # a more modern init system. This is a bit of a problem on Fedora, though, | ||
29 | # which used upstart from Fedora 9 to Fedora 14, then switched to a new | ||
30 | # Red Hat-created system called systemd for Fedora 15 and 16 (so far). | ||
31 | # OpenSUSE also moved to systemd, starting with 12.1. Version 11.4 did not | ||
32 | # use systemd. | ||
33 | # It is also a problem on Ubuntu, starting at version 6.10, where they also | ||
34 | # used upstart. | ||
35 | ##### | ||
36 | |||
37 | |||
38 | |||
39 | |||
40 | ########################################################################### | ||
41 | # &B_chkconfig_on ($daemon_name) creates the symbolic links that are | ||
42 | # named in the "# chkconfig: ___ _ _ " portion of the init.d files. We | ||
43 | # need this utility, in place of the distro's chkconfig, because of both | ||
44 | # our need to add revert functionality and our need to harden distros that | ||
45 | # are not mounted on /. | ||
46 | # | ||
47 | # It uses the following global variables to find the links and the init | ||
48 | # scripts, respectively: | ||
49 | # | ||
50 | # &getGlobal('DIR', "rcd") -- directory where the rc_.d subdirs can be found | ||
51 | # &getGlobal('DIR', "initd") -- directory the rc_.d directories link to | ||
52 | # | ||
53 | # Here an example of where you might use this: | ||
54 | # | ||
55 | # You'd like to tell the system to run the firewall at boot: | ||
56 | # B_chkconfig_on("bastille-firewall") | ||
57 | # | ||
58 | ########################################################################### | ||
59 | |||
60 | # PW: Blech. Copied B_chkconfig_off() and changed a few things, | ||
61 | # then changed a few more things.... | ||
62 | |||
63 | sub B_chkconfig_on { | ||
64 | |||
65 | my $startup_script=$_[0]; | ||
66 | my $retval=1; | ||
67 | |||
68 | my $chkconfig_line; | ||
69 | my ($runlevelinfo,@runlevels); | ||
70 | my ($start_order,$stop_order,$filetolink); | ||
71 | |||
72 | &B_log("ACTION","# chkconfig_on enabling $startup_script\n"); | ||
73 | |||
74 | # In Debian system there is no chkconfig script, run levels are checked | ||
75 | # one by one (jfs) | ||
76 | if (&GetDistro =~/^DB.*/) { | ||
77 | $filetolink = &getGlobal('DIR', "initd") . "/$startup_script"; | ||
78 | if (-x $filetolink) | ||
79 | { | ||
80 | foreach my $level ("0","1","2","3","4","5","6" ) { | ||
81 | my $link = ''; | ||
82 | $link = &getGlobal('DIR', "rcd") . "/rc" . "$level" . ".d/K50" . "$startup_script"; | ||
83 | $retval=symlink($filetolink,$link); | ||
84 | } | ||
85 | } | ||
86 | return $retval; | ||
87 | } | ||
88 | # | ||
89 | # On SUSE, chkconfig-based rc scripts have been replaced with a whole different | ||
90 | # system. chkconfig on SUSE is actually a shell script that does some stuff and then | ||
91 | # calls insserv, their replacement. | ||
92 | # | ||
93 | |||
94 | if (&GetDistro =~ /^SE/) { | ||
95 | # only try to chkconfig on if init script is found | ||
96 | if ( -e (&getGlobal('DIR', "initd") . "/$startup_script") ) { | ||
97 | $chkconfig_line=&getGlobal('BIN','chkconfig'); | ||
98 | &B_System("$chkconfig_line $startup_script on", "$chkconfig_line $startup_script off"); | ||
99 | # chkconfig doesn't take affect until reboot, need to restart service also | ||
100 | B_service_restart("$startup_script"); | ||
101 | return 1; #success | ||
102 | } | ||
103 | return 0; #failure | ||
104 | } | ||
105 | |||
106 | # | ||
107 | # Run through the init script looking for the chkconfig line... | ||
108 | # | ||
109 | $retval = open CHKCONFIG,&getGlobal('DIR', "initd") . "/$startup_script"; | ||
110 | unless ($retval) { | ||
111 | &B_log("ACTION","# Didn't chkconfig_on $startup_script because we couldn't open " . &getGlobal('DIR', "initd") . "/$startup_script\n"); | ||
112 | } | ||
113 | else { | ||
114 | |||
115 | READ_LOOP: | ||
116 | while (my $line=<CHKCONFIG>) { | ||
117 | |||
118 | # We're looking for lines like this one: | ||
119 | # # chkconfig: 2345 10 90 | ||
120 | # OR this | ||
121 | # # chkconfig: - 10 90 | ||
122 | |||
123 | if ($line =~ /^#\s*chkconfig:\s*([-\d]+)\s*(\d+)\s*(\d+)/ ) { | ||
124 | $runlevelinfo = $1; | ||
125 | $start_order = $2; | ||
126 | $stop_order = $3; | ||
127 | # handle a run levels arg of '-' | ||
128 | if ( $runlevelinfo eq '-' ) { | ||
129 | &B_log("ACTION","chkconfig_on saw '-' for run levels for \"$startup_script\", is defaulting to levels 3,4,5\n"); | ||
130 | $runlevelinfo = '345'; | ||
131 | } | ||
132 | @runlevels = split(//,$runlevelinfo); | ||
133 | # make sure the orders have 2 digits | ||
134 | $start_order =~ s/^(\d)$/0$1/; | ||
135 | $stop_order =~ s/^(\d)$/0$1/; | ||
136 | last READ_LOOP; | ||
137 | } | ||
138 | } | ||
139 | close CHKCONFIG; | ||
140 | |||
141 | # Do we have what we need? | ||
142 | if ( (scalar(@runlevels) < 1) || (! $start_order =~ /^\d{2}$/) || (! $stop_order =~ /^\d{2}$/) ) { | ||
143 | # problem | ||
144 | &B_log("ERROR","# B_chkconfig_on $startup_script failed -- no valid run level/start/stop info found\n"); | ||
145 | return(-1); | ||
146 | } | ||
147 | |||
148 | # Now, run through creating symlinks... | ||
149 | &B_log("ACTION","# chkconfig_on will use run levels ".join(",",@runlevels)." for \"$startup_script\" with S order $start_order and K order $stop_order\n"); | ||
150 | |||
151 | $retval=0; | ||
152 | # BUG: we really ought to readdir() on &getGlobal('DIR', "rcd") to get all levels | ||
153 | foreach my $level ( "0","1","2","3","4","5","6" ) { | ||
154 | my $link = ''; | ||
155 | # we make K links in run levels not specified in the chkconfig line | ||
156 | $link = &getGlobal('DIR', "rcd") . "/rc" . $level . ".d/K$stop_order" . $startup_script; | ||
157 | my $klink = $link; | ||
158 | # now we see if this is a specified run level; if so, make an S link | ||
159 | foreach my $markedlevel ( @runlevels ) { | ||
160 | if ( $level == $markedlevel) { | ||
161 | $link = &getGlobal('DIR', "rcd") . "/rc" . $level . ".d/S$start_order" . $startup_script; | ||
162 | } | ||
163 | } | ||
164 | my $target = &getGlobal('DIR', "initd") ."/" . $startup_script; | ||
165 | my $local_return; | ||
166 | |||
167 | if ( (-e "$klink") && ($klink ne $link) ) { | ||
168 | # there's a K link, but this level needs an S link | ||
169 | unless ($GLOBAL_LOGONLY) { | ||
170 | $local_return = unlink("$klink"); | ||
171 | if ( ! $local_return ) { | ||
172 | # unlinking old, bad $klink failed | ||
173 | &B_log("ERROR","Unlinking $klink failed\n"); | ||
174 | } else { | ||
175 | &B_log("ACTION","Removed link $klink\n"); | ||
176 | # If we removed the link, add a link command to the revert file | ||
177 | &B_revert_log (&getGlobal('BIN','ln') . " -s $target $klink\n"); | ||
178 | } # close what to do if unlink works | ||
179 | } # if not GLOBAL_LOGONLY | ||
180 | } # if $klink exists and ne $link | ||
181 | |||
182 | # OK, we've disposed of any old K links, make what we need | ||
183 | if ( (! ( -e "$link" )) && ($link ne '') ) { | ||
184 | # link doesn't exist and the start/stop number is OK; make it | ||
185 | unless ($GLOBAL_LOGONLY) { | ||
186 | # create the link | ||
187 | $local_return = &B_symlink($target,$link); | ||
188 | if ($local_return) { | ||
189 | $retval++; | ||
190 | &B_log("ACTION","Created link $link\n"); | ||
191 | } else { | ||
192 | &B_log("ERROR","Couldn't create $link when trying to chkconfig on $startup_script\n"); | ||
193 | } | ||
194 | } | ||
195 | |||
196 | } # link doesn't exist | ||
197 | } # foreach level | ||
198 | |||
199 | } | ||
200 | |||
201 | if ($retval < @runlevels) { | ||
202 | $retval=0; | ||
203 | } | ||
204 | |||
205 | $retval; | ||
206 | |||
207 | } | ||
208 | |||
209 | |||
210 | ########################################################################### | ||
211 | # &B_chkconfig_off ($daemon_name) deletes the symbolic links that are | ||
212 | # named in the "# chkconfig: ___ _ _ " portion of the init.d files. We | ||
213 | # need this utility, in place of the distro's chkconfig, because of both | ||
214 | # our need to add revert functionality and our need to harden distros that | ||
215 | # are not mounted on /. | ||
216 | # | ||
217 | # chkconfig allows for a REVERT of its work by writing to an executable | ||
218 | # file &getGlobal('BFILE', "removed-symlinks"). | ||
219 | # | ||
220 | # It uses the following global variables to find the links and the init | ||
221 | # scripts, respectively: | ||
222 | # | ||
223 | # &getGlobal('DIR', "rcd") -- directory where the rc_.d subdirs can be found | ||
224 | # &getGlobal('DIR', "initd") -- directory the rc_.d directories link to | ||
225 | # | ||
226 | # Here an example of where you might use this: | ||
227 | # | ||
228 | # You'd like to tell stop running sendmail in daemon mode on boot: | ||
229 | # B_chkconfig_off("sendmail") | ||
230 | # | ||
231 | ########################################################################### | ||
232 | |||
233 | |||
234 | |||
235 | sub B_chkconfig_off { | ||
236 | |||
237 | my $startup_script=$_[0]; | ||
238 | my $retval=1; | ||
239 | |||
240 | my $chkconfig_line; | ||
241 | my @runlevels; | ||
242 | my ($start_order,$stop_order,$filetolink); | ||
243 | |||
244 | if (&GetDistro =~/^DB.*/) { | ||
245 | $filetolink = &getGlobal('DIR', "initd") . "/$startup_script"; | ||
246 | if (-x $filetolink) | ||
247 | { | ||
248 | # Three ways to do this in Debian: | ||
249 | # 1.- have the initd script set to 600 mode | ||
250 | # 2.- Remove the links in rcd (re-installing the package | ||
251 | # will break it) | ||
252 | # 3.- Use update-rc.d --remove (same as 2.) | ||
253 | # (jfs) | ||
254 | &B_chmod(0600,$filetolink); | ||
255 | $retval=6; | ||
256 | |||
257 | # The second option | ||
258 | #foreach my $level ("0","1","2","3","4","5","6" ) { | ||
259 | #my $link = ''; | ||
260 | #$link = &getGlobal('DIR', "rcd") . "/rc" . "$level" . ".d/K50" . "$startup_script"; | ||
261 | #unlink($link); | ||
262 | #} | ||
263 | } | ||
264 | } | ||
265 | |||
266 | # | ||
267 | # On SUSE, chkconfig-based rc scripts have been replaced with a whole different | ||
268 | # system. chkconfig on SUSE is actually a shell script that does some stuff and then | ||
269 | # calls insserv, their replacement. | ||
270 | # | ||
271 | elsif (&GetDistro =~ /^SE/) { | ||
272 | # only try to chkconfig off if init script is found | ||
273 | if ( -e (&getGlobal('DIR', "initd") . "/$startup_script") ) { | ||
274 | $chkconfig_line=&getGlobal('BIN','chkconfig'); | ||
275 | &B_System("$chkconfig_line $startup_script on", "$chkconfig_line $startup_script off"); | ||
276 | # chkconfig doesn't take affect until reboot, need to stop service | ||
277 | # since expectation is that the daemons are disabled even without a reboot | ||
278 | B_service_stop("$startup_script"); | ||
279 | return 1; #success | ||
280 | } | ||
281 | return 0; #failure | ||
282 | } | ||
283 | else { | ||
284 | |||
285 | # Run through the init script looking for the chkconfig line... | ||
286 | |||
287 | |||
288 | $retval = open CHKCONFIG,&getGlobal('DIR', "initd") . "/$startup_script"; | ||
289 | unless ($retval) { | ||
290 | &B_log("ACTION","Didn't chkconfig_off $startup_script because we couldn't open " . &getGlobal('DIR', "initd") . "/$startup_script\n"); | ||
291 | } | ||
292 | else { | ||
293 | |||
294 | READ_LOOP: | ||
295 | while (my $line=<CHKCONFIG>) { | ||
296 | |||
297 | # We're looking for lines like this one: | ||
298 | # # chkconfig: 2345 10 90 | ||
299 | |||
300 | if ($line =~ /^#\s*chkconfig:\s*([-\d]+)\s*(\d+)\s*(\d+)/ ) { | ||
301 | @runlevels=split //,$1; | ||
302 | $start_order=$2; | ||
303 | $stop_order=$3; | ||
304 | |||
305 | |||
306 | # Change single digit run levels to double digit -- otherwise, | ||
307 | # the alphabetic ordering chkconfig depends on fails. | ||
308 | if ($start_order =~ /^\d$/ ) { | ||
309 | $start_order = "0" . $start_order; | ||
310 | &B_log("ACTION","chkconfig_off converted start order to $start_order\n"); | ||
311 | } | ||
312 | if ($stop_order =~ /^\d$/ ) { | ||
313 | $stop_order = "0" . $stop_order; | ||
314 | &B_log("ACTION","chkconfig_off converted stop order to $stop_order\n"); | ||
315 | } | ||
316 | |||
317 | last READ_LOOP; | ||
318 | } | ||
319 | } | ||
320 | close CHKCONFIG; | ||
321 | |||
322 | # If we never found a chkconfig line, can we just run through all 5 | ||
323 | # rcX.d dirs from 1 to 5...? | ||
324 | |||
325 | # unless ( $start_order and $stop_order ) { | ||
326 | # @runlevels=("1","2","3","4","5"); | ||
327 | # $start_order = "*"; $stop_order="*"; | ||
328 | # } | ||
329 | |||
330 | # Now, run through removing symlinks... | ||
331 | |||
332 | |||
333 | |||
334 | $retval=0; | ||
335 | |||
336 | # Handle the special case that the run level specified is solely "-" | ||
337 | if ($runlevels[0] =~ /-/) { | ||
338 | @runlevels = ( "0","1","2","3","4","5","6" ); | ||
339 | } | ||
340 | |||
341 | foreach my $level ( @runlevels ) { | ||
342 | my $link = &getGlobal('DIR', "rcd") . "/rc" . $level . ".d/S$start_order" . $startup_script; | ||
343 | my $new_link = &getGlobal('DIR', "rcd") . "/rc" . $level . ".d/K$stop_order" . $startup_script; | ||
344 | my $target = &getGlobal('DIR', "initd") ."/" . $startup_script; | ||
345 | my $local_return; | ||
346 | |||
347 | |||
348 | # Replace the S__ link in this level with a K__ link. | ||
349 | if ( -e $link ) { | ||
350 | unless ($GLOBAL_LOGONLY) { | ||
351 | $local_return=unlink $link; | ||
352 | if ($local_return) { | ||
353 | $local_return=symlink $target,$new_link; | ||
354 | unless ($local_return) { | ||
355 | &B_log("ERROR","Linking $target to $new_link failed.\n"); | ||
356 | } | ||
357 | } | ||
358 | else { # unlinking failed | ||
359 | &B_log("ERROR","Unlinking $link failed\n"); | ||
360 | } | ||
361 | |||
362 | } | ||
363 | if ($local_return) { | ||
364 | $retval++; | ||
365 | &B_log("ACTION","Removed link $link\n"); | ||
366 | |||
367 | # | ||
368 | # If we removed the link, add a link command to the revert file | ||
369 | # Write out the revert information for recreating the S__ | ||
370 | # symlink and deleting the K__ symlink. | ||
371 | &B_revert_log(&getGlobal('BIN',"ln") . " -s $target $link\n"); | ||
372 | &B_revert_log(&getGlobal('BIN',"rm") . " -f $new_link\n"); | ||
373 | } | ||
374 | else { | ||
375 | &B_log("ERROR","B_chkconfig_off $startup_script failed\n"); | ||
376 | } | ||
377 | |||
378 | } | ||
379 | } # foreach | ||
380 | |||
381 | } # else-unless | ||
382 | |||
383 | } # else-DB | ||
384 | if ($retval < @runlevels) { | ||
385 | $retval=0; | ||
386 | } | ||
387 | |||
388 | $retval; | ||
389 | |||
390 | } | ||
391 | |||
392 | |||
393 | ########################################################################### | ||
394 | # &B_service_start ($daemon_name) | ||
395 | # Starts service on RedHat/SUSE-based Linux distributions which have the | ||
396 | # service command: | ||
397 | # | ||
398 | # service $daemon_name start | ||
399 | # | ||
400 | # Other Linux distros that also support this method of starting | ||
401 | # services can be added to use this function. | ||
402 | # | ||
403 | # Here an example of where you might use this: | ||
404 | # | ||
405 | # You'd like to tell the system to start the vsftpd daemon: | ||
406 | # &B_service_start("vsftpd") | ||
407 | # | ||
408 | # Uses &B_System in HP_API.pm | ||
409 | # To match how the &B_System command works this method: | ||
410 | # returns 1 on success | ||
411 | # returns 0 on failure | ||
412 | ########################################################################### | ||
413 | |||
414 | sub B_service_start { | ||
415 | |||
416 | my $daemon=$_[0]; | ||
417 | |||
418 | if ( (&GetDistro !~ /^SE/) and (&GetDistro !~ /^RH/) and | ||
419 | (&GetDistro !~ /^RHFC/) and (&GetDistro !~ /^MN/) ) { | ||
420 | &B_log("ERROR","Tried to call service_start on a system lacking a service command! Internal Bastille error."); | ||
421 | return undef; | ||
422 | } | ||
423 | |||
424 | # only start service if init script is found | ||
425 | if ( -e (&getGlobal('DIR', 'initd') . "/$daemon") ) { | ||
426 | &B_log("ACTION","# service_start enabling $daemon\n"); | ||
427 | |||
428 | my $service_cmd=&getGlobal('BIN', 'service'); | ||
429 | if ($service_cmd) { | ||
430 | # Start the service, | ||
431 | # Also provide &B_System revert command | ||
432 | |||
433 | return (&B_System("$service_cmd $daemon start", | ||
434 | "$service_cmd $daemon stop")); | ||
435 | } | ||
436 | } | ||
437 | |||
438 | # init script not found, do not try to start, return failure | ||
439 | return 0; | ||
440 | } | ||
441 | |||
442 | ########################################################################### | ||
443 | # &B_service_stop ($daemon_name) | ||
444 | # Stops service on RedHat/SUSE-based Linux distributions which have the | ||
445 | # service command: | ||
446 | # | ||
447 | # service $daemon_name stop | ||
448 | # | ||
449 | # Other Linux distros that also support this method of starting | ||
450 | # services can be added to use this function. | ||
451 | # Stops service. | ||
452 | # | ||
453 | # | ||
454 | # Here an example of where you might use this: | ||
455 | # | ||
456 | # You'd like to tell the system to stop the vsftpd daemon: | ||
457 | # &B_service_stop("vsftpd") | ||
458 | # | ||
459 | # Uses &B_System in HP_API.pm | ||
460 | # To match how the &B_System command works this method: | ||
461 | # returns 1 on success | ||
462 | # returns 0 on failure | ||
463 | ########################################################################### | ||
464 | |||
465 | sub B_service_stop { | ||
466 | |||
467 | my $daemon=$_[0]; | ||
468 | |||
469 | if ( (&GetDistro !~ /^SE/) and (&GetDistro !~ /^RH/) and | ||
470 | (&GetDistro !~ /^RHFC/) and (&GetDistro !~ /^MN/) ) { | ||
471 | &B_log("ERROR","Tried to call service_stop on a system lacking a service command! Internal Bastille error."); | ||
472 | return undef; | ||
473 | } | ||
474 | |||
475 | # only stop service if init script is found | ||
476 | if ( -e (&getGlobal('DIR', 'initd') . "/$daemon") ) { | ||
477 | &B_log("ACTION","# service_stop disabling $daemon\n"); | ||
478 | |||
479 | my $service_cmd=&getGlobal('BIN', 'service'); | ||
480 | if ($service_cmd) { | ||
481 | |||
482 | # Stop the service, | ||
483 | # Also provide &B_System revert command | ||
484 | |||
485 | return (&B_System("$service_cmd $daemon stop", | ||
486 | "$service_cmd $daemon start")); | ||
487 | } | ||
488 | } | ||
489 | |||
490 | # init script not found, do not try to stop, return failure | ||
491 | return 0; | ||
492 | } | ||
493 | |||
494 | |||
495 | ########################################################################### | ||
496 | # &B_service_restart ($daemon_name) | ||
497 | # Restarts service on RedHat/SUSE-based Linux distributions which have the | ||
498 | # service command: | ||
499 | # | ||
500 | # service $daemon_name restart | ||
501 | # | ||
502 | # Other Linux distros that also support this method of starting | ||
503 | # services can be added to use this function. | ||
504 | # | ||
505 | # Here an example of where you might use this: | ||
506 | # | ||
507 | # You'd like to tell the system to restart the vsftpd daemon: | ||
508 | # &B_service_restart("vsftpd") | ||
509 | # | ||
510 | # Uses &B_System in HP_API.pm | ||
511 | # To match how the &B_System command works this method: | ||
512 | # returns 1 on success | ||
513 | # returns 0 on failure | ||
514 | ########################################################################### | ||
515 | |||
516 | sub B_service_restart { | ||
517 | |||
518 | my $daemon=$_[0]; | ||
519 | |||
520 | if ( (&GetDistro !~ /^SE/) and (&GetDistro !~ /^RH/) and | ||
521 | (&GetDistro !~ /^RHFC/) and (&GetDistro !~ /^MN/) ) { | ||
522 | &B_log("ERROR","Tried to call service_restart on a system lacking a service command! Internal Bastille error."); | ||
523 | return undef; | ||
524 | } | ||
525 | |||
526 | # only restart service if init script is found | ||
527 | if ( -e (&getGlobal('DIR', 'initd') . "/$daemon") ) { | ||
528 | &B_log("ACTION","# service_restart re-enabling $daemon\n"); | ||
529 | |||
530 | my $service_cmd=&getGlobal('BIN', 'service'); | ||
531 | if ($service_cmd) { | ||
532 | |||
533 | # Restart the service | ||
534 | return (&B_System("$service_cmd $daemon restart", | ||
535 | "$service_cmd $daemon restart")); | ||
536 | } | ||
537 | } | ||
538 | |||
539 | # init script not found, do not try to restart, return failure | ||
540 | return 0; | ||
541 | } | ||
542 | |||
543 | ########################################################################### | ||
544 | # &B_is_service_off($;$) | ||
545 | # | ||
546 | # Runs the specified test to determine whether or not the question should | ||
547 | # be answered. | ||
548 | # | ||
549 | # return values: | ||
550 | # NOTSECURE_CAN_CHANGE()/0: service is on | ||
551 | # SECURE_CANT_CHANGE()/1: service is off | ||
552 | # undef: test is not defined | ||
553 | ########################################################################### | ||
554 | |||
555 | sub B_is_service_off ($){ | ||
556 | my $service=$_[0]; | ||
557 | |||
558 | if(&GetDistro =~ "^HP-UX"){ | ||
559 | #die "Why do I think I'm on HPUX?!\n"; | ||
560 | return &checkServiceOnHPUX($service); | ||
561 | } | ||
562 | elsif ( (&GetDistro =~ "^RH") || (&GetDistro =~ "^SE") ) { | ||
563 | return &checkServiceOnLinux($service); | ||
564 | } | ||
565 | else { | ||
566 | &B_log("DEBUG","B_is_service off called for unsupported OS"); | ||
567 | # not yet implemented for other distributions of Linux | ||
568 | # when GLOBAL_SERVICE, GLOBAL_SERVTYPE and GLOBAL_PROCESS are filled | ||
569 | # in for Linux, then | ||
570 | # at least inetd and inittab services should be similar to the above, | ||
571 | # whereas chkconfig would be used on some Linux distros to determine | ||
572 | # if non-inetd/inittab services are running at boot time. Looking at | ||
573 | # processes should be similar. | ||
574 | return undef; | ||
575 | } | ||
576 | } | ||
577 | |||
578 | ########################################################################### | ||
579 | # &checkServiceOnLinux($service); | ||
580 | # | ||
581 | # Checks if the given service is running on a Linux system. This is | ||
582 | # called by B_is_Service_Off(), which is the function that Bastille | ||
583 | # modules should call. | ||
584 | # | ||
585 | # Return values: | ||
586 | # NOTSECURE_CAN_CHANGE() if the service is on | ||
587 | # SECURE_CANT_CHANGE() if the service is off | ||
588 | # undef if the state of the service cannot be determined | ||
589 | # | ||
590 | ########################################################################### | ||
591 | sub checkServiceOnLinux($) { | ||
592 | my $service=$_[0]; | ||
593 | |||
594 | # get the list of parameters which could be used to initiate the service | ||
595 | # (could be in /etc/rc.d/rc?.d, /etc/inetd.conf, or /etc/inittab, so we | ||
596 | # check all of them) | ||
597 | |||
598 | my @params = @{ &getGlobal('SERVICE', $service) }; | ||
599 | my $chkconfig = &getGlobal('BIN', 'chkconfig'); | ||
600 | my $grep = &getGlobal('BIN', 'grep'); | ||
601 | my $inittab = &getGlobal('FILE', 'inittab'); | ||
602 | my $serviceType = &getGlobal('SERVTYPE', $service);; | ||
603 | |||
604 | # A kludge to get things running because &getGlobal('SERVICE' doesn't | ||
605 | # return the expected values. | ||
606 | @params = (); | ||
607 | push (@params, $service); | ||
608 | |||
609 | foreach my $param (@params) { | ||
610 | &B_log("DEBUG","Checking to see if service $service is off.\n"); | ||
611 | |||
612 | if ($serviceType =~ /rc/) { | ||
613 | my $on = &B_Backtick("$chkconfig --list $param 2>&1"); | ||
614 | if ($on =~ /^$param:\s+unknown/) { | ||
615 | # This service isn't installed on the system | ||
616 | return NOT_INSTALLED(); | ||
617 | } | ||
618 | if ($on =~ /^error reading information on service $param: No such file or directory/) { | ||
619 | # This service isn't installed on the system | ||
620 | return NOT_INSTALLED(); | ||
621 | } | ||
622 | if ($on =~ /^error/) { | ||
623 | # This probably | ||
624 | &B_log("DEBUG","chkconfig returned: $param=$on\n"); | ||
625 | return undef; | ||
626 | } | ||
627 | $on =~ s/^$param\s+//; # remove the service name and spaces | ||
628 | $on =~ s/[0-6]:off\s*//g; # remove any runlevel:off entries | ||
629 | $on =~ s/:on\s*//g; # remove the :on from the runlevels | ||
630 | # what remains is a list of runlevels in which the service is on, | ||
631 | # or a null string if it is never turned on | ||
632 | chomp $on; # newline should be gone already (\s) | ||
633 | &B_log("DEBUG","chkconfig returned: $param=$on\n"); | ||
634 | |||
635 | if ($on =~ /^\d+$/) { | ||
636 | # service is not off | ||
637 | ########################### BREAK out, don't skip question | ||
638 | return NOTSECURE_CAN_CHANGE(); | ||
639 | } | ||
640 | } | ||
641 | elsif ($serviceType =~ /inet/) { | ||
642 | my $on = &B_Backtick("$chkconfig --list $param 2>&1"); | ||
643 | if ($on =~ /^$param:\s+unknown/) { | ||
644 | # This service isn't installed on the system | ||
645 | return NOT_INSTALLED(); | ||
646 | } | ||
647 | if ($on =~ /^error reading information on service $param: No such file or directory/) { | ||
648 | # This service isn't installed on the system | ||
649 | return NOT_INSTALLED(); | ||
650 | } | ||
651 | if ($on =~ /^error/ ) { | ||
652 | # Something else is wrong? | ||
653 | # return undef | ||
654 | return undef; | ||
655 | } | ||
656 | if ($on =~ tr/\n// > 1) { | ||
657 | $on =~ s/^xinetd.+\n//; | ||
658 | } | ||
659 | $on =~ s/^\s*$param:?\s+//; # remove the service name and spaces | ||
660 | chomp $on; # newline should be gone already (\s) | ||
661 | &B_log("DEBUG","chkconfig returned: $param=$on\n"); | ||
662 | |||
663 | if ($on =~ /^on$/) { | ||
664 | # service is not off | ||
665 | ########################### BREAK out, don't skip question | ||
666 | return NOTSECURE_CAN_CHANGE(); | ||
667 | } | ||
668 | } | ||
669 | else { | ||
670 | # perhaps the service is started by inittab | ||
671 | my $inittabline = &B_Backtick("$grep -E '^[^#].{0,3}:.*:.+:.*$param' $inittab"); | ||
672 | if ($inittabline =~ /.+/) { # . matches anything except newlines | ||
673 | # service is not off | ||
674 | &B_log("DEBUG","Checking inittab; found $inittabline\n"); | ||
675 | ########################### BREAK out, don't skip question | ||
676 | return NOTSECURE_CAN_CHANGE(); | ||
677 | } | ||
678 | } | ||
679 | } # foreach my $param | ||
680 | |||
681 | |||
682 | # boot-time parameters are not set; check processes | ||
683 | # Note the checkProcsforService returns INCONSISTENT() if a process is found | ||
684 | # assuming the checks above | ||
685 | return &checkProcsForService($service); | ||
686 | } | ||
687 | |||
688 | 1; | ||
689 | |||
690 | |||
diff --git a/dynamic-layers/meta-perl/recipes-security/bastille/files/accept_os_flag_in_backend.patch b/dynamic-layers/meta-perl/recipes-security/bastille/files/accept_os_flag_in_backend.patch new file mode 100644 index 0000000..4a438e4 --- /dev/null +++ b/dynamic-layers/meta-perl/recipes-security/bastille/files/accept_os_flag_in_backend.patch | |||
@@ -0,0 +1,34 @@ | |||
1 | Upstream Status: Inappropriate [No upstream maintenance] | ||
2 | |||
3 | Signed-off-by: Anne Mulhern <mulhern@yoctoproject.org> | ||
4 | |||
5 | --- | ||
6 | |||
7 | Index: Bastille/BastilleBackEnd | ||
8 | =================================================================== | ||
9 | --- Bastille.orig/BastilleBackEnd 2013-08-21 12:40:54.000000000 -0400 | ||
10 | +++ Bastille/BastilleBackEnd 2013-08-21 12:43:21.895950001 -0400 | ||
11 | @@ -52,11 +52,13 @@ | ||
12 | my $force = 0; | ||
13 | my $debug = 0; | ||
14 | my $alternate_config=undef; | ||
15 | +my $os_version=undef; | ||
16 | |||
17 | if( Getopt::Long::GetOptions( "n" => \$nodisclaim, | ||
18 | "v" => \$verbose, | ||
19 | "force" => \$force, | ||
20 | "f=s" => \$alternate_config, | ||
21 | + "os=s" => \$os_version, | ||
22 | "debug" => \$debug) ) { | ||
23 | $error = 0; # no parse error | ||
24 | |||
25 | @@ -66,7 +68,8 @@ | ||
26 | |||
27 | &setOptions( | ||
28 | debug => $debug, | ||
29 | - verbose => $verbose); | ||
30 | + verbose => $verbose, | ||
31 | + os => $os_version); | ||
32 | &ConfigureForDistro; | ||
33 | |||
34 | if ( $error ) { # GetOptions couldn't parse all of the args | ||
diff --git a/dynamic-layers/meta-perl/recipes-security/bastille/files/allow_os_with_assess.patch b/dynamic-layers/meta-perl/recipes-security/bastille/files/allow_os_with_assess.patch new file mode 100644 index 0000000..e112f90 --- /dev/null +++ b/dynamic-layers/meta-perl/recipes-security/bastille/files/allow_os_with_assess.patch | |||
@@ -0,0 +1,43 @@ | |||
1 | Upstream Status: Inappropriate [No upstream maintenance] | ||
2 | |||
3 | Signed-off-by: Anne Mulhern <mulhern@yoctoproject.org> | ||
4 | |||
5 | --- | ||
6 | |||
7 | Index: Bastille/bin/bastille | ||
8 | =================================================================== | ||
9 | --- Bastille.orig/bin/bastille 2013-08-21 08:59:06.647950000 -0400 | ||
10 | +++ Bastille/bin/bastille 2013-08-21 15:55:53.193631711 -0400 | ||
11 | @@ -195,7 +195,6 @@ | ||
12 | systemFileLocations | ||
13 | |||
14 | isAssessing='no' | ||
15 | -nonXArg='no' | ||
16 | |||
17 | if [ $PERL_V_MAJ -eq $MIN_V_MAJ -a $PERL_V_MIN -lt $MIN_V_MIN -o $PERL_V_MAJ -lt $MIN_V_MAJ ]; then # invalid Perl | ||
18 | printErr | ||
19 | @@ -316,12 +315,10 @@ | ||
20 | '--os') | ||
21 | options_left="$options_left --os" | ||
22 | optarg='yes' | ||
23 | - nonXArg='yes' | ||
24 | ;; | ||
25 | '-f') | ||
26 | options_left="$options_left -f" | ||
27 | optarg='yes' | ||
28 | - nonXArg='yes' | ||
29 | ;; | ||
30 | # Non-exclusive (undocumented and unsupported) options follow: | ||
31 | # There is no validity/combination checking done with these. | ||
32 | @@ -345,11 +342,6 @@ | ||
33 | fi | ||
34 | done | ||
35 | |||
36 | -#Detect case where -f or --os attempted use with --assess | ||
37 | - if [ \( x$nonXArg = xyes \) -a \( x$isAssessing = xyes \) ]; then | ||
38 | - printUsage | ||
39 | - exit 2 | ||
40 | - fi | ||
41 | |||
42 | # We have a valid version of perl! Verify that all the required | ||
43 | # modules can be found. | ||
diff --git a/dynamic-layers/meta-perl/recipes-security/bastille/files/call_output_config.patch b/dynamic-layers/meta-perl/recipes-security/bastille/files/call_output_config.patch new file mode 100644 index 0000000..1e898b1 --- /dev/null +++ b/dynamic-layers/meta-perl/recipes-security/bastille/files/call_output_config.patch | |||
@@ -0,0 +1,19 @@ | |||
1 | Upstream Status: Inappropriate [No upstream maintenance] | ||
2 | |||
3 | Signed-off-by: Anne Mulhern <mulhern@yoctoproject.org> | ||
4 | |||
5 | --- | ||
6 | |||
7 | Index: Bastille/Bastille_Curses.pm | ||
8 | =================================================================== | ||
9 | --- Bastille.orig/Bastille_Curses.pm 2013-08-21 08:58:53.899950000 -0400 | ||
10 | +++ Bastille/Bastille_Curses.pm 2013-08-21 09:20:20.295950005 -0400 | ||
11 | @@ -84,7 +84,7 @@ | ||
12 | } | ||
13 | |||
14 | # Output answers to the script and display | ||
15 | - &checkAndSaveConfig(&getGlobal('BFILE', "config")); | ||
16 | + &outputConfig; | ||
17 | |||
18 | # Run Bastille | ||
19 | |||
diff --git a/dynamic-layers/meta-perl/recipes-security/bastille/files/config b/dynamic-layers/meta-perl/recipes-security/bastille/files/config new file mode 100755 index 0000000..9e5e206 --- /dev/null +++ b/dynamic-layers/meta-perl/recipes-security/bastille/files/config | |||
@@ -0,0 +1,106 @@ | |||
1 | # Q: Would you like to enforce password aging? [Y] | ||
2 | AccountSecurity.passwdage="Y" | ||
3 | # Q: Should Bastille disable clear-text r-protocols that use IP-based authentication? [Y] | ||
4 | AccountSecurity.protectrhost="Y" | ||
5 | # Q: Should we disallow root login on tty's 1-6? [N] | ||
6 | AccountSecurity.rootttylogins="Y" | ||
7 | # Q: What umask would you like to set for users on the system? [077] | ||
8 | AccountSecurity.umask="077" | ||
9 | # Q: Do you want to set the default umask? [Y] | ||
10 | AccountSecurity.umaskyn="Y" | ||
11 | # Q: Would you like to deactivate the Apache web server? [Y] | ||
12 | Apache.apacheoff="Y" | ||
13 | # Q: Would you like to password protect single-user mode? [Y] | ||
14 | BootSecurity.passsum="Y" | ||
15 | # Q: Should we restrict console access to a small group of user accounts? [N] | ||
16 | ConfigureMiscPAM.consolelogin="Y" | ||
17 | # Q: Which accounts should be able to login at console? [root] | ||
18 | ConfigureMiscPAM.consolelogin_accounts="root" | ||
19 | # Q: Would you like to put limits on system resource usage? [N] | ||
20 | ConfigureMiscPAM.limitsconf="Y" | ||
21 | # Q: Would you like to set more restrictive permissions on the administration utilities? [N] | ||
22 | FilePermissions.generalperms_1_1="Y" | ||
23 | # Q: Would you like to disable SUID status for mount/umount? | ||
24 | FilePermissions.suidmount="Y" | ||
25 | # Q: Would you like to disable SUID status for ping? [Y] | ||
26 | FilePermissions.suidping="Y" | ||
27 | # Q: Would you like to disable SUID status for traceroute? [Y] | ||
28 | FilePermissions.suidtrace="Y" | ||
29 | # Q: Do you need the advanced networking options? | ||
30 | Firewall.ip_advnetwork="Y" | ||
31 | # Q: Should Bastille run the firewall and enable it at boot time? [N] | ||
32 | Firewall.ip_enable_firewall="Y" | ||
33 | # Q: Would you like to run the packet filtering script? [N] | ||
34 | Firewall.ip_intro="Y" | ||
35 | # Q: Interfaces for DHCP queries: [ ] | ||
36 | Firewall.ip_s_dhcpiface=" " | ||
37 | # Q: DNS servers: [0.0.0.0/0] | ||
38 | Firewall.ip_s_dns="10.184.9.1" | ||
39 | # Q: ICMP allowed types: [destination-unreachable echo-reply time-exceeded] | ||
40 | Firewall.ip_s_icmpallowed="destination-unreachable echo-reply time-exceeded" | ||
41 | # Q: ICMP services to audit: [ ] | ||
42 | Firewall.ip_s_icmpaudit=" " | ||
43 | # Q: ICMP types to disallow outbound: [destination-unreachable time-exceeded] | ||
44 | Firewall.ip_s_icmpout="destination-unreachable time-exceeded" | ||
45 | # Q: Internal interfaces: [ ] | ||
46 | Firewall.ip_s_internaliface=" " | ||
47 | # Q: TCP service names or port numbers to allow on private interfaces: [ ] | ||
48 | Firewall.ip_s_internaltcp=" " | ||
49 | # Q: UDP service names or port numbers to allow on private interfaces: [ ] | ||
50 | Firewall.ip_s_internaludp=" " | ||
51 | # Q: Masqueraded networks: [ ] | ||
52 | Firewall.ip_s_ipmasq=" " | ||
53 | # Q: Kernel modules to masquerade: [ftp raudio vdolive] | ||
54 | Firewall.ip_s_kernelmasq="ftp raudio vdolive" | ||
55 | # Q: NTP servers to query: [ ] | ||
56 | Firewall.ip_s_ntpsrv=" " | ||
57 | # Q: Force passive mode? [N] | ||
58 | Firewall.ip_s_passiveftp="N" | ||
59 | # Q: Public interfaces: [eth+ ppp+ slip+] | ||
60 | Firewall.ip_s_publiciface="eth+ ppp+ slip+" | ||
61 | # Q: TCP service names or port numbers to allow on public interfaces:[ ] | ||
62 | Firewall.ip_s_publictcp=" " | ||
63 | # Q: UDP service names or port numbers to allow on public interfaces:[ ] | ||
64 | Firewall.ip_s_publicudp=" " | ||
65 | # Q: Reject method: [DENY] | ||
66 | Firewall.ip_s_rejectmethod="DENY" | ||
67 | # Q: Enable source address verification? [Y] | ||
68 | Firewall.ip_s_srcaddr="Y" | ||
69 | # Q: TCP services to audit: [telnet ftp imap pop3 finger sunrpc exec login linuxconf ssh] | ||
70 | Firewall.ip_s_tcpaudit="telnet ftp imap pop3 finger sunrpc exec login linuxconf ssh" | ||
71 | # Q: TCP services to block: [2049 2065:2090 6000:6020 7100] | ||
72 | Firewall.ip_s_tcpblock="2049 2065:2090 6000:6020 7100" | ||
73 | # Q: Trusted interface names: [lo] | ||
74 | Firewall.ip_s_trustiface="lo" | ||
75 | # Q: UDP services to audit: [31337] | ||
76 | Firewall.ip_s_udpaudit="31337" | ||
77 | # Q: UDP services to block: [2049 6770] | ||
78 | Firewall.ip_s_udpblock="2049 6770" | ||
79 | # Q: Would you like to add additional logging? [Y] | ||
80 | Logging.morelogging="Y" | ||
81 | # Q: Would you like to set up process accounting? [N] | ||
82 | Logging.pacct="N" | ||
83 | # Q: Do you have a remote logging host? [N] | ||
84 | Logging.remotelog="N" | ||
85 | # Q: Would you like to disable acpid and/or apmd? [Y] | ||
86 | MiscellaneousDaemons.apmd="Y" | ||
87 | # Q: Would you like to deactivate NFS and Samba? [Y] | ||
88 | MiscellaneousDaemons.remotefs="Y" | ||
89 | # Q: Would you like to disable printing? [N] | ||
90 | Printing.printing="Y" | ||
91 | # Q: Would you like to disable printing? [N] | ||
92 | Printing.printing_cups="Y" | ||
93 | # Q: Would you like to display "Authorized Use" messages at log-in time? [Y] | ||
94 | SecureInetd.banners="Y" | ||
95 | # Q: Should Bastille ensure inetd's FTP service does not run on this system? [y] | ||
96 | SecureInetd.deactivate_ftp="Y" | ||
97 | # Q: Should Bastille ensure the telnet service does not run on this system? [y] | ||
98 | SecureInetd.deactivate_telnet="Y" | ||
99 | # Q: Who is responsible for granting authorization to use this machine? | ||
100 | SecureInetd.owner="its owner" | ||
101 | # Q: Would you like to set a default-deny on TCP Wrappers and xinetd? [N] | ||
102 | SecureInetd.tcpd_default_deny="Y" | ||
103 | # Q: Do you want to stop sendmail from running in daemon mode? [Y] | ||
104 | Sendmail.sendmaildaemon="Y" | ||
105 | # Q: Would you like to install TMPDIR/TMP scripts? [N] | ||
106 | TMPDIR.tmpdir="N" | ||
diff --git a/dynamic-layers/meta-perl/recipes-security/bastille/files/do_not_apply_config.patch b/dynamic-layers/meta-perl/recipes-security/bastille/files/do_not_apply_config.patch new file mode 100644 index 0000000..574aa98 --- /dev/null +++ b/dynamic-layers/meta-perl/recipes-security/bastille/files/do_not_apply_config.patch | |||
@@ -0,0 +1,40 @@ | |||
1 | Upstream Status: Inappropriate [No upstream maintenance] | ||
2 | |||
3 | Signed-off-by: Anne Mulhern <mulhern@yoctoproject.org> | ||
4 | |||
5 | --- | ||
6 | |||
7 | Index: Bastille/Bastille_Curses.pm | ||
8 | =================================================================== | ||
9 | --- Bastille.orig/Bastille_Curses.pm 2013-08-27 16:43:39.130959000 -0400 | ||
10 | +++ Bastille/Bastille_Curses.pm 2013-08-27 16:43:39.794959000 -0400 | ||
11 | @@ -83,11 +83,6 @@ | ||
12 | # Output answers to the script and display | ||
13 | &outputConfig; | ||
14 | |||
15 | - # Run Bastille | ||
16 | - | ||
17 | - &Run_Bastille_with_Config; | ||
18 | - | ||
19 | - | ||
20 | # Display Credits | ||
21 | |||
22 | open CREDITS,"/usr/share/Bastille/Credits"; | ||
23 | Index: Bastille/InteractiveBastille | ||
24 | =================================================================== | ||
25 | --- Bastille.orig/InteractiveBastille 2013-08-27 16:43:39.434959000 -0400 | ||
26 | +++ Bastille/InteractiveBastille 2013-08-27 17:18:55.758959000 -0400 | ||
27 | @@ -531,10 +531,10 @@ | ||
28 | " Please address bug reports and suggestions to jay\@bastille-linux.org\n" . | ||
29 | "\n"; | ||
30 | |||
31 | - $InterfaceEndScreenDescription = "We will now implement the choices you have made here.\n\n" . | ||
32 | + $InterfaceEndScreenDescription = "We will now record the choices you have made here.\n\n" . | ||
33 | "Answer NO if you want to go back and make changes!\n"; | ||
34 | - $InterfaceEndScreenQuestion = "Are you finished answering the questions, i.e. may we make the changes?"; | ||
35 | - $InterfaceEndScreenNoEpilogue = "Please use Back/Next buttons to move among the questions you wish to\nchange.\n\nChoose YES on this question later to implement your choices.\n"; | ||
36 | + $InterfaceEndScreenQuestion = "Are you finished answering the questions, i.e. may we record the answers and exit?"; | ||
37 | + $InterfaceEndScreenNoEpilogue = "Please use Back/Next buttons to move among the questions you wish to\nchange.\n\nChoose YES on this question later to record your choices.\n"; | ||
38 | require Bastille_Curses; | ||
39 | } elsif ($GLOBAL_AUDITONLY) { | ||
40 | |||
diff --git a/dynamic-layers/meta-perl/recipes-security/bastille/files/edit_usage_message.patch b/dynamic-layers/meta-perl/recipes-security/bastille/files/edit_usage_message.patch new file mode 100644 index 0000000..72cdc2f --- /dev/null +++ b/dynamic-layers/meta-perl/recipes-security/bastille/files/edit_usage_message.patch | |||
@@ -0,0 +1,32 @@ | |||
1 | Upstream Status: Inappropriate [No upstream maintenance] | ||
2 | |||
3 | Signed-off-by: Anne Mulhern <mulhern@yoctoproject.org> | ||
4 | |||
5 | --- | ||
6 | |||
7 | Index: Bastille/bin/bastille | ||
8 | =================================================================== | ||
9 | --- Bastille.orig/bin/bastille 2013-08-25 14:16:35.614779001 -0400 | ||
10 | +++ Bastille/bin/bastille 2013-08-25 14:16:38.674779000 -0400 | ||
11 | @@ -60,7 +60,7 @@ | ||
12 | printUsage () { | ||
13 | cat >&2 << EOF | ||
14 | $ERRSPACES Usage: bastille [ -b | -c | -x ] [ --os <version>] [ -f <alternate config> ] | ||
15 | -$ERRSPACES bastille [-r | -l | -h | --assess | --assessnobrowser ] | ||
16 | +$ERRSPACES bastille [-r | -l | -h | --assess | --assessnobrowser ] [ --os <version> ] | ||
17 | $ERRSPACES -b : use a saved config file to apply changes | ||
18 | $ERRSPACES directly to system | ||
19 | $ERRSPACES -c : use the Curses (non-X11) GUI, not available on HP-UX | ||
20 | Index: Bastille/Bastille/API.pm | ||
21 | =================================================================== | ||
22 | --- Bastille.orig/Bastille/API.pm 2013-08-25 08:15:40.266779002 -0400 | ||
23 | +++ Bastille/Bastille/API.pm 2013-08-25 14:18:22.750778811 -0400 | ||
24 | @@ -206,7 +206,7 @@ | ||
25 | #options before interactive or Bastille runs, so this check is often redundant | ||
26 | $GLOBAL_ERROR{"usage"}="\n". | ||
27 | "$spc Usage: bastille [ -b | -c | -x ] [ --os <version> ] [ -f <alternate config> ]\n". | ||
28 | - "$spc bastille [ -r | --assess | --assessnobowser ]\n\n". | ||
29 | + "$spc bastille [ -r | --assess | --assessnobowser ] [ --os <version> ]\n\n". | ||
30 | "$spc --assess : check status of system and report in browser\n". | ||
31 | "$spc --assessnobrowser : check status of system and list report locations\n". | ||
32 | "$spc -b : use a saved config file to apply changes\n". | ||
diff --git a/dynamic-layers/meta-perl/recipes-security/bastille/files/find_existing_config.patch b/dynamic-layers/meta-perl/recipes-security/bastille/files/find_existing_config.patch new file mode 100644 index 0000000..c075875 --- /dev/null +++ b/dynamic-layers/meta-perl/recipes-security/bastille/files/find_existing_config.patch | |||
@@ -0,0 +1,64 @@ | |||
1 | Upstream Status: Inappropriate [No upstream maintenance] | ||
2 | |||
3 | Signed-off-by: Anne Mulhern <mulhern@yoctoproject.org> | ||
4 | |||
5 | --- | ||
6 | |||
7 | Index: Bastille/bin/bastille | ||
8 | =================================================================== | ||
9 | --- Bastille.orig/bin/bastille 2013-06-20 14:58:01.065796000 -0400 | ||
10 | +++ Bastille/bin/bastille 2013-08-20 15:16:18.472378000 -0400 | ||
11 | @@ -102,8 +102,9 @@ | ||
12 | # defines OS specific file locations based on uname | ||
13 | systemFileLocations | ||
14 | |||
15 | + config_files=`find $config_repository -type f -name \*config 2>/dev/null` | ||
16 | + | ||
17 | if [ -f $last_config ]; then | ||
18 | - config_files=`find $config_repository -type f -name \*config 2>/dev/null` | ||
19 | for config_cursor in `echo $config_files` | ||
20 | do | ||
21 | if /usr/bin/diff $last_config $config_cursor >/dev/null 2>&1 | ||
22 | @@ -112,8 +113,8 @@ | ||
23 | fi | ||
24 | done | ||
25 | if [ -n "$match" ]; then | ||
26 | - echo "The last bastille run corresponds to the following profiles:" | ||
27 | - echo "$match" | ||
28 | + printf "The last Bastille run corresponds to the following profiles:\n" | ||
29 | + printf "$match" | ||
30 | else | ||
31 | cat >&2 << EOF | ||
32 | NOTE: The last config file applied, | ||
33 | @@ -122,18 +123,28 @@ | ||
34 | $ERRSPACES $config_repository. | ||
35 | $ERRSPACES This probably means that Bastille was last run interactively and | ||
36 | $ERRSPACES changes were made to the config file, but they have not yet been | ||
37 | -$ERRSPACES applied, or that the source config file was moved. If you do have pending | ||
38 | +$ERRSPACES applied, or that the source config file was moved. If you do have pending | ||
39 | $ERRSPACES changes in a config file, you can apply them by running | ||
40 | $ERRSPACES 'bastille -b -f <config file>.' | ||
41 | EOF | ||
42 | |||
43 | fi | ||
44 | else | ||
45 | - echo "NOTE: The system is in its pre-bastilled state.\n" | ||
46 | + for config_cursor in `echo $config_files` | ||
47 | + do | ||
48 | + match="$match $config_cursor\n" | ||
49 | + done | ||
50 | + if [ -n "$match" ]; then | ||
51 | + printf "The following Bastille profiles were located:\n" | ||
52 | + printf "$match" | ||
53 | + else | ||
54 | + printf "No Bastille profiles were located.\n" | ||
55 | + fi | ||
56 | + printf "No log files of profiles from previous executions of Bastille have been found. It is likely that Bastille has not been run on this machine.\n" | ||
57 | fi | ||
58 | - | ||
59 | } | ||
60 | |||
61 | + | ||
62 | # First, make sure we're root | ||
63 | if [ `PATH="/usr/bin:/bin"; id -u` -ne 0 ]; then | ||
64 | echo "ERROR: Bastille must be run as root user" >&2 | ||
diff --git a/dynamic-layers/meta-perl/recipes-security/bastille/files/fix_missing_use_directives.patch b/dynamic-layers/meta-perl/recipes-security/bastille/files/fix_missing_use_directives.patch new file mode 100644 index 0000000..05f145a --- /dev/null +++ b/dynamic-layers/meta-perl/recipes-security/bastille/files/fix_missing_use_directives.patch | |||
@@ -0,0 +1,54 @@ | |||
1 | Upstream Status: Inappropriate [No upstream maintenance] | ||
2 | |||
3 | Signed-off-by: Anne Mulhern <mulhern@yoctoproject.org> | ||
4 | |||
5 | --- | ||
6 | |||
7 | Index: Bastille/Bastille/Firewall.pm | ||
8 | =================================================================== | ||
9 | --- Bastille.orig/Bastille/Firewall.pm 2008-09-14 19:56:54.000000000 -0400 | ||
10 | +++ Bastille/Bastille/Firewall.pm 2013-08-20 16:28:44.588378000 -0400 | ||
11 | @@ -21,6 +21,7 @@ | ||
12 | package Bastille::Firewall; | ||
13 | |||
14 | use Bastille::API; | ||
15 | +use Bastille::API::AccountPermission; | ||
16 | use Bastille::API::FileContent; | ||
17 | use Bastille::API::ServiceAdmin; | ||
18 | |||
19 | Index: Bastille/Bastille/SecureInetd.pm | ||
20 | =================================================================== | ||
21 | --- Bastille.orig/Bastille/SecureInetd.pm 2008-09-14 19:56:58.000000000 -0400 | ||
22 | +++ Bastille/Bastille/SecureInetd.pm 2013-08-20 16:45:02.252378001 -0400 | ||
23 | @@ -12,6 +12,7 @@ | ||
24 | use lib "/usr/lib"; | ||
25 | |||
26 | use Bastille::API; | ||
27 | +use Bastille::API::AccountPermission; | ||
28 | use Bastille::API::HPSpecific; | ||
29 | use Bastille::API::ServiceAdmin; | ||
30 | use Bastille::API::FileContent; | ||
31 | Index: Bastille/Bastille/ConfigureMiscPAM.pm | ||
32 | =================================================================== | ||
33 | --- Bastille.orig/Bastille/ConfigureMiscPAM.pm 2005-09-12 23:47:28.000000000 -0400 | ||
34 | +++ Bastille/Bastille/ConfigureMiscPAM.pm 2013-08-20 18:36:07.340378001 -0400 | ||
35 | @@ -5,6 +5,7 @@ | ||
36 | use lib "/usr/lib"; | ||
37 | |||
38 | use Bastille::API; | ||
39 | +use Bastille::API::FileContent; | ||
40 | |||
41 | # To DO: | ||
42 | # | ||
43 | Index: Bastille/Bastille/Printing.pm | ||
44 | =================================================================== | ||
45 | --- Bastille.orig/Bastille/Printing.pm 2008-09-14 19:56:58.000000000 -0400 | ||
46 | +++ Bastille/Bastille/Printing.pm 2013-08-20 19:05:01.532378002 -0400 | ||
47 | @@ -5,6 +5,7 @@ | ||
48 | use lib "/usr/lib"; | ||
49 | |||
50 | use Bastille::API; | ||
51 | +use Bastille::API::AccountPermission; | ||
52 | use Bastille::API::HPSpecific; | ||
53 | use Bastille::API::ServiceAdmin; | ||
54 | use Bastille::API::FileContent; | ||
diff --git a/dynamic-layers/meta-perl/recipes-security/bastille/files/fix_number_of_modules.patch b/dynamic-layers/meta-perl/recipes-security/bastille/files/fix_number_of_modules.patch new file mode 100644 index 0000000..743e549 --- /dev/null +++ b/dynamic-layers/meta-perl/recipes-security/bastille/files/fix_number_of_modules.patch | |||
@@ -0,0 +1,38 @@ | |||
1 | Upstream Status: Inappropriate [No upstream maintenance] | ||
2 | |||
3 | Signed-off-by: Anne Mulhern <mulhern@yoctoproject.org> | ||
4 | |||
5 | --- | ||
6 | |||
7 | Index: Bastille/Bastille_Curses.pm | ||
8 | =================================================================== | ||
9 | --- Bastille.orig/Bastille_Curses.pm 2013-08-24 18:21:54.445288000 -0400 | ||
10 | +++ Bastille/Bastille_Curses.pm 2013-08-24 18:29:16.981288000 -0400 | ||
11 | @@ -36,9 +36,6 @@ | ||
12 | use Curses; | ||
13 | use Curses::Widgets; | ||
14 | |||
15 | - # Number_Modules is the number of modules loaded in by Load_Questions | ||
16 | - $Number_Modules=0; | ||
17 | - | ||
18 | # | ||
19 | # Highlighted button is the button currently chosen in the button bar | ||
20 | # We preserve this from question to question... | ||
21 | @@ -397,7 +394,7 @@ | ||
22 | my $title; | ||
23 | |||
24 | if ($module) { | ||
25 | - $title=$module . " of $Number_Modules"; | ||
26 | + $title=$module; | ||
27 | } | ||
28 | |||
29 | txt_field( 'window' => $window, | ||
30 | @@ -488,7 +485,7 @@ | ||
31 | my $title; | ||
32 | |||
33 | if ($module) { | ||
34 | - $title=$module . " of $Number_Modules"; | ||
35 | + $title=$module; | ||
36 | } | ||
37 | |||
38 | noecho; | ||
diff --git a/dynamic-layers/meta-perl/recipes-security/bastille/files/fix_version_parse.patch b/dynamic-layers/meta-perl/recipes-security/bastille/files/fix_version_parse.patch new file mode 100644 index 0000000..5923c04 --- /dev/null +++ b/dynamic-layers/meta-perl/recipes-security/bastille/files/fix_version_parse.patch | |||
@@ -0,0 +1,27 @@ | |||
1 | Upstream Status: Inappropriate [No upstream maintenance] | ||
2 | |||
3 | Signed-off-by: Anne Mulhern <mulhern@yoctoproject.org> | ||
4 | |||
5 | --- | ||
6 | |||
7 | Index: Bastille/bin/bastille | ||
8 | =================================================================== | ||
9 | --- Bastille.orig/bin/bastille | ||
10 | +++ Bastille/bin/bastille | ||
11 | @@ -162,11 +162,12 @@ fi | ||
12 | # We check that the version is at least the minimum | ||
13 | |||
14 | PERL_VERSION=`${CURRENT_PERL_PATH}/perl -version | | ||
15 | - head -2 | # the second line contains the version | ||
16 | + head -n 2 | # the second line contains the version | ||
17 | tr " " "\n" | # split words into separate lines | ||
18 | - sed -e "s/^v//" | # to get rid of the v in v5.6.0 | ||
19 | - grep "^[1-9]\." | # find a "word" that starts with number dot | ||
20 | - sed -e "s/_/./"` # substitute _patchlevel with .patchlevel | ||
21 | + grep "^(v" | # find a "word" that starts with '(v' | ||
22 | + sed -e "s/^(v//" -e "s/)//" -e "s/_/./"` | ||
23 | + # to get rid of the (v in v5.6.0 | ||
24 | + # substitute _patchlevel with .patchlevel | ||
25 | # (used in 5.005_03 and prior) | ||
26 | |||
27 | # everything before the first . | ||
diff --git a/dynamic-layers/meta-perl/recipes-security/bastille/files/fixed_defined_warnings.patch b/dynamic-layers/meta-perl/recipes-security/bastille/files/fixed_defined_warnings.patch new file mode 100644 index 0000000..e7996e3 --- /dev/null +++ b/dynamic-layers/meta-perl/recipes-security/bastille/files/fixed_defined_warnings.patch | |||
@@ -0,0 +1,65 @@ | |||
1 | From c59b84ca3bda8e4244d47901b6966f28dd675434 Mon Sep 17 00:00:00 2001 | ||
2 | From: Andrei Dinu <andrei.adrianx.dinu@intel.com> | ||
3 | Date: Thu, 23 May 2013 15:12:23 +0300 | ||
4 | Subject: [PATCH] added yocto-standard to bastille | ||
5 | |||
6 | In order to make Bastille functional and avoid errors | ||
7 | regarding distros, if not any given distro is identified, | ||
8 | yocto-standard distro is added to the distro variable | ||
9 | in Bastille. | ||
10 | |||
11 | Fixed also some warnings regarding defined statements | ||
12 | in API.pm. | ||
13 | |||
14 | Upstream Status: Inappropriate [No upstream maintenance] | ||
15 | |||
16 | Signed-off-by: Andrei Dinu <andrei.adrianx.dinu@intel.com> | ||
17 | |||
18 | Signed-off-by: Anne Mulhern <mulhern@yoctoproject.org> | ||
19 | |||
20 | --- | ||
21 | Bastille/API.pm | 12 ++++++------ | ||
22 | 1 file changed, 6 insertions(+), 6 deletions(-) | ||
23 | |||
24 | Index: Bastille/Bastille/API.pm | ||
25 | =================================================================== | ||
26 | --- Bastille.orig/Bastille/API.pm 2008-09-14 19:56:53.000000000 -0400 | ||
27 | +++ Bastille/Bastille/API.pm 2013-08-21 08:55:26.715950001 -0400 | ||
28 | @@ -445,8 +445,8 @@ | ||
29 | $release=`/usr/bin/uname -sr`; | ||
30 | } | ||
31 | else { | ||
32 | - print STDERR "$err Could not determine operating system version!\n"; | ||
33 | - $distro="unknown"; | ||
34 | + print STDERR "$err Could not determine operating system version!\n"; | ||
35 | + $distro="unknown" | ||
36 | } | ||
37 | |||
38 | # Figure out what kind of system we're on. | ||
39 | @@ -1284,7 +1284,7 @@ | ||
40 | |||
41 | my $sumFile = &getGlobal('BFILE',"sum.csv"); | ||
42 | |||
43 | - if ( defined %GLOBAL_SUM ) { | ||
44 | + if ( %GLOBAL_SUM ) { | ||
45 | |||
46 | open( SUM, "> $sumFile") or &B_log("ERROR","Unable to open $sumFile for write.\n$!\n"); | ||
47 | |||
48 | @@ -1318,7 +1318,7 @@ | ||
49 | my $file = $_[0]; | ||
50 | my $cksum = &getGlobal('BIN',"cksum"); | ||
51 | |||
52 | - if (not(defined(%GLOBAL_SUM))) { | ||
53 | + if (not(%GLOBAL_SUM)) { | ||
54 | &B_read_sums; | ||
55 | } | ||
56 | |||
57 | @@ -1375,7 +1375,7 @@ | ||
58 | sub B_isFileinSumDB($) { | ||
59 | my $file = $_[0]; | ||
60 | |||
61 | - if (not(defined(%GLOBAL_SUM))) { | ||
62 | + if (not(%GLOBAL_SUM)) { | ||
63 | &B_log("DEBUG","Reading in DB from B_isFileinSumDB"); | ||
64 | &B_read_sums; | ||
65 | } | ||
diff --git a/dynamic-layers/meta-perl/recipes-security/bastille/files/organize_distro_discovery.patch b/dynamic-layers/meta-perl/recipes-security/bastille/files/organize_distro_discovery.patch new file mode 100644 index 0000000..d64d1e2 --- /dev/null +++ b/dynamic-layers/meta-perl/recipes-security/bastille/files/organize_distro_discovery.patch | |||
@@ -0,0 +1,476 @@ | |||
1 | Upstream Status: Inappropriate [No upstream maintenance] | ||
2 | |||
3 | Signed-off-by: Anne Mulhern <mulhern@yoctoproject.org> | ||
4 | |||
5 | --- | ||
6 | |||
7 | Index: Bastille/Bastille/API.pm | ||
8 | =================================================================== | ||
9 | --- Bastille.orig/Bastille/API.pm 2013-08-22 04:32:38.269968002 -0400 | ||
10 | +++ Bastille/Bastille/API.pm 2013-08-22 11:29:53.137968002 -0400 | ||
11 | @@ -141,7 +141,7 @@ | ||
12 | checkProcsForService | ||
13 | |||
14 | |||
15 | - $GLOBAL_OS $GLOBAL_ACTUAL_OS $CLI | ||
16 | + $CLI | ||
17 | $GLOBAL_LOGONLY $GLOBAL_VERBOSE $GLOBAL_DEBUG $GLOBAL_AUDITONLY $GLOBAL_AUDIT_NO_BROWSER $errorFlag | ||
18 | %GLOBAL_BIN %GLOBAL_DIR %GLOBAL_FILE | ||
19 | %GLOBAL_BDIR %GLOBAL_BFILE | ||
20 | @@ -198,7 +198,7 @@ | ||
21 | my $err ="ERROR: "; | ||
22 | my $spc =" "; | ||
23 | my $GLOBAL_OS="None"; | ||
24 | -my $GLOBAL_ACTUAL_OS="None"; | ||
25 | +my $GLOBAL_INFERRED_OS="None"; | ||
26 | my %GLOBAL_SUMS=(); | ||
27 | my $CLI=''; | ||
28 | |||
29 | @@ -306,7 +306,7 @@ | ||
30 | |||
31 | ########################################################################### | ||
32 | # | ||
33 | -# GetDistro checks to see if the target is a known distribution and reports | ||
34 | +# InferDistro checks to see if the target is a known distribution and reports | ||
35 | # said distribution. | ||
36 | # | ||
37 | # This is used throughout the script, but also by ConfigureForDistro. | ||
38 | @@ -314,205 +314,194 @@ | ||
39 | # | ||
40 | ########################################################################### | ||
41 | |||
42 | -sub GetDistro() { | ||
43 | +sub InferDistro() { | ||
44 | |||
45 | my ($release,$distro); | ||
46 | |||
47 | - # Only read files for the distro once. | ||
48 | - # if the --os option was used then | ||
49 | - if ($GLOBAL_OS eq "None") { | ||
50 | - if ( -e "/etc/mandrake-release" ) { | ||
51 | - open(MANDRAKE_RELEASE,"/etc/mandrake-release"); | ||
52 | - $release=<MANDRAKE_RELEASE>; | ||
53 | - | ||
54 | - if ( ($release =~ /^Mandrake Linux release (\d+\.\d+\w*)/) or ($release =~ /^Linux Mandrake release (\d+\.\d+\w*)/) ) { | ||
55 | - $distro="MN$1"; | ||
56 | - } | ||
57 | - elsif ( $release =~ /^Mandrakelinux release (\d+\.\d+)\b/ ) { | ||
58 | - $distro="MN$1"; | ||
59 | - } | ||
60 | - else { | ||
61 | - print STDERR "$err Couldn't determine Mandrake/Mandriva version! Setting to 10.1!\n"; | ||
62 | - $distro="MN10.1"; | ||
63 | - } | ||
64 | - | ||
65 | - close(MANDRAKE_RELEASE); | ||
66 | - } | ||
67 | - elsif ( -e "/etc/immunix-release" ) { | ||
68 | - open(IMMUNIX_RELEASE,"/etc/immunix-release"); | ||
69 | - $release=<IMMUNIX_RELEASE>; | ||
70 | - unless ($release =~ /^Immunix Linux release (\d+\.\d+\w*)/) { | ||
71 | - print STDERR "$err Couldn't determine Immunix version! Setting to 6.2!\n"; | ||
72 | - $distro="RH6.2"; | ||
73 | - } | ||
74 | - else { | ||
75 | - $distro="RH$1"; | ||
76 | - } | ||
77 | - close(*IMMUNIX_RELEASE); | ||
78 | - } | ||
79 | - elsif ( -e '/etc/fedora-release' ) { | ||
80 | - open(FEDORA_RELEASE,'/etc/fedora-release'); | ||
81 | - $release=<FEDORA_RELEASE>; | ||
82 | - close FEDORA_RELEASE; | ||
83 | - if ($release =~ /^Fedora Core release (\d+\.?\d*)/) { | ||
84 | - $distro = "RHFC$1"; | ||
85 | - } | ||
86 | - elsif ($release =~ /^Fedora release (\d+\.?\d*)/) { | ||
87 | - $distro = "RHFC$1"; | ||
88 | - } | ||
89 | - else { | ||
90 | - print STDERR "$err Could not determine Fedora version! Setting to Fedora Core 8\n"; | ||
91 | - $distro='RHFC8'; | ||
92 | - } | ||
93 | + if ( -e "/etc/mandrake-release" ) { | ||
94 | + open(MANDRAKE_RELEASE,"/etc/mandrake-release"); | ||
95 | + $release=<MANDRAKE_RELEASE>; | ||
96 | + | ||
97 | + if ( ($release =~ /^Mandrake Linux release (\d+\.\d+\w*)/) or ($release =~ /^Linux Mandrake release (\d+\.\d+\w*)/) ) { | ||
98 | + $distro="MN$1"; | ||
99 | + } | ||
100 | + elsif ( $release =~ /^Mandrakelinux release (\d+\.\d+)\b/ ) { | ||
101 | + $distro="MN$1"; | ||
102 | + } | ||
103 | + else { | ||
104 | + print STDERR "$err Could not infer Mandrake/Mandriva version! Setting to 10.1!\n"; | ||
105 | + $distro="MN10.1"; | ||
106 | + } | ||
107 | + | ||
108 | + close(MANDRAKE_RELEASE); | ||
109 | + } | ||
110 | + elsif ( -e "/etc/immunix-release" ) { | ||
111 | + open(IMMUNIX_RELEASE,"/etc/immunix-release"); | ||
112 | + $release=<IMMUNIX_RELEASE>; | ||
113 | + unless ($release =~ /^Immunix Linux release (\d+\.\d+\w*)/) { | ||
114 | + print STDERR "$err Could not infer Immunix version! Setting to 6.2!\n"; | ||
115 | + $distro="RH6.2"; | ||
116 | + } | ||
117 | + else { | ||
118 | + $distro="RH$1"; | ||
119 | } | ||
120 | - elsif ( -e "/etc/redhat-release" ) { | ||
121 | - open(*REDHAT_RELEASE,"/etc/redhat-release"); | ||
122 | - $release=<REDHAT_RELEASE>; | ||
123 | - if ($release =~ /^Red Hat Linux release (\d+\.?\d*\w*)/) { | ||
124 | - $distro="RH$1"; | ||
125 | - } | ||
126 | - elsif ($release =~ /^Red Hat Linux .+ release (\d+)\.?\d*([AEW]S)/) { | ||
127 | - $distro="RHEL$1$2"; | ||
128 | - } | ||
129 | - elsif ($release =~ /^Red Hat Enterprise Linux ([AEW]S) release (\d+)/) { | ||
130 | - $distro="RHEL$2$1"; | ||
131 | + close(*IMMUNIX_RELEASE); | ||
132 | + } | ||
133 | + elsif ( -e '/etc/fedora-release' ) { | ||
134 | + open(FEDORA_RELEASE,'/etc/fedora-release'); | ||
135 | + $release=<FEDORA_RELEASE>; | ||
136 | + close FEDORA_RELEASE; | ||
137 | + if ($release =~ /^Fedora Core release (\d+\.?\d*)/) { | ||
138 | + $distro = "RHFC$1"; | ||
139 | + } | ||
140 | + elsif ($release =~ /^Fedora release (\d+\.?\d*)/) { | ||
141 | + $distro = "RHFC$1"; | ||
142 | + } | ||
143 | + else { | ||
144 | + print STDERR "$err Could not infer Fedora version! Setting to Fedora Core 8\n"; | ||
145 | + $distro='RHFC8'; | ||
146 | + } | ||
147 | + } | ||
148 | + elsif ( -e "/etc/redhat-release" ) { | ||
149 | + open(*REDHAT_RELEASE,"/etc/redhat-release"); | ||
150 | + $release=<REDHAT_RELEASE>; | ||
151 | + if ($release =~ /^Red Hat Linux release (\d+\.?\d*\w*)/) { | ||
152 | + $distro="RH$1"; | ||
153 | + } | ||
154 | + elsif ($release =~ /^Red Hat Linux .+ release (\d+)\.?\d*([AEW]S)/) { | ||
155 | + $distro="RHEL$1$2"; | ||
156 | + } | ||
157 | + elsif ($release =~ /^Red Hat Enterprise Linux ([AEW]S) release (\d+)/) { | ||
158 | + $distro="RHEL$2$1"; | ||
159 | + } | ||
160 | + elsif ($release =~ /^CentOS release (\d+\.\d+)/) { | ||
161 | + my $version = $1; | ||
162 | + if ($version =~ /^4\./) { | ||
163 | + $distro='RHEL4AS'; | ||
164 | } | ||
165 | - elsif ($release =~ /^CentOS release (\d+\.\d+)/) { | ||
166 | - my $version = $1; | ||
167 | - if ($version =~ /^4\./) { | ||
168 | - $distro='RHEL4AS'; | ||
169 | - } | ||
170 | - elsif ($version =~ /^3\./) { | ||
171 | - $distro='RHEL3AS'; | ||
172 | - } | ||
173 | - else { | ||
174 | - print STDERR "$err Could not determine CentOS version! Setting to Red Hat Enterprise 4 AS.\n"; | ||
175 | - $distro='RHEL4AS'; | ||
176 | - } | ||
177 | - } | ||
178 | - else { | ||
179 | - # JJB/HP - Should this be B_log? | ||
180 | - print STDERR "$err Couldn't determine Red Hat version! Setting to 9!\n"; | ||
181 | - $distro="RH9"; | ||
182 | - } | ||
183 | - close(REDHAT_RELEASE); | ||
184 | - | ||
185 | - } | ||
186 | - elsif ( -e "/etc/debian_version" ) { | ||
187 | - $stable="3.1"; #Change this when Debian stable changes | ||
188 | - open(*DEBIAN_RELEASE,"/etc/debian_version"); | ||
189 | - $release=<DEBIAN_RELEASE>; | ||
190 | - unless ($release =~ /^(\d+\.\d+\w*)/) { | ||
191 | - print STDERR "$err System is not running a stable Debian GNU/Linux version. Setting to $stable.\n"; | ||
192 | - $distro="DB$stable"; | ||
193 | + elsif ($version =~ /^3\./) { | ||
194 | + $distro='RHEL3AS'; | ||
195 | } | ||
196 | else { | ||
197 | - $distro="DB$1"; | ||
198 | - } | ||
199 | - close(DEBIAN_RELEASE); | ||
200 | - } | ||
201 | - elsif ( -e "/etc/SuSE-release" ) { | ||
202 | - open(*SUSE_RELEASE,"/etc/SuSE-release"); | ||
203 | - $release=<SUSE_RELEASE>; | ||
204 | - if ($release =~ /^SuSE Linux (\d+\.\d+\w*)/i) { | ||
205 | - $distro="SE$1"; | ||
206 | - } | ||
207 | - elsif ($release =~ /^SUSE LINUX Enterprise Server (\d+\.?\d?\w*)/i) { | ||
208 | - $distro="SESLES$1"; | ||
209 | - } | ||
210 | - elsif ($release =~ /^SUSE Linux Enterprise Server (\d+\.?\d?\w*)/i) { | ||
211 | - $distro="SESLES$1"; | ||
212 | - } | ||
213 | - elsif ($release =~ /^openSuSE (\d+\.\d+\w*)/i) { | ||
214 | - $distro="SE$1"; | ||
215 | + print STDERR "$err Could not infer CentOS version! Setting to Red Hat Enterprise 4 AS.\n"; | ||
216 | + $distro='RHEL4AS'; | ||
217 | } | ||
218 | - else { | ||
219 | - print STDERR "$err Couldn't determine SuSE version! Setting to 10.3!\n"; | ||
220 | - $distro="SE10.3"; | ||
221 | - } | ||
222 | - close(SUSE_RELEASE); | ||
223 | - } | ||
224 | - elsif ( -e "/etc/turbolinux-release") { | ||
225 | - open(*TURBOLINUX_RELEASE,"/etc/turbolinux-release"); | ||
226 | - $release=<TURBOLINUX_RELEASE>; | ||
227 | - unless ($release =~ /^Turbolinux Workstation (\d+\.\d+\w*)/) { | ||
228 | - print STDERR "$err Couldn't determine TurboLinux version! Setting to 7.0!\n"; | ||
229 | - $distro="TB7.0"; | ||
230 | - } | ||
231 | - else { | ||
232 | - $distro="TB$1"; | ||
233 | - } | ||
234 | - close(TURBOLINUX_RELEASE); | ||
235 | + } | ||
236 | + else { | ||
237 | + # JJB/HP - Should this be B_log? | ||
238 | + print STDERR "$err Could not infer Red Hat version! Setting to 9!\n"; | ||
239 | + $distro="RH9"; | ||
240 | + } | ||
241 | + close(REDHAT_RELEASE); | ||
242 | + | ||
243 | + } | ||
244 | + elsif ( -e "/etc/debian_version" ) { | ||
245 | + $stable="3.1"; #Change this when Debian stable changes | ||
246 | + open(*DEBIAN_RELEASE,"/etc/debian_version"); | ||
247 | + $release=<DEBIAN_RELEASE>; | ||
248 | + unless ($release =~ /^(\d+\.\d+\w*)/) { | ||
249 | + print STDERR "$err System is not running a stable Debian GNU/Linux version. Setting to $stable.\n"; | ||
250 | + $distro="DB$stable"; | ||
251 | + } | ||
252 | + else { | ||
253 | + $distro="DB$1"; | ||
254 | + } | ||
255 | + close(DEBIAN_RELEASE); | ||
256 | + } | ||
257 | + elsif ( -e "/etc/SuSE-release" ) { | ||
258 | + open(*SUSE_RELEASE,"/etc/SuSE-release"); | ||
259 | + $release=<SUSE_RELEASE>; | ||
260 | + if ($release =~ /^SuSE Linux (\d+\.\d+\w*)/i) { | ||
261 | + $distro="SE$1"; | ||
262 | + } | ||
263 | + elsif ($release =~ /^SUSE LINUX Enterprise Server (\d+\.?\d?\w*)/i) { | ||
264 | + $distro="SESLES$1"; | ||
265 | + } | ||
266 | + elsif ($release =~ /^SUSE Linux Enterprise Server (\d+\.?\d?\w*)/i) { | ||
267 | + $distro="SESLES$1"; | ||
268 | + } | ||
269 | + elsif ($release =~ /^openSuSE (\d+\.\d+\w*)/i) { | ||
270 | + $distro="SE$1"; | ||
271 | + } | ||
272 | + else { | ||
273 | + print STDERR "$err Could not infer SuSE version! Setting to 10.3!\n"; | ||
274 | + $distro="SE10.3"; | ||
275 | } | ||
276 | + close(SUSE_RELEASE); | ||
277 | + } | ||
278 | + elsif ( -e "/etc/turbolinux-release") { | ||
279 | + open(*TURBOLINUX_RELEASE,"/etc/turbolinux-release"); | ||
280 | + $release=<TURBOLINUX_RELEASE>; | ||
281 | + unless ($release =~ /^Turbolinux Workstation (\d+\.\d+\w*)/) { | ||
282 | + print STDERR "$err Could not infer TurboLinux version! Setting to 7.0!\n"; | ||
283 | + $distro="TB7.0"; | ||
284 | + } | ||
285 | else { | ||
286 | - # We're either on Mac OS X, HP-UX or an unsupported O/S. | ||
287 | - if ( -x '/usr/bin/uname') { | ||
288 | + $distro="TB$1"; | ||
289 | + } | ||
290 | + close(TURBOLINUX_RELEASE); | ||
291 | + } | ||
292 | + else { | ||
293 | + # We're either on Mac OS X, HP-UX or an unsupported O/S. | ||
294 | + if ( -x '/usr/bin/uname') { | ||
295 | # uname is in /usr/bin on Mac OS X and HP-UX | ||
296 | - $release=`/usr/bin/uname -sr`; | ||
297 | - } | ||
298 | - else { | ||
299 | - print STDERR "$err Could not determine operating system version!\n"; | ||
300 | - $distro="unknown" | ||
301 | - } | ||
302 | - | ||
303 | - # Figure out what kind of system we're on. | ||
304 | - if ($release ne "") { | ||
305 | - if ($release =~ /^Darwin\s+(\d+)\.(\d+)/) { | ||
306 | - if ($1 == 6 ) { | ||
307 | - $distro = "OSX10.2"; | ||
308 | - } | ||
309 | - elsif ($1 == 7) { | ||
310 | - $distro = "OSX10.3"; | ||
311 | - } | ||
312 | - elsif ($1 == 8) { | ||
313 | - $distro = "OSX10.3"; | ||
314 | - } | ||
315 | - else { | ||
316 | - $distro = "unknown"; | ||
317 | - } | ||
318 | + $release=`/usr/bin/uname -sr`; | ||
319 | + } | ||
320 | + else { | ||
321 | + print STDERR "$err Could not infer operating system version from filesystem context. Setting inferred distro to 'unknown'.\n"; | ||
322 | + $distro="unknown"; | ||
323 | + } | ||
324 | + | ||
325 | + # Figure out what kind of system we're on. | ||
326 | + if ($release ne "") { | ||
327 | + if ($release =~ /^Darwin\s+(\d+)\.(\d+)/) { | ||
328 | + if ($1 == 6 ) { | ||
329 | + $distro = "OSX10.2"; | ||
330 | } | ||
331 | - elsif ( $release =~ /(^HP-UX)\s*B\.(\d+\.\d+)/ ) { | ||
332 | - $distro="$1$2"; | ||
333 | + elsif ($1 == 7) { | ||
334 | + $distro = "OSX10.3"; | ||
335 | } | ||
336 | + elsif ($1 == 8) { | ||
337 | + $distro = "OSX10.3"; | ||
338 | + } | ||
339 | else { | ||
340 | - print STDERR "$err Could not determine operating system version!\n"; | ||
341 | - $distro="unknown"; | ||
342 | + print STDERR "$err Could not infer operating system version from filesystem context. Setting inferred distro to 'unknown'.\n"; | ||
343 | + $distro = "unknown"; | ||
344 | } | ||
345 | } | ||
346 | + elsif ( $release =~ /(^HP-UX)\s*B\.(\d+\.\d+)/ ) { | ||
347 | + $distro="$1$2"; | ||
348 | + } | ||
349 | + else { | ||
350 | + print STDERR "$err Could not infer operating system version from filesystem context. Setting inferred distro to 'unknown'.\n"; | ||
351 | + $distro="unknown"; | ||
352 | + } | ||
353 | } | ||
354 | - | ||
355 | - $GLOBAL_OS=$distro; | ||
356 | - } elsif (not (defined $GLOBAL_OS)) { | ||
357 | - print "ERROR: GLOBAL OS Scoping Issue\n"; | ||
358 | - } else { | ||
359 | - $distro = $GLOBAL_OS; | ||
360 | } | ||
361 | - | ||
362 | return $distro; | ||
363 | } | ||
364 | |||
365 | ################################################################################### | ||
366 | -# &getActualDistro; # | ||
367 | +# &getInferredDistro; # | ||
368 | # # | ||
369 | # This subroutine returns the actual os version in which is running on. This # | ||
370 | # os version is independent of the --os switch feed to bastille. # | ||
371 | # # | ||
372 | ################################################################################### | ||
373 | -sub getActualDistro { | ||
374 | - # set local variable to $GLOBAL_OS | ||
375 | +sub getInferredDistro { | ||
376 | + if ($GLOBAL_INFERRED_OS eq "None") { | ||
377 | + $GLOBAL_INFERRED_OS = &InferDistro; | ||
378 | + } | ||
379 | + return $GLOBAL_INFERRED_OS; | ||
380 | +} | ||
381 | |||
382 | - if ($GLOBAL_ACTUAL_OS eq "None") { | ||
383 | - my $os = $GLOBAL_OS; | ||
384 | - # undef GLOBAL_OS so that the GetDistro routine will return | ||
385 | - # the actualDistro, it might otherwise return the distro set | ||
386 | - # by the --os switch. | ||
387 | - $GLOBAL_OS = "None"; | ||
388 | - $GLOBAL_ACTUAL_OS = &GetDistro; | ||
389 | - # reset the GLOBAL_OS variable | ||
390 | - $GLOBAL_OS = $os; | ||
391 | +sub GetDistro { | ||
392 | + if ($GLOBAL_OS eq "None") { | ||
393 | + return &getInferredDistro; | ||
394 | } | ||
395 | - return $GLOBAL_ACTUAL_OS; | ||
396 | + return $GLOBAL_OS; | ||
397 | } | ||
398 | + | ||
399 | # These are helper routines which used to be included inside GetDistro | ||
400 | sub is_OS_supported($) { | ||
401 | my $os=$_[0]; | ||
402 | @@ -556,7 +545,8 @@ | ||
403 | "SE7.2","SE7.3", "SE8.0","SE8.1","SE9.0","SE9.1", | ||
404 | "SE9.2","SE9.3","SE10.0","SE10.1","SE10.2","SE10.3", | ||
405 | "SESLES8","SESLES9","SESLES10", | ||
406 | - "TB7.0" | ||
407 | + "TB7.0", | ||
408 | + "Yocto" | ||
409 | ], | ||
410 | |||
411 | "HP-UX" => [ | ||
412 | @@ -882,23 +872,19 @@ | ||
413 | ########################################################################### | ||
414 | sub ConfigureForDistro { | ||
415 | |||
416 | - my $retval=1; | ||
417 | - | ||
418 | - # checking to see if the os version given is in fact supported | ||
419 | my $distro = &GetDistro; | ||
420 | |||
421 | - # checking to see if the actual os version is in fact supported | ||
422 | - my $actualDistro = &getActualDistro; | ||
423 | + my $inferredDistro = &getInferredDistro; | ||
424 | + | ||
425 | + if (! ($inferredDistro eq $distro) ) { | ||
426 | + print STDERR "WARNING: Inferred distro $inferredDistro is not the same as specified distro $distro. Using specified distro.\n"; | ||
427 | + } | ||
428 | + | ||
429 | $ENV{'LOCALE'}=''; # So that test cases checking for english results work ok. | ||
430 | - if ((! &is_OS_supported($distro)) or (! &is_OS_supported($actualDistro)) ) { | ||
431 | - # if either is not supported then print out a list of supported versions | ||
432 | - if (! &is_OS_supported($distro)) { | ||
433 | - print STDERR "$err '$distro' is not a supported operating system.\n"; | ||
434 | - } | ||
435 | - else { | ||
436 | - print STDERR "$err Bastille is unable to operate correctly on this\n"; | ||
437 | - print STDERR "$spc $distro operating system.\n"; | ||
438 | - } | ||
439 | + | ||
440 | + if (! &is_OS_supported($distro)) { | ||
441 | + print STDERR "$err '$distro' is not a supported operating system.\n"; | ||
442 | + | ||
443 | my %supportedOSHash = &getSupportedOSHash; | ||
444 | print STDERR "$spc Valid operating system versions are as follows:\n"; | ||
445 | |||
446 | @@ -930,7 +916,7 @@ | ||
447 | # intend via setting the Perl umask | ||
448 | umask(077); | ||
449 | |||
450 | - &getFileAndServiceInfo($distro,$actualDistro); | ||
451 | + &getFileAndServiceInfo($distro,$distro); | ||
452 | |||
453 | # &dumpFileInfo; # great for debuging file location issues | ||
454 | # &dumpServiceInfo; # great for debuging service information issues | ||
455 | @@ -942,7 +928,7 @@ | ||
456 | "$spc You must use Bastille\'s -n flag (for example:\n" . | ||
457 | "$spc bastille -f -n) or \'touch $nodisclaim_file \'\n"; | ||
458 | |||
459 | - return $retval; | ||
460 | + return 1; | ||
461 | } | ||
462 | |||
463 | |||
464 | Index: Bastille/Bastille/LogAPI.pm | ||
465 | =================================================================== | ||
466 | --- Bastille.orig/Bastille/LogAPI.pm 2013-08-22 04:32:38.269968002 -0400 | ||
467 | +++ Bastille/Bastille/LogAPI.pm 2013-08-22 04:32:47.509968002 -0400 | ||
468 | @@ -111,7 +111,7 @@ | ||
469 | # do this here to prevent bootstrapping problem, where we need to | ||
470 | # write an error that the errorlog location isn't defined. | ||
471 | my $logdir="/var/log/Bastille"; | ||
472 | - if(&getActualDistro =~ "^HP-UX"){ | ||
473 | + if(&getInferredDistro =~ "^HP-UX"){ | ||
474 | $logdir = "/var/opt/sec_mgmt/bastille/log/"; | ||
475 | } | ||
476 | |||
diff --git a/dynamic-layers/meta-perl/recipes-security/bastille/files/remove_questions_text_file_references.patch b/dynamic-layers/meta-perl/recipes-security/bastille/files/remove_questions_text_file_references.patch new file mode 100644 index 0000000..bd094ee --- /dev/null +++ b/dynamic-layers/meta-perl/recipes-security/bastille/files/remove_questions_text_file_references.patch | |||
@@ -0,0 +1,30 @@ | |||
1 | Upstream Status: Inappropriate [No upstream maintenance] | ||
2 | |||
3 | Signed-off-by: Anne Mulhern <mulhern@yoctoproject.org> | ||
4 | |||
5 | --- | ||
6 | |||
7 | Index: Bastille/OSMap/LINUX.bastille | ||
8 | =================================================================== | ||
9 | --- Bastille.orig/OSMap/LINUX.bastille 2008-01-25 18:31:35.000000000 -0500 | ||
10 | +++ Bastille/OSMap/LINUX.bastille 2013-08-22 04:48:32.677968002 -0400 | ||
11 | @@ -12,7 +12,6 @@ | ||
12 | |||
13 | bfile,InteractiveBastille,'/usr/sbin/InteractiveBastille' | ||
14 | bfile,BastilleBackEnd,'/usr/sbin/BastilleBackEnd' | ||
15 | -bfile,Questions,'/usr/share/Bastille/Questions.txt' | ||
16 | bfile,QuestionsModules,'/usr/share/Bastille/Modules.txt' | ||
17 | bfile,TODO,'/var/log/Bastille/TODO' | ||
18 | bfile,TODOFlag,'/var/log/Bastille/TODOFlag.txt' | ||
19 | Index: Bastille/OSMap/OSX.bastille | ||
20 | =================================================================== | ||
21 | --- Bastille.orig/OSMap/OSX.bastille 2007-09-11 18:09:26.000000000 -0400 | ||
22 | +++ Bastille/OSMap/OSX.bastille 2013-08-22 04:48:47.245968001 -0400 | ||
23 | @@ -10,7 +10,6 @@ | ||
24 | bdir,share,'/usr/share/Bastille' | ||
25 | |||
26 | bfile,BastilleBackEnd,'/var/root/Bastille/BastilleBackEnd' | ||
27 | -bfile,Questions,'/usr/share/Bastille/Questions.txt' | ||
28 | bfile,QuestionsModules,'/usr/share/Bastille/Modules.txt' | ||
29 | bfile,TODO,'/var/log/Bastille/TODO' | ||
30 | bfile,TODOFlag,'/var/log/Bastille/TODOFlag.txt' | ||
diff --git a/dynamic-layers/meta-perl/recipes-security/bastille/files/set_required_questions.py b/dynamic-layers/meta-perl/recipes-security/bastille/files/set_required_questions.py new file mode 100755 index 0000000..f306109 --- /dev/null +++ b/dynamic-layers/meta-perl/recipes-security/bastille/files/set_required_questions.py | |||
@@ -0,0 +1,157 @@ | |||
1 | #!/usr/bin/env python3 | ||
2 | |||
3 | #Signed-off-by: Anne Mulhern <mulhern@yoctoproject.org> | ||
4 | |||
5 | import argparse, os, shutil, sys, tempfile, traceback | ||
6 | from os import path | ||
7 | |||
8 | |||
9 | |||
10 | def get_config(lines): | ||
11 | """ | ||
12 | From a sequence of lines retrieve the question file name, question identifier | ||
13 | pairs. | ||
14 | """ | ||
15 | for l in lines: | ||
16 | if not l.startswith("#"): | ||
17 | try: | ||
18 | (coord, value) = l.split("=") | ||
19 | try: | ||
20 | (fname, ident) = coord.split(".") | ||
21 | yield fname, ident | ||
22 | except ValueError as e: | ||
23 | raise ValueError("Badly formatted coordinates %s in line %s." % (coord, l.strip())) | ||
24 | except ValueError as e: | ||
25 | raise ValueError("Skipping badly formatted line %s, %s" % (l.strip(), e)) | ||
26 | |||
27 | |||
28 | |||
29 | def check_contains(line, name): | ||
30 | """ | ||
31 | Check if the value field for REQUIRE_DISTRO contains the given name. | ||
32 | @param name line The REQUIRE_DISTRO line | ||
33 | @param name name The name to look for in the value field of the line. | ||
34 | """ | ||
35 | try: | ||
36 | (label, distros) = line.split(":") | ||
37 | return name in distros.split() | ||
38 | except ValueError as e: | ||
39 | raise ValueError("Error splitting REQUIRE_DISTRO line: %s" % e) | ||
40 | |||
41 | |||
42 | |||
43 | def add_requires(the_ident, distro, lines): | ||
44 | |||
45 | """ | ||
46 | Yield a sequence of lines the same as lines except that where | ||
47 | the_ident matches a question identifier change the REQUIRE_DISTRO so that | ||
48 | it includes the specified distro. | ||
49 | |||
50 | @param name the_ident The question identifier to be matched. | ||
51 | @param name distro The distribution to added to the questions REQUIRE_DISTRO | ||
52 | field. | ||
53 | @param lines The sequence to be processed. | ||
54 | """ | ||
55 | for l in lines: | ||
56 | yield l | ||
57 | if l.startswith("LABEL:"): | ||
58 | try: | ||
59 | (label, ident) = l.split(":") | ||
60 | if ident.strip() == the_ident: | ||
61 | break | ||
62 | except ValueError as e: | ||
63 | raise ValueError("Unexpected line %s in questions file." % l.strip()) | ||
64 | for l in lines: | ||
65 | if l.startswith("REQUIRE_DISTRO"): | ||
66 | if not check_contains(l, distro): | ||
67 | yield l.rstrip() + " " + distro + "\n" | ||
68 | else: | ||
69 | yield l | ||
70 | break; | ||
71 | else: | ||
72 | yield l | ||
73 | for l in lines: | ||
74 | yield l | ||
75 | |||
76 | |||
77 | |||
78 | def xform_file(qfile, distro, qlabel): | ||
79 | """ | ||
80 | Transform a Questions file. | ||
81 | @param name qfile The designated questions file. | ||
82 | @param name distro The distribution to add to the required distributions. | ||
83 | @param name qlabel The question label for which the distro is to be added. | ||
84 | """ | ||
85 | questions_in = open(qfile) | ||
86 | questions_out = tempfile.NamedTemporaryFile(mode="w+", delete=False) | ||
87 | for l in add_requires(qlabel, distro, questions_in): | ||
88 | questions_out.write(l) | ||
89 | questions_out.close() | ||
90 | questions_in.close() | ||
91 | shutil.copystat(qfile, questions_out.name) | ||
92 | os.remove(qfile) | ||
93 | shutil.move(questions_out.name, qfile) | ||
94 | |||
95 | |||
96 | |||
97 | def handle_args(parser): | ||
98 | parser.add_argument('config_file', | ||
99 | help = "Configuration file path.") | ||
100 | parser.add_argument('questions_dir', | ||
101 | help = "Directory containing Questions files.") | ||
102 | parser.add_argument('--distro', '-d', | ||
103 | help = "The distribution, the default is Yocto.", | ||
104 | default = "Yocto") | ||
105 | parser.add_argument('--debug', '-b', | ||
106 | help = "Print debug information.", | ||
107 | action = 'store_true') | ||
108 | return parser.parse_args() | ||
109 | |||
110 | |||
111 | |||
112 | def check_args(args): | ||
113 | args.config_file = os.path.abspath(args.config_file) | ||
114 | args.questions_dir = os.path.abspath(args.questions_dir) | ||
115 | |||
116 | if not os.path.isdir(args.questions_dir): | ||
117 | raise ValueError("Specified Questions directory %s does not exist or is not a directory." % args.questions_dir) | ||
118 | |||
119 | if not os.path.isfile(args.config_file): | ||
120 | raise ValueError("Specified configuration file %s not found." % args.config_file) | ||
121 | |||
122 | |||
123 | |||
124 | def main(): | ||
125 | opts = handle_args(argparse.ArgumentParser(description="A simple script that sets required questions based on the question/answer pairs in a configuration file.")) | ||
126 | |||
127 | try: | ||
128 | check_args(opts) | ||
129 | except ValueError as e: | ||
130 | if opts.debug: | ||
131 | traceback.print_exc() | ||
132 | else: | ||
133 | sys.exit("Fatal error:\n%s" % e) | ||
134 | |||
135 | |||
136 | try: | ||
137 | config_in = open(opts.config_file) | ||
138 | for qfile, qlabel in get_config(config_in): | ||
139 | questions_file = os.path.join(opts.questions_dir, qfile + ".txt") | ||
140 | xform_file(questions_file, opts.distro, qlabel) | ||
141 | config_in.close() | ||
142 | |||
143 | except IOError as e: | ||
144 | if opts.debug: | ||
145 | traceback.print_exc() | ||
146 | else: | ||
147 | sys.exit("Fatal error reading or writing file:\n%s" % e) | ||
148 | except ValueError as e: | ||
149 | if opts.debug: | ||
150 | traceback.print_exc() | ||
151 | else: | ||
152 | sys.exit("Fatal error:\n%s" % e) | ||
153 | |||
154 | |||
155 | |||
156 | if __name__ == "__main__": | ||
157 | main() | ||
diff --git a/dynamic-layers/meta-perl/recipes-security/bastille/files/simplify_B_place.patch b/dynamic-layers/meta-perl/recipes-security/bastille/files/simplify_B_place.patch new file mode 100644 index 0000000..307fdca --- /dev/null +++ b/dynamic-layers/meta-perl/recipes-security/bastille/files/simplify_B_place.patch | |||
@@ -0,0 +1,40 @@ | |||
1 | Upstream Status: Inappropriate [No upstream maintenance] | ||
2 | |||
3 | Signed-off-by: Anne Mulhern <mulhern@yoctoproject.org> | ||
4 | |||
5 | --- | ||
6 | |||
7 | Index: Bastille/Bastille/API.pm | ||
8 | =================================================================== | ||
9 | --- Bastille.orig/Bastille/API.pm 2013-08-21 08:59:17.939950001 -0400 | ||
10 | +++ Bastille/Bastille/API.pm 2013-08-21 08:59:30.983950001 -0400 | ||
11 | @@ -1679,24 +1679,22 @@ | ||
12 | |||
13 | use File::Copy; | ||
14 | |||
15 | - my $original_source=$source; | ||
16 | $source = &getGlobal('BDIR', "share") . $source; | ||
17 | - my $original_target=$target; | ||
18 | |||
19 | if ( -e $target and -f $target ) { | ||
20 | - &B_backup_file($original_target); | ||
21 | - &B_log("ACTION","About to copy $original_source to $original_target -- had to backup target\n"); | ||
22 | + &B_backup_file($target); | ||
23 | + &B_log("ACTION","About to copy $source to $target -- had to backup target\n"); | ||
24 | $had_to_backup_target=1; | ||
25 | } | ||
26 | $retval=copy($source,$target); | ||
27 | if ($retval) { | ||
28 | - &B_log("ACTION","placed file $original_source as $original_target\n"); | ||
29 | + &B_log("ACTION","placed file $source as $target\n"); | ||
30 | # | ||
31 | # We want to add a line to the &getGlobal('BFILE', "created-files") so that the | ||
32 | # file we just put at $original_target gets deleted. | ||
33 | - &B_revert_log(&getGlobal('BIN',"rm") . " $original_target\n"); | ||
34 | + &B_revert_log(&getGlobal('BIN',"rm") . " $target\n"); | ||
35 | } else { | ||
36 | - &B_log("ERROR","Failed to place $original_source as $original_target\n"); | ||
37 | + &B_log("ERROR","Failed to place $source as $target\n"); | ||
38 | } | ||
39 | |||
40 | # We add the file to the GLOBAL_SUMS hash if it is not already present | ||
diff --git a/dynamic-layers/meta-perl/recipes-security/bastille/files/upgrade_options_processing.patch b/dynamic-layers/meta-perl/recipes-security/bastille/files/upgrade_options_processing.patch new file mode 100644 index 0000000..4093867 --- /dev/null +++ b/dynamic-layers/meta-perl/recipes-security/bastille/files/upgrade_options_processing.patch | |||
@@ -0,0 +1,91 @@ | |||
1 | Upstream Status: Inappropriate [No upstream maintenance] | ||
2 | |||
3 | Signed-off-by: Anne Mulhern <mulhern@yoctoproject.org> | ||
4 | |||
5 | --- | ||
6 | |||
7 | Index: Bastille/Bastille/API.pm | ||
8 | =================================================================== | ||
9 | --- Bastille.orig/Bastille/API.pm 2013-08-21 11:41:09.235950000 -0400 | ||
10 | +++ Bastille/Bastille/API.pm 2013-08-21 11:41:16.183950000 -0400 | ||
11 | @@ -271,9 +271,15 @@ | ||
12 | # setOptions takes six arguments, $GLOBAL_DEBUG, $GLOBAL_LOGONLY, | ||
13 | # $GLOBAL_VERBOSE, $GLOBAL_AUDITONLY, $GLOBAL_AUDIT_NO_BROWSER, and GLOBAL_OS; | ||
14 | ########################################################################### | ||
15 | -sub setOptions($$$$$$) { | ||
16 | - ($GLOBAL_DEBUG,$GLOBAL_LOGONLY,$GLOBAL_VERBOSE,$GLOBAL_AUDITONLY, | ||
17 | - $GLOBAL_AUDIT_NO_BROWSER,$GLOBAL_OS) = @_; | ||
18 | +sub setOptions { | ||
19 | + my %opts = @_; | ||
20 | + | ||
21 | + $GLOBAL_DEBUG = $opts{debug}; | ||
22 | + $GLOBAL_LOGONLY = $opts{logonly}; | ||
23 | + $GLOBAL_VERBOSE = $opts{verbose}; | ||
24 | + $GLOBAL_AUDITONLY = $opts{auditonly}; | ||
25 | + $GLOBAL_AUDIT_NO_BROWSER = $opts{audit_no_browser}; | ||
26 | + $GLOBAL_OS = $opts{os}; | ||
27 | if ($GLOBAL_AUDIT_NO_BROWSER) { | ||
28 | $GLOBAL_AUDITONLY = 1; | ||
29 | } | ||
30 | Index: Bastille/BastilleBackEnd | ||
31 | =================================================================== | ||
32 | --- Bastille.orig/BastilleBackEnd 2013-08-21 11:41:09.235950000 -0400 | ||
33 | +++ Bastille/BastilleBackEnd 2013-08-21 12:40:54.055950001 -0400 | ||
34 | @@ -50,15 +50,13 @@ | ||
35 | my $nodisclaim = 0; | ||
36 | my $verbose = 0; | ||
37 | my $force = 0; | ||
38 | -my $log_only = 0; | ||
39 | my $debug = 0; | ||
40 | my $alternate_config=undef; | ||
41 | |||
42 | if( Getopt::Long::GetOptions( "n" => \$nodisclaim, | ||
43 | "v" => \$verbose, | ||
44 | "force" => \$force, | ||
45 | -# "log" => \$log_only, # broken | ||
46 | - "f:s" => \$alternate_config, | ||
47 | + "f=s" => \$alternate_config, | ||
48 | "debug" => \$debug) ) { | ||
49 | $error = 0; # no parse error | ||
50 | |||
51 | @@ -66,7 +64,9 @@ | ||
52 | $error = 1; # parse error | ||
53 | } | ||
54 | |||
55 | -&setOptions($debug,$log_only,$verbose); | ||
56 | +&setOptions( | ||
57 | + debug => $debug, | ||
58 | + verbose => $verbose); | ||
59 | &ConfigureForDistro; | ||
60 | |||
61 | if ( $error ) { # GetOptions couldn't parse all of the args | ||
62 | Index: Bastille/InteractiveBastille | ||
63 | =================================================================== | ||
64 | --- Bastille.orig/InteractiveBastille 2013-08-21 11:41:09.235950000 -0400 | ||
65 | +++ Bastille/InteractiveBastille 2013-08-21 12:40:30.531950001 -0400 | ||
66 | @@ -234,8 +234,8 @@ | ||
67 | "a" => \$audit, | ||
68 | "force" => \$force, | ||
69 | "log" => \$log_only, | ||
70 | - "os:s" => \$os_version, | ||
71 | - "f:s" => \$alternate_config, | ||
72 | + "os=s" => \$os_version, | ||
73 | + "f=s" => \$alternate_config, | ||
74 | "debug" => \$debug) ) { | ||
75 | $error = 0; # no parse error | ||
76 | } else { | ||
77 | @@ -293,7 +293,13 @@ | ||
78 | $UseRequiresRules = 'N'; | ||
79 | } | ||
80 | |||
81 | -&setOptions($debug,$log_only,$verbose,$audit,$auditnobrowser,$os_version); | ||
82 | +&setOptions( | ||
83 | + debug => $debug, | ||
84 | + logonly => $log_only, | ||
85 | + verbose => $verbose, | ||
86 | + auditonly => $audit, | ||
87 | + audit_no_browser => $auditnobrowser, | ||
88 | + os => $os_version); | ||
89 | &ConfigureForDistro; | ||
90 | |||
91 | # ensuring mutually exclusive options are exclusive | ||
diff --git a/dynamic-layers/meta-perl/recipes-security/nikto/files/location.patch b/dynamic-layers/meta-perl/recipes-security/nikto/files/location.patch new file mode 100644 index 0000000..edaa204 --- /dev/null +++ b/dynamic-layers/meta-perl/recipes-security/nikto/files/location.patch | |||
@@ -0,0 +1,36 @@ | |||
1 | From d1cb702d5147abea0d3208a4d554c61a6f2decd6 Mon Sep 17 00:00:00 2001 | ||
2 | From: Scott Ellis <scott@jumpnowtek.com> | ||
3 | Date: Fri, 28 Dec 2018 11:08:25 -0500 | ||
4 | Subject: [PATCH] Set custom paths | ||
5 | |||
6 | Upstream Status: Inappropriate | ||
7 | |||
8 | Signed-off-by: Scott Ellis <scott@jumpnowtek.com> | ||
9 | --- | ||
10 | nikto.conf | 10 +++++----- | ||
11 | 1 file changed, 5 insertions(+), 5 deletions(-) | ||
12 | |||
13 | diff --git a/program/nikto.conf b/program/nikto.conf | ||
14 | index bf36c58..8c55415 100644 | ||
15 | --- a/nikto.conf | ||
16 | +++ b/nikto.conf | ||
17 | @@ -61,11 +61,11 @@ CIRT=107.170.99.251 | ||
18 | CHECKMETHODS=HEAD GET | ||
19 | |||
20 | # If you want to specify the location of any of the files, specify them here | ||
21 | -# EXECDIR=/opt/nikto # Location of Nikto | ||
22 | -# PLUGINDIR=/opt/nikto/plugins # Location of plugin dir | ||
23 | -# DBDIR=/opt/nikto/databases # Location of database dir | ||
24 | -# TEMPLATEDIR=/opt/nikto/templates # Location of template dir | ||
25 | -# DOCDIR=/opt/nikto/docs # Location of docs dir | ||
26 | +EXECDIR=/usr/bin/nikto # Location of Nikto | ||
27 | +PLUGINDIR=/etc/nikto/plugins # Location of plugin dir | ||
28 | +DBDIR=/etc/nikto/databases # Location of database dir | ||
29 | +TEMPLATEDIR=/etc/nikto/templates # Location of template dir | ||
30 | +DOCDIR=/usr/share/doc/nikto # Location of docs dir | ||
31 | |||
32 | # Default plugin macros | ||
33 | # Remove plugins designed to be run standalone | ||
34 | -- | ||
35 | 2.7.4 | ||
36 | |||
diff --git a/dynamic-layers/meta-perl/recipes-security/nikto/nikto_2.1.6.bb b/dynamic-layers/meta-perl/recipes-security/nikto/nikto_2.1.6.bb new file mode 100644 index 0000000..8c21b30 --- /dev/null +++ b/dynamic-layers/meta-perl/recipes-security/nikto/nikto_2.1.6.bb | |||
@@ -0,0 +1,118 @@ | |||
1 | SUMMARY = "web server scanner" | ||
2 | DESCRIPTION = "Nikto is an Open Source web server scanner which performs comprehensive tests against web servers" | ||
3 | SECTION = "security" | ||
4 | HOMEPAGE = "https://cirt.net/Nikto2" | ||
5 | |||
6 | LICENSE = "GPL-2.0-only" | ||
7 | LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/GPL-2.0-only;md5=801f80980d171dd6425610833a22dbe6" | ||
8 | |||
9 | SRCREV = "f1bbd1a8756c076c8fd4f4dd0bc34a8ef215ae79" | ||
10 | SRC_URI = "git://github.com/sullo/nikto.git;branch=master;protocol=https \ | ||
11 | file://location.patch" | ||
12 | |||
13 | S = "${WORKDIR}/git/program" | ||
14 | |||
15 | do_install() { | ||
16 | install -d ${D}${bindir} | ||
17 | install -d ${D}${datadir} | ||
18 | install -d ${D}${datadir}/man/man1 | ||
19 | install -d ${D}${datadir}/doc/nikto | ||
20 | install -d ${D}${sysconfdir}/nikto | ||
21 | install -d ${D}${sysconfdir}/nikto/databases | ||
22 | install -d ${D}${sysconfdir}/nikto/plugins | ||
23 | install -d ${D}${sysconfdir}/nikto/templates | ||
24 | |||
25 | install -m 0644 databases/db_404_strings ${D}${sysconfdir}/nikto/databases | ||
26 | install -m 0644 databases/db_content_search ${D}${sysconfdir}/nikto/databases | ||
27 | install -m 0644 databases/db_dictionary ${D}${sysconfdir}/nikto/databases | ||
28 | install -m 0644 databases/db_dir_traversal ${D}${sysconfdir}/nikto/databases | ||
29 | install -m 0644 databases/db_domino ${D}${sysconfdir}/nikto/databases | ||
30 | install -m 0644 databases/db_drupal ${D}${sysconfdir}/nikto/databases | ||
31 | install -m 0644 databases/db_embedded ${D}${sysconfdir}/nikto/databases | ||
32 | install -m 0644 databases/db_favicon ${D}${sysconfdir}/nikto/databases | ||
33 | install -m 0644 databases/db_headers ${D}${sysconfdir}/nikto/databases | ||
34 | install -m 0644 databases/db_httpoptions ${D}${sysconfdir}/nikto/databases | ||
35 | install -m 0644 databases/db_multiple_index ${D}${sysconfdir}/nikto/databases | ||
36 | install -m 0644 databases/db_outdated ${D}${sysconfdir}/nikto/databases | ||
37 | install -m 0644 databases/db_parked_strings ${D}${sysconfdir}/nikto/databases | ||
38 | install -m 0644 databases/db_realms ${D}${sysconfdir}/nikto/databases | ||
39 | install -m 0644 databases/db_server_msgs ${D}${sysconfdir}/nikto/databases | ||
40 | install -m 0644 databases/db_tests ${D}${sysconfdir}/nikto/databases | ||
41 | install -m 0644 databases/db_variables ${D}${sysconfdir}/nikto/databases | ||
42 | |||
43 | install -m 0644 plugins/LW2.pm ${D}${sysconfdir}/nikto/plugins | ||
44 | install -m 0644 plugins/nikto_apache_expect_xss.plugin ${D}${sysconfdir}/nikto/plugins | ||
45 | install -m 0644 plugins/nikto_apacheusers.plugin ${D}${sysconfdir}/nikto/plugins | ||
46 | install -m 0644 plugins/nikto_auth.plugin ${D}${sysconfdir}/nikto/plugins | ||
47 | install -m 0644 plugins/nikto_cgi.plugin ${D}${sysconfdir}/nikto/plugins | ||
48 | install -m 0644 plugins/nikto_clientaccesspolicy.plugin ${D}${sysconfdir}/nikto/plugins | ||
49 | install -m 0644 plugins/nikto_content_search.plugin ${D}${sysconfdir}/nikto/plugins | ||
50 | install -m 0644 plugins/nikto_cookies.plugin ${D}${sysconfdir}/nikto/plugins | ||
51 | install -m 0644 plugins/nikto_core.plugin ${D}${sysconfdir}/nikto/plugins | ||
52 | install -m 0644 plugins/nikto_dictionary_attack.plugin ${D}${sysconfdir}/nikto/plugins | ||
53 | install -m 0644 plugins/nikto_dir_traversal.plugin ${D}${sysconfdir}/nikto/plugins | ||
54 | install -m 0644 plugins/nikto_dishwasher.plugin ${D}${sysconfdir}/nikto/plugins | ||
55 | install -m 0644 plugins/nikto_docker_registry.plugin ${D}${sysconfdir}/nikto/plugins | ||
56 | install -m 0644 plugins/nikto_domino.plugin ${D}${sysconfdir}/nikto/plugins | ||
57 | install -m 0644 plugins/nikto_drupal.plugin ${D}${sysconfdir}/nikto/plugins | ||
58 | install -m 0644 plugins/nikto_embedded.plugin ${D}${sysconfdir}/nikto/plugins | ||
59 | install -m 0644 plugins/nikto_favicon.plugin ${D}${sysconfdir}/nikto/plugins | ||
60 | install -m 0644 plugins/nikto_fileops.plugin ${D}${sysconfdir}/nikto/plugins | ||
61 | install -m 0644 plugins/nikto_headers.plugin ${D}${sysconfdir}/nikto/plugins | ||
62 | install -m 0644 plugins/nikto_httpoptions.plugin ${D}${sysconfdir}/nikto/plugins | ||
63 | install -m 0644 plugins/nikto_ms10_070.plugin ${D}${sysconfdir}/nikto/plugins | ||
64 | install -m 0644 plugins/nikto_msgs.plugin ${D}${sysconfdir}/nikto/plugins | ||
65 | install -m 0644 plugins/nikto_multiple_index.plugin ${D}${sysconfdir}/nikto/plugins | ||
66 | install -m 0644 plugins/nikto_negotiate.plugin ${D}${sysconfdir}/nikto/plugins | ||
67 | install -m 0644 plugins/nikto_origin_reflection.plugin ${D}${sysconfdir}/nikto/plugins | ||
68 | install -m 0644 plugins/nikto_outdated.plugin ${D}${sysconfdir}/nikto/plugins | ||
69 | install -m 0644 plugins/nikto_parked.plugin ${D}${sysconfdir}/nikto/plugins | ||
70 | install -m 0644 plugins/nikto_paths.plugin ${D}${sysconfdir}/nikto/plugins | ||
71 | install -m 0644 plugins/nikto_put_del_test.plugin ${D}${sysconfdir}/nikto/plugins | ||
72 | install -m 0644 plugins/nikto_report_csv.plugin ${D}${sysconfdir}/nikto/plugins | ||
73 | install -m 0644 plugins/nikto_report_html.plugin ${D}${sysconfdir}/nikto/plugins | ||
74 | install -m 0644 plugins/nikto_report_json.plugin ${D}${sysconfdir}/nikto/plugins | ||
75 | install -m 0644 plugins/nikto_report_nbe.plugin ${D}${sysconfdir}/nikto/plugins | ||
76 | install -m 0644 plugins/nikto_report_sqlg.plugin ${D}${sysconfdir}/nikto/plugins | ||
77 | install -m 0644 plugins/nikto_report_text.plugin ${D}${sysconfdir}/nikto/plugins | ||
78 | install -m 0644 plugins/nikto_report_xml.plugin ${D}${sysconfdir}/nikto/plugins | ||
79 | install -m 0644 plugins/nikto_robots.plugin ${D}${sysconfdir}/nikto/plugins | ||
80 | install -m 0644 plugins/nikto_siebel.plugin ${D}${sysconfdir}/nikto/plugins | ||
81 | install -m 0644 plugins/nikto_sitefiles.plugin ${D}${sysconfdir}/nikto/plugins | ||
82 | install -m 0644 plugins/nikto_ssl.plugin ${D}${sysconfdir}/nikto/plugins | ||
83 | install -m 0644 plugins/nikto_strutshock.plugin ${D}${sysconfdir}/nikto/plugins | ||
84 | install -m 0644 plugins/nikto_tests.plugin ${D}${sysconfdir}/nikto/plugins | ||
85 | |||
86 | install -m 0644 templates/htm_close.tmpl ${D}${sysconfdir}/nikto/templates | ||
87 | install -m 0644 templates/htm_end.tmpl ${D}${sysconfdir}/nikto/templates | ||
88 | install -m 0644 templates/htm_host_head.tmpl ${D}${sysconfdir}/nikto/templates | ||
89 | install -m 0644 templates/htm_host_im.tmpl ${D}${sysconfdir}/nikto/templates | ||
90 | install -m 0644 templates/htm_host_item.tmpl ${D}${sysconfdir}/nikto/templates | ||
91 | install -m 0644 templates/htm_start.tmpl ${D}${sysconfdir}/nikto/templates | ||
92 | install -m 0644 templates/htm_stop.tmpl ${D}${sysconfdir}/nikto/templates | ||
93 | install -m 0644 templates/htm_start.tmpl ${D}${sysconfdir}/nikto/templates | ||
94 | install -m 0644 templates/htm_summary.tmpl ${D}${sysconfdir}/nikto/templates | ||
95 | install -m 0644 templates/xml_end.tmpl ${D}${sysconfdir}/nikto/templates | ||
96 | install -m 0644 templates/xml_host_head.tmpl ${D}${sysconfdir}/nikto/templates | ||
97 | install -m 0644 templates/xml_host_im.tmpl ${D}${sysconfdir}/nikto/templates | ||
98 | install -m 0644 templates/xml_host_item.tmpl ${D}${sysconfdir}/nikto/templates | ||
99 | install -m 0644 templates/xml_start.tmpl ${D}${sysconfdir}/nikto/templates | ||
100 | install -m 0644 templates/xml_summary.tmpl ${D}${sysconfdir}/nikto/templates | ||
101 | |||
102 | install -m 0644 nikto.conf ${D}${sysconfdir} | ||
103 | |||
104 | install -m 0755 nikto.pl ${D}${bindir}/nikto | ||
105 | install -m 0644 replay.pl ${D}${bindir} | ||
106 | install -m 0644 docs/nikto.1 ${D}${datadir}/man/man1 | ||
107 | |||
108 | install -m 0644 docs/CHANGES.txt ${D}${datadir}/doc/nikto | ||
109 | install -m 0644 docs/LICENSE.txt ${D}${datadir}/doc/nikto | ||
110 | install -m 0644 docs/nikto.dtd ${D}${datadir}/doc/nikto | ||
111 | install -m 0644 docs/nikto_manual.html ${D}${datadir}/doc/nikto | ||
112 | } | ||
113 | |||
114 | RDEPENDS:${PN} = "perl libnet-ssleay-perl libwhisker2-perl \ | ||
115 | perl-module-getopt-long perl-module-time-local \ | ||
116 | perl-module-io-socket perl-module-overloading \ | ||
117 | perl-module-base perl-module-b perl-module-bytes" | ||
118 | |||