root/psad/tags/psad-2.0.2-pre4/install.pl

Revision 1847, 71.5 kB (checked in by mbr, 2 years ago)

minor update to run 'make clean' under more conditions for previously installed psad perl modules

  • Property svn:eol-style set to native
  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
Line 
1 #!/usr/bin/perl -w
2 #
3 #########################################################################
4 #
5 # File: install.pl
6 #
7 # Purpose:  install.pl is the installation script for psad.  It is safe
8 #           to execute install.pl even if psad has already been installed
9 #           on a system since install.pl will preserve the existing
10 #           config section within the new script.
11 #
12 # Credits:  (see the CREDITS file)
13 #
14 # Copyright (C) 1999-2006 Michael Rash (mbr@cipherdyne.org)
15 #
16 # License (GNU Public License):
17 #
18 #    This program is distributed in the hope that it will be useful,
19 #    but WITHOUT ANY WARRANTY; without even the implied warranty of
20 #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21 #    GNU General Public License for more details.
22 #
23 #    You should have received a copy of the GNU General Public License
24 #    along with this program; if not, write to the Free Software
25 #    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
26 #    USA
27 #
28 # TODO:
29 #
30 #########################################################################
31 #
32 # $Id$
33 #
34
35 use Cwd;
36 use File::Path;
37 use File::Copy;
38 use Sys::Hostname;
39 use IO::Socket;
40 use Getopt::Long;
41 use strict;
42
43 ### Note that Psad.pm is not included within the above list (installation
44 ### over existing psad should not make use of an old Psad.pm).
45
46 ### These three variables should not really be changed unless
47 ### you're really sure.
48 my $PSAD_DIR     = '/var/log/psad';
49 my $PSAD_CONFDIR = '/etc/psad';
50 my $VARLIBDIR    = '/var/lib/psad';
51 my $RUNDIR       = '/var/run/psad';
52 my $LIBDIR       = '/usr/lib/psad';
53
54 #============== config ===============
55 my $INSTALL_LOG  = "${PSAD_DIR}/install.log";
56 my $PSAD_FIFO    = "${VARLIBDIR}/psadfifo";
57 my $INIT_DIR     = '/etc/init.d';
58 my $USRSBIN_DIR  = '/usr/sbin'### consistent with FHS (Filesystem
59                                  ### Hierarchy Standard)
60 my $USRBIN_DIR   = '/usr/bin'### consistent with FHS (Filesystem
61 my $CONF_ARCHIVE = "${PSAD_CONFDIR}/archive";
62 my @LOGR_FILES   = (*STDOUT, $INSTALL_LOG);
63 my $RUNLEVEL;    ### This should only be set if install.pl
64                  ### cannot determine the correct runlevel
65 my $WHOIS_PSAD   = "${USRBIN_DIR}/whois_psad";
66
67 ### directory in which to install snort rules
68 my $SNORT_DIR    = "${PSAD_CONFDIR}/snort_rules";
69
70 ### system binaries ###
71 my $chkconfigCmd = '/sbin/chkconfig';
72 my $rcupdateCmd  = '/sbin/rc-update'### Gentoo
73 my $gzipCmd      = '/usr/bin/gzip';
74 my $psCmd        = '/bin/ps';
75 my $netstatCmd   = '/bin/netstat';
76 my $ifconfigCmd  = '/sbin/ifconfig';
77 my $mknodCmd     = '/bin/mknod';
78 my $makeCmd      = '/usr/bin/make';
79 my $killallCmd   = '/usr/bin/killall';
80 my $perlCmd      = '/usr/bin/perl';
81 my $iptablesCmd  = '/sbin/iptables';
82 my $psadCmd      = "${USRSBIN_DIR}/psad";
83 #============ end config ============
84
85 ### map perl modules to versions
86 my %required_perl_modules = (
87     'Unix::Syslog' => {
88         'force-install' => 0,
89         'mod-dir' => 'Unix-Syslog'
90     },
91     'Bit::Vector' => {
92         'force-install' => 0,
93         'mod-dir' => 'Bit-Vector'
94     },
95     'Date::Calc', => {
96         'force-install' => 0,
97         'mod-dir' => 'Date-Calc'
98     },
99     'Net::IPv4Addr' => {
100         'force-install' => 0,
101         'mod-dir' => 'Net-IPv4Addr'
102     },
103     'IPTables::Parse' => {
104         'force-install' => 1,
105         'mod-dir' => 'IPTables-Parse'
106     },
107     'IPTables::ChainMgr' => {
108         'force-install' => 1,
109         'mod-dir' => 'IPTables-ChainMgr'
110     },
111     'Psad' => {
112         'force-install' => 1,
113         'mod-dir' => 'Psad'
114     }
115 );
116
117 my @cmd_search_paths = qw(
118     /bin
119     /sbin
120     /usr/bin
121     /usr/sbin
122     /usr/local/bin
123     /usr/local/sbin
124 );
125
126 ### IP regex
127 my $ip_re = '(?:\d{1,3}\.){3}\d{1,3}';
128
129 ### used to preserve old FW_MSG_SEARCH vars from previous
130 ### psad installation.  This is only needed when upgrading
131 ### to a newer version of psad that uses the fw_search.conf
132 ### file from a previous version that doesn't.
133 my @old_fw_msg_search;
134
135 ### get the hostname of the system
136 my $HOSTNAME = hostname();
137
138 my $src_dir = getcwd() or die "[*] Could not get current working directory.";
139
140 if (-e $INSTALL_LOG) {
141     open INSTALL, "> $INSTALL_LOG" or
142         die "[*] Could not open $INSTALL_LOG: $!";
143     close INSTALL;
144 }
145
146 ### scope these vars
147 my $PERL_INSTALL_DIR;  ### This is used to find pre-0.9.2 installations of psad
148
149 ### set the install directory for the Psad.pm module
150 my $found = 0;
151 for my $dir (@INC) {
152     if ($dir =~ /site_perl\/\d\S+/) {
153         $PERL_INSTALL_DIR = $dir;
154         $found = 1;
155         last;
156     }
157 }
158 unless ($found) {
159     $PERL_INSTALL_DIR = $INC[0];
160 }
161
162 ### set the default execution flags and command line args
163 my $noarchive   = 0;
164 my $uninstall   = 0;
165 my $help        = 0;
166 my $archived_old = 0;
167 my $skip_syslog_test = 0;
168 my $skip_module_install   = 0;
169 my $cmdline_force_install = 0;
170 my $force_path_update = 0;
171 my $force_install_re  = '';
172 my $syslog_conf = '';
173
174 ### make Getopts case sensitive
175 Getopt::Long::Configure('no_ignore_case');
176
177 &usage(1) unless (GetOptions(
178     'force-mod-install' => \$cmdline_force_install,  ### force install of all modules
179     'Force-mod-regex=s' => \$force_install_re,  ### force specific mod install with regex
180     'path-update'       => \$force_path_update, ### update command paths
181     'Skip-mod-install'  => \$skip_module_install,
182     'no-preserve'       => \$noarchive,   ### Don't preserve existing configs.
183     'syslog-conf=s'     => \$syslog_conf, ### specify path to syslog config file.
184     'no-syslog-test'    => \$skip_syslog_test,
185     'uninstall'         => \$uninstall,   ### Uninstall psad.
186     'help'              => \$help         ### Display help.
187 ));
188 &usage(0) if $help;
189
190 my %Cmds = (
191     'gzip'     => $gzipCmd,
192     'ps'       => $psCmd,
193     'mknod'    => $mknodCmd,
194     'netstat'  => $netstatCmd,
195     'ifconfig' => $ifconfigCmd,
196     'make'     => $makeCmd,
197     'killall'  => $killallCmd,
198     'perl'     => $perlCmd,
199     'iptables' => $iptablesCmd,
200 );
201
202 my $distro = &get_distro();
203
204 if ($distro eq 'redhat' or $distro eq 'fedora') {
205     ### add chkconfig only if we are runing on a redhat distro
206     $Cmds{'chkconfig'} = $chkconfigCmd;
207 } elsif ($distro eq 'gentoo') {
208     ### add rc-update if we are running on a gentoo distro
209     $Cmds{'rc-update'} = $rcupdateCmd;
210 }
211
212 my $init_dir = '';
213
214 if (-d $INIT_DIR) {
215     $init_dir = $INIT_DIR;
216 } elsif (-d '/etc/rc.d/init.d') {
217     $init_dir = '/etc/rc.d/init.d';
218 } elsif (-d '/etc/rc.d') {  ### for Slackware
219     $init_dir = '/etc/rc.d';
220 } else {
221     die "[*] Cannot find the init script directory, edit ",
222         "the \$INIT_DIR variable.\n";
223 }
224
225 ### need to make sure this exists before attempting to
226 ### write anything to the install log.
227 mkdir $PSAD_DIR, 0500 unless -d $PSAD_DIR;
228
229 ### make sure the system binaries are where we expect
230 ### them to be.
231 &check_commands();
232
233 $Cmds{'psad'} = $psadCmd;
234
235 ### check to make sure we are running as root
236 $< == 0 && $> == 0 or die "You need to be root (or equivalent UID 0",
237     " account) to install/uninstall psad!\n";
238
239 ### occasionally things from old psad installations need to be
240 ### dealt with separately.
241 &check_old_psad_installation();
242
243 if ($uninstall) {
244     &uninstall();
245 } else {
246     &install();
247 }
248 exit 0;
249 #================= end main =================
250
251 sub install() {
252
253     ### make sure install.pl is being called from the source directory
254     unless (-e 'psad' && -e 'Psad/lib/Psad.pm') {
255         die "[*] install.pl can only be executed from the directory\n",
256             "    that contains the psad sources!  Exiting.";
257     }
258     &logr('[+] ' . localtime() . " Installing psad on hostname: $HOSTNAME\n");
259
260     ### make sure another psad process is not running
261     if (&ask_to_stop_psad()) {
262         &stop_psad();
263     }
264
265     unless (-d $RUNDIR) {
266         &logr("[+] Creating $RUNDIR\n");
267         mkdir $RUNDIR, 0500;
268     }
269     unless (-d $VARLIBDIR) {
270         &logr("[+] Creating $VARLIBDIR\n");
271         mkdir $VARLIBDIR, 0500;
272     }
273
274     ### deal with old psad_auto_ips path
275     if (-e "${PSAD_CONFDIR}/psad_auto_ips") {
276         move "${PSAD_CONFDIR}/psad_auto_ips",
277             "${PSAD_CONFDIR}/auto_dl" or die "[*] Could not move ",
278             "${PSAD_CONFDIR}/psad_auto_ips -> ${PSAD_CONFDIR}/auto_dl: $!";
279     }
280     ### deal with old psad_signatures path
281     if (-e "${PSAD_CONFDIR}/psad_signatures") {
282         move "${PSAD_CONFDIR}/psad_signatures",
283             "${PSAD_CONFDIR}/signatures" or die "[*] Could not move ",
284             "${PSAD_CONFDIR}/psad_signatures -> ${PSAD_CONFDIR}/signatures: $!";
285     }
286     ### deal with old psad_posf path
287     if (-e "${PSAD_CONFDIR}/psad_posf") {
288         move "${PSAD_CONFDIR}/psad_posf",
289             "${PSAD_CONFDIR}/posf" or die "[*] Could not move ",
290             "${PSAD_CONFDIR}/psad_posf -> ${PSAD_CONFDIR}/posf: $!";
291     }
292     ### deal with old psad_icmp_types path
293     if (-e "${PSAD_CONFDIR}/psad_icmp_types") {
294         move "${PSAD_CONFDIR}/psad_icmp_types",
295             "${PSAD_CONFDIR}/icmp_types" or die "[*] Could not move ",
296             "${PSAD_CONFDIR}/psad_icmp_types -> ${PSAD_CONFDIR}/icmp_types: $!";
297     }
298
299     ### change any existing psad module directory to allow anyone to execute
300     chmod 0755, $LIBDIR;
301     unless (-d $PSAD_CONFDIR) {
302         &logr("[+] Creating $PSAD_CONFDIR\n");
303         mkdir $PSAD_CONFDIR, 0500;
304     }
305     unless (-d $CONF_ARCHIVE) {
306         &logr("[+] Creating $CONF_ARCHIVE\n");
307         mkdir $CONF_ARCHIVE, 0500;
308     }
309     unless (-e $PSAD_FIFO) {
310         &logr("[+] Creating named pipe $PSAD_FIFO\n");
311         unless (((system "$Cmds{'mknod'} -m 600 $PSAD_FIFO p")>>8) == 0) {
312             &logr("[*] Could not create the named pipe \"$PSAD_FIFO\"!\n" .
313                 "[*] psad requires this file to exist!  Aborting install.\n");
314             die;
315         }
316         unless (-p $PSAD_FIFO) {
317             &logr("[*] Could not create the named pipe \"$PSAD_FIFO\"!\n" .
318                 "[*] psad requires this file to exist!  Aborting " .
319                 "install.\n");
320             die;
321         }
322     }
323
324     unless (-d $PSAD_DIR) {
325         &logr("[+] Creating $PSAD_DIR\n");
326         mkdir $PSAD_DIR, 0500;
327     }
328     unless (-e "${PSAD_DIR}/fwdata") {
329         &logr("[+] Creating ${PSAD_DIR}/fwdata file\n");
330         open F, "> ${PSAD_DIR}/fwdata" or die "[*] Could not open ",
331             "${PSAD_DIR}/fwdata: $!";
332         close F;
333         chmod 0600, "${PSAD_DIR}/fwdata";
334         &perms_ownership("${PSAD_DIR}/fwdata", 0600);
335     }
336
337     unless (-d $USRSBIN_DIR) {
338         &logr("[+] Creating $USRSBIN_DIR\n");
339         mkdir $USRSBIN_DIR,0755;
340     }
341     if (-d 'whois') {
342         &logr("[+] Compiling Marco d'Itri's whois client\n");
343         system "$Cmds{'make'} -C whois";
344         if (-e 'whois/whois') {
345             &logr("[+] Copying whois binary to $WHOIS_PSAD\n");
346             copy "whois/whois", $WHOIS_PSAD or die "[*] Could not copy ",
347                 "whois/whois -> $WHOIS_PSAD: $!";
348         } else {
349             die "[*] Could not compile whois";
350         }
351     }
352     &perms_ownership($WHOIS_PSAD, 0755);
353     print "\n\n";
354
355     ### install perl modules
356     unless ($skip_module_install) {
357         for my $module (keys %required_perl_modules) {
358             &install_perl_module($module);
359         }
360     }
361
362     &logr("[+] Installing Snort-2.3.3 signatures in $SNORT_DIR\n");
363     unless (-d $SNORT_DIR) {
364         mkdir $SNORT_DIR, 0500 or die "[*] Could not create $SNORT_DIR: $!";
365     }
366     opendir D, 'snort_rules' or die "[*] Could not open ",
367         "the snort_rules directory: $!";
368     my @files = readdir D;
369     closedir D;
370
371     for my $file (@files) {
372         next unless $file =~ /\.rules$/ or $file =~ /\.config$/;
373         &logr("[+] Installing snort_rules/${file}\n");
374         copy "snort_rules/${file}", "${SNORT_DIR}/${file}" or
375             die "[*] Could not copy snort_rules/${file} -> ",
376                 "${SNORT_DIR}/${file}: $!";
377         &perms_ownership("${SNORT_DIR}/${file}", 0600);
378     }
379     print "\n\n";
380
381     &logr("[+] Compiling kmsgsd, and psadwatchd:\n");
382
383     ### remove any previously compiled kmsgsd
384     unlink 'kmsgsd' if -e 'kmsgsd';
385
386     ### remove any previously compiled psadwatchd
387     unlink 'psadwatchd' if -e 'psadwatchd';
388
389     ### compile the C psad daemons
390     system $Cmds{'make'};
391     if (! -e 'kmsgsd' && -e 'kmsgsd.pl') {
392         &logr("[-] Could not compile kmsgsd.c.  Installing perl kmsgsd.\n");
393         unless (((system "$Cmds{'perl'} -c kmsgsd.pl")>>8) == 0) {
394             die "[*] kmsgsd.pl does not compile with \"perl -c\".  ",
395                 "Download the latest sources " .
396                 "from:\n\nhttp://www.cipherdyne.org/\n";
397         }
398         copy 'kmsgsd.pl', 'kmsgsd' or die "[*] Could not copy ",
399             "kmsgsd.pl -> kmsgsd: $!";
400     }
401     if (! -e 'psadwatchd' && -e 'psadwatchd.pl') {
402         &logr("[-] Could not compile psadwatchd.c.  " .
403             "Installing perl psadwatchd.\n");
404         unless (((system "$Cmds{'perl'} -c psadwatchd.pl")>>8) == 0) {
405             die "[*] psadwatchd.pl does not compile with \"perl -c\".  ",
406                 "Download the latest sources " .
407                 "from:\n\nhttp://www.cipherdyne.org/\n";
408         }
409         copy 'psadwatchd.pl', 'psadwatchd' or die "[*] Could not copy ",
410             "psadwatchd.pl -> psadwatchd: $!";
411     }
412
413     ### install fwcheck_psad.pl
414     print "\n\n";
415     &logr("[+] Verifying compilation of fwcheck_psad.pl script:\n");
416     unless (((system "$Cmds{'perl'} -c fwcheck_psad.pl")>>8) == 0) {
417         die "[*] fwcheck_psad.pl does not compile with \"perl -c\".  Download ",
418             "the latest sources from:\n\nhttp://www.cipherdyne.org/\n";
419     }
420
421     ### make sure the psad (perl) daemon compiles.  The other three
422     ### daemons have all been re-written in C.
423     &logr("[+] Verifying compilation of psad perl daemon:\n");
424     unless (((system "$Cmds{'perl'} -c psad")>>8) == 0) {
425         die "[*] psad does not compile with \"perl -c\".  Download the",
426             " latest sources from:\n\nhttp://www.cipherdyne.org/\n";
427     }
428     print "\n\n";
429
430     ### install nf2csv
431     print "\n\n";
432     &logr("[+] Verifying compilation of nf2csv script:\n");
433     unless (((system "$Cmds{'perl'} -c nf2csv")>>8) == 0) {
434         die "[*] nf2csv does not compile with \"perl -c\".  Download ",
435             "the latest sources from:\n\nhttp://www.cipherdyne.org/\n";
436     }
437
438     ### put the nf2csv script in place
439     unlink '/usr/sbin/nf2csv' if -e '/usr/sbin/nf2csv'### old path
440     &logr("[+] Copying nf2csv -> ${USRBIN_DIR}/nf2csv\n");
441     unlink "${USRBIN_DIR}/nf2csv" if -e "${USRBIN_DIR}/nf2csv";
442     copy 'nf2csv', "${USRBIN_DIR}/nf2csv" or die "[*] Could ",
443         "not copy nf2csv -> ${USRBIN_DIR}/nf2csv: $!";
444     &perms_ownership("${USRBIN_DIR}/nf2csv", 0755);
445
446     ### put the fwcheck_psad.pl script in place
447     &logr("[+] Copying fwcheck_psad.pl -> ${USRSBIN_DIR}/fwcheck_psad\n");
448     unlink "${USRSBIN_DIR}/fwcheck_psad" if -e "${USRSBIN_DIR}/fwcheck_psad";
449     copy 'fwcheck_psad.pl', "${USRSBIN_DIR}/fwcheck_psad" or die "[*] Could ",
450         "not copy fwcheck_psad.pl -> ${USRSBIN_DIR}/fwcheck_psad: $!";
451     &perms_ownership("${USRSBIN_DIR}/fwcheck_psad", 0500);
452
453     ### put the psad daemons in place
454     &logr("[+] Copying psad -> ${USRSBIN_DIR}/psad\n");
455     unlink "${USRSBIN_DIR}/psad" if -e "${USRSBIN_DIR}/psad";
456     copy 'psad', "${USRSBIN_DIR}/psad" or die "[*] Could not copy ",
457         "psad -> ${USRSBIN_DIR}/psad: $!";
458     &perms_ownership("${USRSBIN_DIR}/psad", 0500);
459
460     &logr("[+] Copying psadwatchd -> ${USRSBIN_DIR}/psadwatchd\n");
461     unlink "${USRSBIN_DIR}/psadwatchd" if -e "${USRSBIN_DIR}/psadwatchd";
462     copy 'psadwatchd', "${USRSBIN_DIR}/psadwatchd" or die "[*] Could not ",
463         "copy psadwatchd -> ${USRSBIN_DIR}/psadwatchd: $!";
464     &perms_ownership("${USRSBIN_DIR}/psadwatchd", 0500);
465
466     &logr("[+] Copying kmsgsd -> ${USRSBIN_DIR}/kmsgsd\n");
467     unlink "${USRSBIN_DIR}/kmsgsd" if -e "${USRSBIN_DIR}/kmsgsd";
468     copy 'kmsgsd', "${USRSBIN_DIR}/kmsgsd" or die "[*] Could not copy ",
469         "kmsgsd -> ${USRSBIN_DIR}/kmsgsd: $!";
470     &perms_ownership("${USRSBIN_DIR}/kmsgsd", 0500);
471
472     unless (-d $PSAD_CONFDIR) {
473         &logr("[+] Creating $PSAD_CONFDIR\n");
474         mkdir $PSAD_CONFDIR,0500;
475     }
476
477     ### get syslog daemon (e.g. syslog, syslog-ng, or metalog)
478     my $syslog_str = &query_syslog();
479
480     my $preserve_rv = 0;
481     if (-e "${PSAD_CONFDIR}/psad.conf") {
482         $preserve_rv = &query_preserve_config();
483     }
484
485     ### the order of the config files is important (legacy FW_MSG_SEARCH
486     ### vars in psad.conf).
487     for my $file qw(psad.conf psadwatchd.conf
488             kmsgsd.conf fw_search.conf alert.conf) {
489         if (-e "${PSAD_CONFDIR}/$file") {
490             &archive("${PSAD_CONFDIR}/$file") unless $noarchive;
491             if ($preserve_rv) {
492                 &preserve_config($file);
493             } else {
494                 &logr("[+] Copying $file -> ${PSAD_CONFDIR}/$file\n");
495                 copy $file, "${PSAD_CONFDIR}/$file" or die "[*] Could not ",
496                     "copy $file -> ${PSAD_CONFDIR}/$file: $!";
497             }
498             if ($file eq 'fw_search.conf' and @old_fw_msg_search) {
499                 &logr("[-] Warning: psad.conf contains FW_MSG_SEARCH vars, " .
500                     "but fw_search.conf also exists!\n");
501             }
502         } else {
503             &logr("[+] Copying $file -> ${PSAD_CONFDIR}/$file\n");
504             copy $file, "${PSAD_CONFDIR}/$file" or die "[*] Could not copy ",
505                 "$file -> ${PSAD_CONFDIR}/$file: $!";
506
507             ### Deal with legacy FW_MSG_SEARCH in psad.conf.  Note that
508             ### this will only preserve old search strings if 1) they already
509             ### existed within psad.conf and 2) the file fw_search.conf does
510             ### not already exist in /etc/psad/.
511             if ($file eq 'fw_search.conf' and @old_fw_msg_search) {
512                 &preserve_old_fw_msg_search();
513             }
514         }
515
516         if ($force_path_update or not $preserve_rv) {
517             &update_command_paths("$PSAD_CONFDIR/$file")
518                 if ($file eq 'psad.conf' or $file eq 'psadwatchd.conf');
519         }
520
521         &perms_ownership("${PSAD_CONFDIR}/$file", 0600);
522     }
523
524     ### deal with any legacy diskmond.conf file
525     if (-e "${PSAD_CONFDIR}/diskmond.conf") {
526         &archive("${PSAD_CONFDIR}/diskmond.conf") unless $noarchive;
527         unlink "${PSAD_CONFDIR}/diskmond.conf";
528     }
529
530     ### install auto_dl, signatures, icmp_types, posf, and pf.os files
531     for my $file qw(signatures icmp_types
532             posf auto_dl snort_rule_dl pf.os ip_options) {
533         if (-e "${PSAD_CONFDIR}/$file") {
534             &archive("${PSAD_CONFDIR}/$file") unless $noarchive;
535 ### FIXME, need a real config preservation routine for these files.
536 #            unless (&query_preserve_sigs_autodl("${PSAD_CONFDIR}/$file")) {
537         }
538         &logr("[+] Copying $file -> ${PSAD_CONFDIR}/$file\n");
539         copy $file, "${PSAD_CONFDIR}/$file" or die "[*] Could not ",
540             "copy $file -> ${PSAD_CONFDIR}/$file: $!";
541         &perms_ownership("${PSAD_CONFDIR}/$file", 0600);
542     }
543     &logr("\n");
544
545     unless ($preserve_rv) {  ### we want to preserve the existing config
546
547         ### get email address(es)
548         my $email_str = &query_email();
549         if ($email_str) {
550             for my $file qw(psad.conf psadwatchd.conf) {
551                 &put_string('EMAIL_ADDRESSES', $email_str,
552                     "${PSAD_CONFDIR}/$file");
553             }
554         }
555
556         ### Give the admin the opportunity to set the strings that are
557         ### parsed out of iptables messages.  This is useful since the
558         ### admin may have configured the firewall to use a logging prefix
559         ### of "Audit" or something else other than the default string
560         ### "DROP".
561         my $fw_search_aref = &get_fw_search_strings();
562         if ($fw_search_aref) {
563             open F, "< ${PSAD_CONFDIR}/fw_search.conf"
564                 or die "[*] Could not open ${PSAD_CONFDIR}/fw_search.conf: $!";
565             my @lines = <F>;
566             close F;
567             open T, "> ${PSAD_CONFDIR}/fw_search.conf.tmp"
568                 or die "[*] Could not open ${PSAD_CONFDIR}/fw_search.conf.tmp: $!";
569             for my $line (@lines) {
570                 if ($line =~ /^\s*FW_MSG_SEARCH/) {
571                     last;
572                 } else {
573                     print T $line;
574                 }
575             }
576             for my $fw_str (@$fw_search_aref) {
577                 &logr(qq{[+] Setting FW_MSG_SEARCH to "$fw_str" } .
578                     "in ${PSAD_CONFDIR}/fw_search.conf\n");
579                 printf T "%-28s%s;\n", 'FW_MSG_SEARCH', $fw_str;
580             }
581             close T;
582             move "${PSAD_CONFDIR}/fw_search.conf.tmp",
583                 "${PSAD_CONFDIR}/fw_search.conf" or die "[*] Could not move ",
584                 "${PSAD_CONFDIR}/fw_search.conf.tmp -> ",
585                 "${PSAD_CONFDIR}/fw_search.conf: $!";
586         }
587         ### Give the admin the opportunity to set the HOME_NET variable.
588         &set_home_net("${PSAD_CONFDIR}/psad.conf");
589
590         ### see if the admin would like to have psad send info to
591         ### DShield
592         if (&query_dshield()) {
593             &put_string('ENABLE_DSHIELD_ALERTS', 'Y',
594                 "${PSAD_CONFDIR}/psad.conf");
595         }
596
597         ### Set the hostname
598         for my $file ("${PSAD_CONFDIR}/psad.conf",
599                 "${PSAD_CONFDIR}/kmsgsd.conf",
600                 "${PSAD_CONFDIR}/psadwatchd.conf") {
601             &logr("[+] Setting hostname to \"$HOSTNAME\" in $file\n");
602             &set_hostname($file);
603         }
604     }
605
606     &put_string('SYSLOG_DAEMON', $syslog_str,
607         "${PSAD_CONFDIR}/psad.conf");
608
609     if ($syslog_str ne 'ulogd') {
610         my $restarted_syslog = 0;
611         if ($syslog_str eq 'syslogd') {
612             if (-e $syslog_conf) {
613                 &append_fifo_syslog($syslog_conf);
614                 if (((system "$Cmds{'killall'} -HUP syslogd 2> /dev/null")>>8) == 0) {
615                     &logr("[+] HUP signal sent to syslogd.\n");
616                     $restarted_syslog = 1;
617                 }
618             }
619         } elsif ($syslog_str eq 'syslog-ng') {
620             if (-e $syslog_conf) {
621                 &append_fifo_syslog_ng($syslog_conf);
622                 if (((system "$Cmds{'killall'} -HUP syslog-ng 2> /dev/null")>>8) == 0) {
623                     &logr("[+] HUP signal sent to syslog-ng.\n");
624                     $restarted_syslog = 1;
625                 }
626             }
627         } elsif ($syslog_str eq 'metalog') {
628             if (-e $syslog_conf) {
629                 &config_metalog($syslog_conf);
630                 &logr("[-] Metalog support is shaky in psad.  " .
631                     "Use at your own risk.\n");
632                 ### don't send warning about not restarting metalog daemon
633                 $restarted_syslog = 1;
634             }
635         }
636
637         unless ($restarted_syslog) {
638             &logr("[-] Could not restart any syslog daemons.\n");
639         }
640     }
641
642     if (-x $Cmds{'iptables'} and not $skip_syslog_test) {
643         &logr("[+] Found iptables. Testing syslog configuration:\n");
644         ### make sure we actually see packets being logged by
645         ### the firewall.
646         if ($syslog_str ne 'ulogd') {
647             if (&test_syslog_config($syslog_str)) {
648                 &logr("[+] Successful $syslog_str reconfiguration.\n\n");
649             } else {
650                 if (&query_init_script_restart_syslog()) {
651
652                     my $restarted = 0;
653                     if (-e "$INIT_DIR/sysklogd") {
654                         system "$INIT_DIR/sysklogd restart";
655                         $restarted = 1;
656                     } elsif (-e "$INIT_DIR/syslog") {
657                         system "$INIT_DIR/syslogd restart";
658                         $restarted = 1;
659                     }
660                     ### test syslog config again now that we
661                     ### have restarted syslog via the init script
662                     ### instead of relying on a HUP signal to
663                     ### syslog
664                     if ($restarted) {
665                         if (&test_syslog_config($syslog_str)) {
666                             &logr("[+] Successful $syslog_str reconfiguration.\n\n");
667                         } else {
668                             &logr("[-] Unsuccessful $syslog_str reconfiguration.\n");
669                             &logr("    Consult the psad man page for the basic " .
670                                 "$syslog_str requirement to get psad to work.\n\n");
671                         }
672                     }
673                 } else {
674                     &logr("[-] Ok, hoping that psad can get packet data anyway.\n");
675                 }
676             }
677         }
678     }
679
680     ### make sure the PSAD_DIR and PSAD_FIFO variables are correctly defined
681     ### in psad.conf and kmsgsd.conf
682     &put_string('PSAD_DIR', $PSAD_DIR, "${PSAD_CONFDIR}/psad.conf");
683     &put_string('PSAD_FIFO', $PSAD_FIFO, "${PSAD_CONFDIR}/kmsgsd.conf");
684
685     &install_manpage('psad.8');
686     &install_manpage('psadwatchd.8');
687     &install_manpage('kmsgsd.8');
688     &install_manpage('nf2csv.1');
689
690     my $init_file = '';
691     if ($distro eq 'redhat') {
692         $init_file = 'init-scripts/psad-init.redhat';
693     } elsif ($distro eq 'fedora') {
694         $init_file = 'init-scripts/psad-init.fedora';
695     } elsif ($distro eq 'gentoo') {
696         $init_file = 'init-scripts/psad-init.gentoo';
697     } else {
698         $init_file = 'init-scripts/psad-init.generic';
699     }
700
701     if ($init_dir) {
702         &logr("[+] Copying $init_file -> ${init_dir}/psad\n");
703         copy $init_file, "${init_dir}/psad" or die "[*] Could not copy ",
704             "$init_file -> ${init_dir}/psad: $!";
705         &perms_ownership("${init_dir}/psad", 0744);
706         &enable_psad_at_boot($distro);
707     }
708
709     &logr("\n========================================================\n");
710     if ($archived_old) {
711         &logr("[+] Copies of your original configs have been made " .
712             "in: $CONF_ARCHIVE\n");
713     }
714     if ($preserve_rv) {
715         &logr("\n[+] Psad has been installed (with your original config merged).\n");
716     } else {
717         &logr("\n[+] Psad has been installed.\n");
718     }
719     if ($init_dir) {
720         &logr("\n[+] To start psad, run \"${init_dir}/psad start\"\n");
721     } else {
722         &logr("\n[+] To start psad, run ${USRSBIN_DIR}/psad\"\n");
723     }
724     return;
725 }
726
727 sub uninstall() {
728     &logr("\n[+] Uninstalling psad from $HOSTNAME: " . localtime() . "\n");
729
730     my $ans = '';
731     while ($ans ne 'y' && $ans ne 'n') {
732         print '[+] This will completely remove psad ',
733             "from your system.\n    Are you sure (y/n)? ";
734         $ans = <STDIN>;
735         chomp $ans;
736     }
737     if ($ans eq 'n') {
738         &logr("[*] User aborted uninstall by answering \"n\" to the remove " .
739             "question!  Exiting.\n");
740         exit 0;
741     }
742     ### after this point, psad will really be uninstalled so stop writing stuff
743     ### to the install.log file.  Just print everything to STDOUT
744     if (-e "${RUNDIR}/psad.pid") {
745         open PID, "${RUNDIR}/psad.pid" or die "[*] Could not open ",
746