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

Revision 1875, 73.5 kB (checked in by mbr, 2 years ago)

minor comment fixes

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