my $perlCmd = '/usr/bin/perl';
my $wgetCmd = '/usr/bin/wget';
my $runlevelCmd = '/sbin/runlevel';
+
+my $install_root = '/';
#============ end config ============
my %file_vars = (
my $force_path_update = 0;
my $force_mod_re = '';
my $exclude_mod_re = '';
+my $install_test_dir = 0;
my $no_rm_old_lib_dir = 0;
my $syslog_conf = '';
my $locale = 'C'; ### default LC_ALL env variable
my $init_name = 'psad';
my $install_syslog_fifo = 0;
my $runlevel = -1;
+my @installation_lines = ();
### make Getopts case sensitive
Getopt::Long::Configure('no_ignore_case');
'init-dir=s' => \$init_dir,
'init-name=s' => \$init_name,
'install-syslog-fifo' => \$install_syslog_fifo,
+ 'install-root=s' => \$install_root,
+ 'install-test-dir' => \$install_test_dir,
'runlevel=i' => \$runlevel,
'LC_ALL=s' => \$locale,
'no-LC_ALL' => \$no_locale,
### set LC_ALL env variable
$ENV{'LC_ALL'} = $locale unless $no_locale;
+$install_root = getcwd() . '/test/psad-install' if $install_test_dir;
+
### import paths from default psad.conf
&import_config();
-my @LOGR_FILES = (*STDOUT, $config{'INSTALL_LOG_FILE'});
-
$force_mod_re = qr|$force_mod_re| if $force_mod_re;
$exclude_mod_re = qr|$exclude_mod_re| if $exclude_mod_re;
$cmds{'perl'} = $perlCmd;
$cmds{'runlevel'} = $runlevelCmd;
-if (-e $config{'INSTALL_LOG_FILE'}) {
- open INSTALL, "> $config{'INSTALL_LOG_FILE'}" or
- die "[*] Could not open $config{'INSTALL_LOG_FILE'}: $!";
- close INSTALL;
-}
-
my $distro = &get_distro();
if ($distro eq 'redhat' or $distro eq 'fedora') {
### need to make sure this exists before attempting to
### write anything to the install log.
-mkdir $config{'PSAD_DIR'}, 0500 unless -d $config{'PSAD_DIR'};
+&full_mkdir($config{'PSAD_DIR'}, 0700);
### make sure the system binaries are where we expect
### them to be.
&check_commands();
-### check to make sure we are running as root
-$< == 0 && $> == 0 or die "You need to be root (or equivalent UID 0",
- " account) to install/uninstall psad!";
-
### occasionally things from old psad installations need to be
### dealt with separately.
&check_old_psad_installation();
} else {
&install();
}
+
+open F, "> $config{'INSTALL_LOG_FILE'}" or die $!;
+print F for @installation_lines;
+close F;
+
exit 0;
#================= end main =================
unless (-d $config{'PSAD_RUN_DIR'}) {
&logr("[+] Creating $config{'PSAD_RUN_DIR'}\n");
- mkdir $config{'PSAD_RUN_DIR'}, 0500;
+ &full_mkdir($config{'PSAD_RUN_DIR'}, 0700);
}
unless (-d $config{'PSAD_FIFO_DIR'}) {
&logr("[+] Creating $config{'PSAD_FIFO_DIR'}\n");
- mkdir $config{'PSAD_FIFO_DIR'}, 0500;
+ &full_mkdir($config{'PSAD_FIFO_DIR'}, 0700);
}
### change any existing psad module directory to allow anyone to import
}
unless (-d $config{'PSAD_CONF_DIR'}) {
&logr("[+] Creating $config{'PSAD_CONF_DIR'}\n");
- mkdir $config{'PSAD_CONF_DIR'}, 0500;
+ &full_mkdir($config{'PSAD_CONF_DIR'}, 0700);
}
unless (-d $config{'CONF_ARCHIVE_DIR'}) {
&logr("[+] Creating $config{'CONF_ARCHIVE_DIR'}\n");
- mkdir $config{'CONF_ARCHIVE_DIR'}, 0500;
+ &full_mkdir($config{'CONF_ARCHIVE_DIR'}, 0700);
}
if ($install_syslog_fifo) {
unless (-d $config{'PSAD_DIR'}) {
&logr("[+] Creating $config{'PSAD_DIR'}\n");
- mkdir $config{'PSAD_DIR'}, 0500;
+ &full_mkdir($config{'PSAD_DIR'}, 0700);
+ }
+ unless (-d $config{'PSAD_LIBS_DIR'}) {
+ &logr("[+] Creating $config{'PSAD_LIBS_DIR'}\n");
+ &full_mkdir($config{'PSAD_LIBS_DIR'}, 0755);
}
+
unless (-e $config{'FW_DATA_FILE'}) {
&logr("[+] Creating $config{'FW_DATA_FILE'} file\n");
open F, "> $config{'FW_DATA_FILE'}" or die "[*] Could not open ",
unless (-d $USRSBIN_DIR) {
&logr("[+] Creating $USRSBIN_DIR\n");
- mkdir $USRSBIN_DIR,0755;
+ &full_mkdir($USRSBIN_DIR, 0755);
}
if (-d 'deps' and -d 'deps/whois') {
&logr("[+] Compiling Marco d'Itri's whois client\n");
&logr("[+] Installing Snort-2.3.3 signatures in " .
"$config{'SNORT_RULES_DIR'}\n");
unless (-d $config{'SNORT_RULES_DIR'}) {
- mkdir $config{'SNORT_RULES_DIR'}, 0500
- or die "[*] Could not create $config{'SNORT_RULES_DIR'}: $!";
+ &full_mkdir($config{'SNORT_RULES_DIR'}, 0700);
}
opendir D, 'deps/snort_rules' or die "[*] Could not open ",
unless (-d $config{'PSAD_CONF_DIR'}) {
&logr("[+] Creating $config{'PSAD_CONF_DIR'}\n");
- mkdir $config{'PSAD_CONF_DIR'},0500;
+ &full_mkdir($config{'PSAD_CONF_DIR'}, 0700);
}
my $syslog_str = '';
&install_manpage('nf2csv.1');
my $init_file = '';
+ my $installed_init_script = 0;
if ($distro eq 'redhat') {
$init_file = 'init-scripts/psad-init.redhat';
} elsif ($distro eq 'fedora') {
$init_file = 'init-scripts/psad-init.generic';
}
- if ($init_dir) {
+ if ($init_dir and &is_root()) {
&logr("[+] Copying $init_file -> ${init_dir}/$init_name\n");
copy $init_file, "${init_dir}/$init_name" or die "[*] Could not copy ",
"$init_file -> ${init_dir}/$init_name: $!";
&perms_ownership("${init_dir}/$init_name", 0744);
&enable_psad_at_boot($distro);
+ $installed_init_script = 1;
}
&logr("\n========================================================\n");
} else {
&logr("\n[+] psad has been installed.\n");
}
- if ($init_dir) {
- &logr("\n[+] To start psad, run \"${init_dir}/psad start\"\n");
- } else {
- &logr("\n[+] To start psad, run ${USRSBIN_DIR}/psad\"\n");
+ if ($installed_init_script) {
+ if ($init_dir) {
+ &logr("\n[+] To start psad, run \"${init_dir}/psad start\"\n");
+ } else {
+ &logr("\n[+] To start psad, run ${USRSBIN_DIR}/psad\"\n");
+ }
}
return;
}
}
close C;
+ ### see if the install root is the same as the default in psad.conf and
+ ### update if not
+ if ($install_root ne '/') {
+ $install_root = getcwd() . "/$install_root"
+ unless $install_root =~ m|^/|;
+ $config{'INSTALL_ROOT'} = $install_root;
+ $USRSBIN_DIR = $config{'INSTALL_ROOT'} . $USRSBIN_DIR;
+ $USRBIN_DIR = $config{'INSTALL_ROOT'} . $USRBIN_DIR;
+
+ &put_string('INSTALL_ROOT', $install_root, $psad_conf_file);
+ }
+
+ for my $dir ($install_root, $USRSBIN_DIR, $USRBIN_DIR) {
+ &full_mkdir($dir, 0755) unless -d $dir;
+ }
+
### resolve internal vars within variable values
&expand_vars();
die "[*] sub-ver $sub_var not allowed within same ",
"variable $var" if $sub_var eq $var;
if (defined $config{$sub_var}) {
- $val =~ s|\$$sub_var|$config{$sub_var}|;
+ if ($sub_var eq 'INSTALL_ROOT' and $config{$sub_var} eq '/') {
+ $val =~ s|\$$sub_var||;
+ } else {
+ $val =~ s|\$$sub_var|$config{$sub_var}|;
+ }
$hr->{$var} = $val;
} else {
die "[*] sub-var \"$sub_var\" not defined in ",
}
if ($install_module) {
- unless (-d $config{'PSAD_LIBS_DIR'}) {
- &logr("[+] Creating $config{'PSAD_LIBS_DIR'}\n");
- mkdir $config{'PSAD_LIBS_DIR'}, 0755 or
- die "[*] Could not mkdir $config{'PSAD_LIBS_DIR'}: $!";
- }
&logr("[+] Installing the $mod_name $version perl " .
"module in $config{'PSAD_LIBS_DIR'}/\n");
my $mod_dir = $required_perl_modules{$mod_name}{'mod-dir'};
print "\n\n";
}
+
return;
}
}
sub check_old_psad_installation() {
+
+ return unless &is_root();
+
my $old_install_dir = '/usr/local/bin';
if (-e "${old_install_dir}/psad") {
move "${old_install_dir}/psad", "${USRSBIN_DIR}/psad" or die "[*] ",
sub perms_ownership() {
my ($file, $perm_value) = @_;
+
chmod $perm_value, $file or die "[*] Could not ",
"chmod($perm_value, $file): $!";
+
+ return unless &is_root();
+
### root (maybe should take the group assignment out)
chown 0, 0, $file or die "[*] Could not chown 0,0,$file: $!";
+
return;
}
}
&logr("[+] Archiving $file -> $config{'CONF_ARCHIVE_DIR'}/${base}1.gz\n");
unlink "${base}1.gz" if -e "${base}1.gz";
+
### move $file into the archive directory
copy $file, "${base}1" or die "[*] Could not copy ",
"$file -> ${base}1: $!";
sub enable_psad_at_boot() {
my $distro = shift;
+ return unless &is_root();
+
if (&query_yes_no("[+] Enable psad at boot time ([y]/n)? ",
$ACCEPT_YES_DEFAULT)) {
if ($distro eq 'redhat' or $distro eq 'fedora') {
### check paths to commands and attempt to correct if any are wrong.
sub check_commands() {
+
CMD: for my $cmd (keys %cmds) {
next CMD if defined $exclude_cmds{$cmd};
unless (-x $cmds{$cmd}) {
}
}
unless (-x $cmds{$cmd}) {
+ return unless &is_root();
die "\n[*] $cmd is located at ",
"$cmds{$cmd} but is not executable by uid: $<";
}
return;
}
+sub is_root() {
+ return 1 if $< == 0 and $> == 0;
+ return 0;
+}
+
sub install_manpage() {
my $manpage = shift;
- my $name;
- my $section;
+ my $name = '';
+ my $section = '';
if ($manpage =~ m|(\w+)\.(\d)|) {
$name = $1;
}
### remove old man page
- unlink "/usr/local/man/man$section/${manpage}" if
- (-e "/usr/local/man/man$section/${manpage}");
+ if (&is_root()) {
+ unlink "/usr/local/man/man$section/${manpage}" if
+ -e "/usr/local/man/man$section/${manpage}";
+ }
### default location to put the psad man page, but check with
### /etc/man.config
}
}
}
- mkdir $mpath, 0755 unless -d $mpath;
+
+ if ($install_root ne '/') {
+ $mpath = $config{'INSTALL_ROOT'} . $mpath;
+ }
+
+ &full_mkdir($mpath, 0755);
my $mfile = "${mpath}/${manpage}";
&logr("[+] Installing $manpage man page at $mfile\n");
copy $manpage, $mfile or die "[*] Could not copy $manpage to ",
return;
}
+sub full_mkdir() {
+ my ($dir, $perms) = @_;
+
+ my @dirs = split /\//, $dir;
+ my $path = $dirs[0];
+ shift @dirs;
+ for my $d (@dirs) {
+ next unless $d and $d =~ /\S/;
+ $path .= "/$d";
+ unless (-d $path) {
+ printf "[+] mkdir $path, %o\n", $perms;
+ mkdir $path, $perms or die "[*] Could not mkdir($path): $!";
+ }
+ }
+ return;
+}
+
sub has_perl_module() {
my $module = shift;
my $cmd = $1;
my $spaces = $2;
my $path = $3;
+ if ($path =~ /\$INSTALL_ROOT/) {
+ $path =~ s|\$INSTALL_ROOT|$install_root|;
+ }
unless (-e $path and -x $path) {
### the command is not at this path, try to find it
my $cmd_minor_name = $cmd;
### logging subroutine that handles multiple filehandles
sub logr() {
my $msg = shift;
- for my $file (@LOGR_FILES) {
- if ($file eq *STDOUT) {
- print STDOUT $msg;
- } elsif ($file eq *STDERR) {
- print STDERR $msg;
- } else {
- open F, ">> $file" or die "[*] Could not open ",
- "$file: $!";
- print F $msg;
- close F;
- }
- }
+
+ print STDOUT $msg;
+ push @installation_lines, $msg;
+
return;
}
### regex to match IP addresses
my $ip_re = qr|(?:[0-2]?\d{1,2}\.){3}[0-2]?\d{1,2}|; ### IPv4
-my $ipv6_re = qr|(?:[a-f0-9]{4}:){7}(?:[a-f0-9]{4})|i; ### IPv6
+my $ipv6_re = qr|(?:[a-f0-9]{4}:){7}(?:[a-f0-9]{4})|i; ### IPv6
### ttl values are decremented depending on the number of hops
### the packet has taken before it hits the firewall. We will
### make $src directory here in /var/log/psad
### unless it already exists
- mkdir "$config{'PSAD_DIR'}/${src}", 0500
+ mkdir "$config{'PSAD_DIR'}/${src}", 0700
unless -d "$config{'PSAD_DIR'}/${src}";
my $src_dir = "$config{'PSAD_DIR'}/${src}";
my $dl_file = "${src_dir}/danger_level";
chdir $config{'PSAD_DIR'} or die "[*] Could not chdir ",
"$config{'PSAD_DIR'}: $!";
unless (-d $config{'SCAN_DATA_ARCHIVE_DIR'}) {
- mkdir $config{'SCAN_DATA_ARCHIVE_DIR'}, 0500 or
+ mkdir $config{'SCAN_DATA_ARCHIVE_DIR'}, 0700 or
die "[*] Could not create dir: ",
"$config{'SCAN_DATA_ARCHIVE_DIR'}: $!";
}
PSAD_ERR_DIR
)) {
next if -d $config{$dir};
- mkdir $config{$dir}, 0500 or
+ mkdir $config{$dir}, 0700 or
die "[*] Could not mkdir $config{$dir}: $!";
}
return;
### of our worries).
&sys_log("removing $config{'SCAN_DATA_ARCHIVE_DIR'} directory");
rmtree $config{'SCAN_DATA_ARCHIVE_DIR'};
- mkdir $config{'SCAN_DATA_ARCHIVE_DIR'}, 0500;
+ mkdir $config{'SCAN_DATA_ARCHIVE_DIR'}, 0700;
}
opendir D, $config{'PSAD_DIR'} or
die "[*] Could not open dir: $config{'PSAD_DIR'}: $!";
die "[*] sub-ver $sub_var not allowed within same ",
"variable $var" if $sub_var eq $var;
if (defined $config{$sub_var}) {
- $val =~ s|\$$sub_var|$config{$sub_var}|;
+ if ($sub_var eq 'INSTALL_ROOT'
+ and $config{$sub_var} eq '/') {
+ $val =~ s|\$$sub_var||;
+ } else {
+ $val =~ s|\$$sub_var|$config{$sub_var}|;
+ }
$hr->{$var} = $val;
} else {
die "[*] sub-var \"$sub_var\" not defined in ",
}
sub is_root() {
- $< == 0 && $> == 0 or
+
+ ### exceptions
+ for my $var ($download_sigs,
+ $analyze_mode,
+ $get_next_rule_id,
+ $gnuplot_mode,
+ $csv_mode,
+ $dump_conf,
+ $status_mode,
+ $benchmark,
+ ) {
+ return if $var;
+ }
+
+ $< == 0 and $> == 0 or
die '[*] psad: You must be root (or equivalent ',
- "UID 0 account) to execute psad! Exiting.\n";
+ "UID 0 account) to execute psad! Exiting.";
}
### check to make sure all required varables are defined in the config
ENABLE_SYSLOG_FILE IPT_SYSLOG_FILE IPT_WRITE_FWDATA
ETC_RSYSLOG_CONF IFCFGTYPE ENABLE_WHOIS_FORCE_ASCII
ENABLE_WHOIS_FORCE_SRC_IP ENABLE_IPV6_DETECTION
- PERSISTENCE_CTR_THRESHOLD MAX_SCAN_IP_PAIRS
+ PERSISTENCE_CTR_THRESHOLD MAX_SCAN_IP_PAIRS INSTALL_ROOT
));
&defined_vars(\@required_vars);
return;