root/fwknop/tags/fwknop-0.9.7-pre3/install.pl

Revision 479, 41.3 kB (checked in by mbr, 2 years ago)

minor refactoring to use the VERSION files in perl module directories (to not use them is a bug)

  • 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: Installer for fwknop
8 #
9 # Credits:  (see the CREDITS file)
10 #
11 # Copyright (C) 1999-2002 Michael Rash (mbr@cipherdyne.org)
12 #
13 # License (GNU Public License):
14 #
15 #    This program is distributed in the hope that it will be useful,
16 #    but WITHOUT ANY WARRANTY; without even the implied warranty of
17 #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 #    GNU General Public License for more details.
19 #
20 #    You should have received a copy of the GNU General Public License
21 #    along with this program; if not, write to the Free Software
22 #    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
23 #    USA
24 #
25 #############################################################################
26 #
27 # $Id$
28 #
29
30 use Cwd;
31 use File::Copy;
32 use File::Path;
33 use Getopt::Long;
34 use Sys::Hostname;
35 use strict;
36
37 #========================== config ===========================
38 my $libdir     = '/usr/lib/fwknop';
39 my $confdir    = '/etc/fwknop';
40 my $vardir     = '/var/log/fwknop';
41 my $varlibdir  = '/var/lib/fwknop';
42 my $piddir     = '/var/run/fwknop';
43 my $archivedir = "$confdir/archive";
44 my $bindir     = '/usr/bin';
45 my $sbindir    = '/usr/sbin';
46 my $initdir    = '/etc/init.d';
47
48 ### only used it $ENV{'HOME'} is not set for some reason
49 my $config_homedir = '';
50
51 my $fwknop_fifo = "$varlibdir/fwknopfifo";
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 $gzipCmd      = '/bin/gzip';
59 my $killallCmd   = '/usr/bin/killall';
60 my $mknodCmd     = '/bin/mknod';
61 my $ifconfigCmd  = '/sbin/ifconfig';
62 #======================== end config =========================
63
64 my $client_install = 0;
65 my $homedir = '';
66 my $syslog_conf = '';
67 my $distro = '';
68 my $print_help = 0;
69 my $uninstall  = 0;
70 my $data_method = '';
71 my $runlevel;
72 my $cmdline_force_install = 0;
73
74 ### perl module directories
75 my %required_perl_modules = (
76     'Class::MethodMaker' => {
77         'force-install' => 0,
78         'mod-dir' => 'Class-MethodMaker'
79     },
80     'GnuPG::Interface' => {
81         'force-install' => 0,
82         'mod-dir' => 'GnuPG-Interface'
83     },
84     'Unix::Syslog' => {
85         'force-install' => 0,
86         'mod-dir' => 'Unix-Syslog'
87     },
88     'Net::IPv4Addr' => {
89         'force-install' => 0,
90         'mod-dir' => 'Net-IPv4Addr'
91     },
92     'Net::RawIP' => {
93         'force-install' => 0,
94         'mod-dir' => 'Net-RawIP'
95     },
96     'Net::Ping::External' => {
97         'force-install' => 0,
98         'mod-dir' => 'Net-Ping-External'
99     },
100     'Net::Pcap' => {
101         'force-install' => 0,
102         'mod-dir' => 'Net-Pcap'
103     },
104     'Crypt::Rijndael' => {
105         'force-install' => 0,
106         'mod-dir' => 'Crypt-Rijndael'
107     },
108     'Crypt::CBC' => {
109         'force-install' => 0,
110         'mod-dir' => 'Crypt-CBC'
111     },
112     'Term::ReadKey' => {
113         'force-install' => 0,
114         'mod-dir' => 'TermReadKey'
115     },
116     'IPTables::Parse' => {
117         'force-install' => 1,
118         'mod-dir' => 'IPTables-Parse'
119     },
120     'IPTables::ChainMgr' => {
121         'force-install' => 1,
122         'mod-dir' => 'IPTables-ChainMgr'
123     }
124 );
125
126 my %cmds = (
127     'make'     => $makeCmd,
128     'perl'     => $perlCmd,
129     'gzip'     => $gzipCmd,
130     'killall'  => $killallCmd,
131     'mknod'    => $mknodCmd,
132     'ifconfig' => $ifconfigCmd,
133 );
134
135 &usage(1) unless (GetOptions(
136     'force-mod-install' => \$cmdline_force_install,  ### force install of all modules
137     'client-only'   => \$client_install, # Force client-only installation
138     'uninstall'     => \$uninstall,      # Uninstall fwknop.
139     'syslog-conf=s' => \$syslog_conf,    # Specify path to syslog config file.
140     'help'          => \$print_help      # Display help.
141 ));
142 &usage(0) if $print_help;
143
144 unless ($< == 0 && $> == 0) {
145     ### we are installing as a normal user instead of root, so see
146     ### if it is ok to install within the user's home directory
147     $homedir = '';
148     if ($config_homedir) {
149         $homedir = $config_homedir;
150     } else {
151         $homedir = $ENV{'HOME'} or die '[*] Could not get home ',
152             "directory, set the $config_homedir var.";
153     }
154     print
155 "[+] It looks like you are installing fwknop as a non-root user.  This will\n",
156 "    result in fwknop being installed in your local home directory.\n",
157 "    Specifically, fwknop will be installed at $homedir/bin/fwknop, and a few\n",
158 "    perl modules needed by fwknop may be installed in $homedir/lib/fwknop/.\n",
159 "    If you want fwknop to act as a server (i.e. monitor knock sequences or\n",
160 "    authentication packets and modify firewall access or execute commands\n",
161 "    accordingly), you will need to install as root.\n\n";
162     $client_install = 1;
163     $libdir = "$homedir/lib/fwknop";
164     $bindir = "$homedir/bin";
165 }
166
167 unless ($client_install) {
168     $distro = &get_distro();
169
170     if ($distro eq 'redhat' or $distro eq 'fedora') {
171         ### add chkconfig only if we are runing on a redhat distro
172         $cmds{'chkconfig'} = $chkconfigCmd;
173     } elsif ($distro eq 'gentoo') {
174         ### add rc-update if we are running on a gentoo distro
175         $cmds{'rc-update'} = $rcupdateCmd;
176     }
177 }
178
179 ### make sure the system binaries are where we expect
180 ### them to be.
181 &check_commands();
182
183 my $hostname = hostname();
184
185 my $src_dir = getcwd() or die "[*] Could not get current working directory.";
186
187 unless ($client_install) {
188     unless (-d $initdir) {
189         if (-d '/etc/rc.d/init.d') {
190             $initdir = '/etc/rc.d/init.d';
191         } elsif (-d '/etc/rc.d') {  ### for Slackware
192             $initdir = '/etc/rc.d';
193         } else {
194             die "[*] Cannot find the init script directory, edit ",
195                 "the \$initdir variable.\n";
196         }
197     }
198 }
199
200 if (not $uninstall) {
201     &install();
202 } else {
203     &uninstall();
204 }
205 exit 0;
206 #======================= end main ==========================
207
208 sub install() {
209     print "[+] Installing fwknop on $hostname\n";
210
211     my $init_file = '';
212     my $preserve_rv = 0;
213     unless ($client_install) {
214         if (&ask_to_stop_fwknop()) {
215             &stop_fwknop();
216         }
217
218         unless (-d '/usr/lib') {
219             mkdir '/usr/lib' or die "[*] Could not mkdir /usr/lib: $!";
220         }
221         unless (-d '/var/run') {
222             mkdir '/var/run' or die "[*] Could not mkdir /var/run: $!";
223         }
224         unless (-d '/var/log') {
225             mkdir '/var/log' or die "[*] Could not mkdir /var/log: $!";
226         }
227         unless (-d $piddir) {
228             mkdir $piddir or die "[*] Could not mkdir $piddir: $!";
229         }
230         unless (-d $varlibdir) {
231             mkdir $varlibdir or die "[*] Could not mkdir $varlibdir: $!";
232         }
233         unless (-d $sbindir) {
234             mkdir $sbindir or die "[*] Could not mkdir $sbindir: $!";
235         }
236     }
237     unless (-d $bindir) {
238         print "[+] Creating: $bindir\n";
239         mkdir $bindir or die "[*] Could not mkdir $bindir: $!";
240     }
241
242     ### config directory
243     unless ($client_install) {
244         if (-d $confdir) {
245             print "[-] Config directory $confdir already exists.\n";
246         } else {
247             ### Note that root will only be able to view files in
248             ### /etc/fwknop since fwknop only needs to view fwknop.conf
249             ### when being run as a daemon.
250             print "[+] Creating config directory: $confdir\n";
251             mkdir $confdir, 0500 or die "[*] Could not mkdir $confdir: $!";
252         }
253
254         if (-d $vardir) {
255             print "[-] Cache directory $vardir already exists.\n";
256         } else {
257             print "[+] Creating cache directory: $vardir\n";
258             mkdir $vardir, 0500 or die "[*] Could not mkdir $vardir: $!";
259         }
260
261         ### archive directory for previously install config files
262         if (-d $archivedir) {
263             print "[-] Archive directory $archivedir already exists.\n";
264         } else {
265             print "[+] Creating archive directory: $archivedir\n";
266             mkdir $archivedir, 0500 or die "[*] Could not mkdir $archivedir: $!";
267         }
268     }
269
270     print "[+] Several perl modules needed by fwknop will be installed in\n",
271         "    $libdir.  Installing them here will keep the system perl\n",
272         "    library tree clean.\n";
273
274     ### make our library directory (for perl modules)
275     if ($client_install) {
276         if (-d "$homedir/lib") {
277             print "[-] Directory $homedir/lib already exists.\n";
278         } else {
279             print "[+] Creating directory $homedir/lib\n";
280             mkdir "$homedir/lib", 0755
281                 or die "[*] Could not mkdir $homedir/lib: $!";
282         }
283     }
284     if (-d $libdir) {
285         print "[-] Lib directory $libdir already exists.\n";
286     } else {
287         print "[+] Creating directory $libdir\n";
288         mkdir $libdir, 0755 or die "[*] Could not mkdir $libdir: $!";
289     }
290
291     ### install perl modules
292     for my $module (keys %required_perl_modules) {
293         &install_perl_module($module);
294     }
295
296     ### special case the NetPacket::<proto> modules since the NetPacket
297     ### directory is just for the base class, and we need to make sure
298     ### we have each of the NetPacket::IP, NetPacket::ICMP, NetPacket::UDP,
299     ### and NetPacket::TCP modules.
300     chdir 'NetPacket' or die "[*] Could not chdir NetPacket directory: $!";
301     unless (-e 'Makefile.PL') {
302         die "[*] Your NetPacket source directory appears to be incomplete!\n",
303             "    Download the latest sources from ",
304             "http://www.cipherdyne.org\n";
305     }
306     system "$cmds{'make'} clean" if -e 'Makefile';
307     system "$cmds{'perl'} Makefile.PL PREFIX=$libdir LIB=$libdir";
308     system $cmds{'make'};
309 #        system "$cmds{'make'} test";
310     system "$cmds{'make'} install";
311     chdir $src_dir or die "[*] Could not chdir $src_dir: $!";
312
313     unless ($client_install) {
314
315         ### install man pages
316         &install_manpage('knopmd.8');
317         &install_manpage('knopwatchd.8');
318         &install_manpage('fwknop.8');
319         &install_manpage('fwknopd.8');
320
321         if ($distro eq 'redhat') {
322             $init_file = 'fwknop-init.redhat';
323         } elsif ($distro eq 'fedora') {
324             $init_file = 'fwknop-init.fedora';
325         } elsif ($distro eq 'gentoo') {
326             $init_file = 'fwknop-init.gentoo';
327         } else {
328             $init_file = 'fwknop-init.generic';
329         }
330
331         if (-e "${confdir}/fwknop.conf") {
332             $preserve_rv = &query_preserve_config();
333         }
334
335         ### install all config and access files
336         for my $file qw(fwknop.conf
337                 knopmd.conf
338                 knopwatchd.conf
339                 access.conf
340                 alert.conf
341                 pf.os) {
342             if (-e "$confdir/$file") {
343                 &archive("$confdir/$file");
344                 if ($preserve_rv) {
345                     if ($file eq 'access.conf') {
346                         ### access.conf can have missing fields (i.e.
347                         ### REQUIRE_OS_REGEX and REQUIRE_USERNAME),
348                         ### and also it can have multiple sequences
349                         ### defined.  Hence we just use the old one.
350                         print "[+] Using original access.conf\n";
351                     } elsif ($file ne 'pf.os') {
352                         &preserve_config($file);
353                     }
354                 } else {
355                     print "[+] Copying $file -> $confdir\n";
356                     copy $file, $confdir or
357                         die "[*] Could not cp $file to $confdir";
358                 }
359             } else {
360                 print "[+] Copying $file -> $confdir\n";
361                 copy $file, $confdir or
362                     die "[*] Could not cp $file to $confdir";
363             }
364             if ($file eq 'knopwatchd.conf') {
365                 &set_hostname("$confdir/$file");
366             }
367             chmod 0600, "$confdir/$file" or
368                 die "[*] Could not chmod(600, $confdir/$file: $!";
369             chown 0, 0, "$confdir/$file" or
370                 die "[*] Could not chown 0, 0, $confdir/$file: $!";
371         }
372
373         ### get data acquisition method (e.g. syslogd, sysylog-ng, ulogd
374         ### or pcap)
375         $data_method = &query_data_method();
376
377         if ($data_method =~ /syslog/) {
378
379             ### create the named pipe
380             unless (-e $fwknop_fifo and -p $fwknop_fifo) {
381                 unlink $fwknop_fifo if -e $fwknop_fifo;
382                 print "[+] Creating named pipe $fwknop_fifo\n";
383                 my $created_pipe = 1;
384                 unless (((system "$cmds{'mknod'} -m 600 $fwknop_fifo p")>>8)
385                         == 0) {
386                     $created_pipe = 0;
387                 }
388                 unless (-e $fwknop_fifo and -p $fwknop_fifo) {
389                     $created_pipe = 0;
390                 }
391                 unless ($created_pipe) {
392                     die
393 "[*] Could not create the named pipe \"$fwknop_fifo\"!\n",
394 "[*] fwknop requires this file to exist!  Aborting install.\n";
395                 }
396             }
397
398             unless (-e "${vardir}/fwdata") {
399                 print "[+] Creating ${vardir}/fwdata file\n";
400                 open F, "> ${vardir}/fwdata" or die "[*] Could not open ",
401                     "${vardir}/fwdata: $!";
402                 close F;
403                 chmod 0600, "${vardir}/fwdata";
404                 &perms_ownership("${vardir}/fwdata", 0600);
405             }
406
407             ### we are acquiring data via syslog
408             &put_string('AUTH_MODE', 'KNOCK', "${confdir}/fwknop.conf");
409
410             &put_string('SYSLOG_DAEMON', $data_method,
411                 "${confdir}/fwknop.conf");
412
413             my $restarted_syslog = 0;
414             if ($data_method eq 'syslogd') {
415                 if (-e $syslog_conf) {
416                     &append_fifo_syslog($syslog_conf);
417                     if (((system "$cmds{'killall'} -HUP syslogd " .
418                             "2> /dev/null")>>8) == 0) {
419                         print "[+] HUP signal sent to syslogd.\n";
420                         $restarted_syslog = 1;
421                     }
422                 }
423             } elsif ($data_method eq 'syslog-ng') {
424                 if (-e $syslog_conf) {
425                     &append_fifo_syslog_ng($syslog_conf);
426                     if (((system "$cmds{'killall'} -HUP syslog-ng " .
427                             "2> /dev/null")>>8) == 0) {
428                         print "[+] HUP signal sent to syslog-ng.\n";
429                         $restarted_syslog = 1;
430                     }
431                 }
432             }
433
434             unless ($restarted_syslog) {
435                 print "[-] Could not restart any syslog daemons.\n";
436             }
437         } elsif ($data_method =~ /pcap/i or $data_method =~ /ulog/i) {
438             ### we are using a pcap method
439             if ($data_method eq 'ulogd' or $data_method eq 'file_pcap') {
440                 print
441 "[+] By default, fwknop uses the file /var/log/sniff.pcap in order to\n",
442 "    acquire packet data logged via a sniffer (or ulogd) to a pcap file,\n",
443 "    but this path may be changed by altering the PCAP_PKT_FILE keyword\n",
444 "    in ${confdir}/fwknop.conf.\n\n";
445
446                 if ($data_method eq 'file_pcap') {
447                     &put_string('AUTH_MODE', 'FILE_PCAP',
448                         "${confdir}/fwknop.conf");
449                 } else {
450                     &put_string('AUTH_MODE', 'ULOG_PCAP',
451                         "${confdir}/fwknop.conf");
452                 }
453             } else {
454                 my $intf = &get_pcap_intf();
455                 if ($intf) {
456                     &put_string('PCAP_INTF', $intf, "${confdir}/fwknop.conf");
457                 } else {
458 print "[-] Could not get sniffing interface, need to set this manually in\n",
459     "    {confdir}/fwknop.conf\n";
460                 }
461             }
462         } else {
463             ### it is a client-only install, so don't reconfigure syslog
464             ### or anything.
465         }
466
467         print "[+] Compiling knopmd and knopwatchd daemons:\n";
468
469         ### remove any previously compiled knopmd
470         unlink 'knopmd' if -e 'knopmd';
471
472         ### remove any previously compiled knopwatchd
473         unlink 'knopwatchd' if -e 'knopwatchd';
474
475         ### compile the C fwknop daemons
476         system $cmds{'make'};
477
478         unless (-e 'knopmd' and -e 'knopwatchd') {
479             die "[*] Compilation failed.";
480         }
481
482         ### install fwknop server-side daemons/programs
483         for my $daemon qw(fwknopd knopmd knopwatchd knoptm fwknop_serv) {
484             if ($daemon eq 'fwknopd' or $daemon eq 'knoptm') {
485                 unless (((system "$cmds{'perl'} -c $daemon")>>8) == 0) {
486                     die "[*] $daemon does not compile with \"perl -c\".  ",
487                         "Download the latest sources ",
488                         "from:\n\nhttp://www.cipherdyne.org/\n";
489                 }
490             }
491             print "[+] Copying $daemon -> $sbindir\n";
492             copy $daemon, $sbindir or
493                 die "[*] Could not cp $daemon to $sbindir: $!";
494             chmod 0500, "$sbindir/$daemon" or
495                 die "[*] Could not chmod 500 $sbindir/$daemon: $!";
496         }
497     }
498
499     print "[+] Copying fwknop -> $bindir\n";
500     copy 'fwknop', $bindir or
501         die "[*] Could not cp fwknop to $bindir: $!";
502
503     if ($client_install) {
504         open F, "< $bindir/fwknop" or die "[*] Could not open ",
505             "$bindir/fwknop: $!";
506         my @lines = <F>;
507         close F;
508         open P, "> $bindir/fwknop.tmp" or die "[*] Could not open ",
509             "$bindir/fwknop.tmp: $!";
510         for my $line (@lines) {
511             ### change the lib dir to new homedir path
512             if ($line =~ m|^\s*use\s+lib\s+\'/usr/lib/fwknop\';|) {
513                 print P "use lib '", $libdir, "';\n";
514             } else {
515                 print P $line;
516             }
517         }
518         close P;
519         move "$bindir/fwknop.tmp", "$bindir/fwknop" or die "[*] Could ",
520             "not move $bindir/fwknop.tmp -> $bindir/fwknop: $!";
521         chmod 0700, "$bindir/fwknop" or
522             die "[*] Could not chmod 755 $bindir/fwknop: $!";
523     } else {
524         chmod 0755, "$bindir/fwknop" or
525             die "[*] Could not chmod 755 $bindir/fwknop: $!";
526     }
527
528     unless (((system "$cmds{'perl'} -c $bindir/fwknop")>>8) == 0) {
529         die "[*] $bindir/fwknop does not compile with \"perl -c\".  ",
530             "Download the latest sources ",
531             "from:\n\nhttp://www.cipherdyne.org/\n";
532     }
533
534     unless ($client_install) {
535         unless ($preserve_rv) {
536             my $email_str = &query_email();
537             if ($email_str) {
538                 for my $file qw(fwknop.conf knopwatchd.conf) {
539                     &put_string('EMAIL_ADDRESSES', $email_str,
540                         "$confdir/$file");
541                 }
542             }
543         }
544
545         if (-d $initdir) {
546             print "[+] Copying init-scripts/$init_file -> ${initdir}/fwknop\n";
547             copy "init-scripts/$init_file", "${initdir}/fwknop"
548                 or die "[*] Could not cp fwknop init script to $initdir: $!";
549             &perms_ownership("${initdir}/fwknop", 0744);
550             &enable_fwknop_at_boot($distro) unless $data_method =~ /client/i;
551         }
552     }
553
554     if ($client_install) {
555         print
556 "\n[+] fwknop has been installed at $bindir/fwknop.  Since this is a\n",
557 "    client-only install, the man pages could not be installed.  For more\n",
558 "    information about how to use fwknop, execute \"$bindir/fwknop -h\" or\n",
559 "    refer to:\n\n",
560 "        http://www.cipherdyne.org/fwknop/manpage.html\n\n";
561     } else {
562         if ($data_method =~ /client/i) {
563             print "\n[+] fwknop has been installed!\n\n";
564         } else {
565             print
566 "\n[+] fwknop has been installed!  To start in server mode, run\n\n",
567 "    \"/etc/init.d/fwknop start\"\n\n",
568 "    Note: You will need to edit $confdir/access.conf for fwknop to\n",
569 "    function properly in server mode.  More information can be found in\n",
570 "    the fwknop manpage.\n\n";
571         }
572     }
573     return;
574 }
575
576 sub uninstall() {
577     ### FIXME: need to pid check to see if fwknop is still running
578     ### before we remove it.
579     print "[+] Uninstalling fwknop\n";
580
581     ### stop any running fwknop daemons.
582     &stop_fwknop();
583
584     unlink "$bindir/fwknop" if -e "$bindir/fwknop";
585     unlink "$sbindir/knopmd" if -e "$sbindir/knopmd";
586     unlink "$sbindir/knopwatchd" if -e "$sbindir/knopwatchd";
587     unlink "$initdir/fwknop" if -e "$initdir/fwknop";
588     rmtree $confdir, 1, 1 if -d $confdir;
589     rmtree $libdir, 1, 1 if -d $libdir;
590
591     return;
592 }
593
594 ### check paths to commands and attempt to correct if any are wrong.
595 sub check_commands() {
596     my @path = qw(
597         /bin
598         /sbin
599         /usr/bin
600         /usr/sbin
601         /usr/local/bin
602         /usr/local/sbin
603     );
604     CMD: for my $cmd (keys %cmds) {
605         unless (-x $cmds{$cmd}) {
606             my $found = 0;
607             PATH: for my $dir (@path) {
608                 if (-x "${dir}/${cmd}") {
609                     $cmds{$cmd} = "${dir}/${cmd}";
610                     $found = 1;
611                     last PATH;
612                 }
613             }
614             unless ($found) {
615                 die "[*] Could not find $cmd anywhere!!!  ",
616                     "Please edit the config section to include the path to ",
617                     "$cmd.\n";
618             }
619         }
620         unless (-x $cmds{$cmd}) {
621             die "[*] $cmd is located at ",
622                 "$cmds{$cmd} but is not executable by uid: $<\n";
623         }
624     }
625     return;
626 }
627
628 sub archive() {
629     my $file = shift;
630     return unless -e $file;
631     my $curr_pwd = cwd();
632     chdir $archivedir or die $!;
633     my ($filename) = ($file =~ m|.*/(.*)|);
634     my $base = "${filename}.old";
635     for (my $i = 5; $i > 1; $i--) {  ### keep five copies of old config files
636         my $j = $i - 1;
637         unlink "${base}${i}.gz" if -e "${base}${i}.gz";
638         move "${base}${j}.gz", "${base}${i}.gz" if -e "${base}${j}.gz";
639     }
640     print "[+] Archiving $file -> ${base}1\n";
641     unlink "${base}1.gz" if -e "${base}1.gz";
642     copy $file, "${base}1";   ### move $file into the archive directory
643     system "$cmds{'gzip'} ${base}1";
644     chdir $curr_pwd or die $!;
645     return;
646 }
647
648 sub preserve_config() {
649     my $file = shift;
650     open C, "< $file" or die "[*] Could not open $file: $!";
651     my @new_lines = <C>;
652     close C;
653
654     open CO, "< ${confdir}/$file" or die "[*] Could not open ",
655         "${confdir}/$file: $!";
656     my @orig_lines = <CO>;
657     close CO;
658
659     print "[+] Preserving existing config: ${confdir}/$file\n";
660     ### write to a tmp file and then move so any running fwknop daemon will
661     ### re-import a full config file if a HUP signal is received during
662     ### the install.
663     open CONF, "> ${confdir}/${file}.new" or die "[*] Could not open ",
664         "${confdir}/${file}.new: $!";
665     for my $new_line (@new_lines) {
666         if ($new_line =~ /^\s*#/) {
667             print CONF $new_line;  ### take comments from new file.
668         } elsif ($new_line =~ /^\s*(\S+)/) {
669             my $var = $1;
670             my $found = 0;
671             for my $orig_line (@orig_lines) {
672                 if ($orig_line =~ /^\s*$var\s/) {
673                     print CONF $orig_line;
674                     $found = 1;
675                     last;
676                 }
677             }
678             unless ($found) {
679                 print CONF $new_line;
680             }
681         } else {
682             print CONF $new_line;
683         }
684     }
685     close CONF;
686     move "${confdir}/${file}.new", "${confdir}/$file" or die "[*] ",
687         "Could not move ${confdir}/${file}.new -> ",
688         "${confdir}/$file: $!";
689     return;
690 }
691
692 sub append_fifo_syslog() {
693     print "[+] Modifying /etc/syslog.conf to write kern.info messages to\n";
694     print "    $fwknop_fifo\n";
695     unless (-e '/etc/syslog.conf.orig') {
696         copy '/etc/syslog.conf', '/etc/syslog.conf.orig';
697     }
698     &archive('/etc/syslog.conf');
699     open RS, '< /etc/syslog.conf' or
700         die "[*]  Unable to open /etc/syslog.conf: $!\n";
701     my @slines = <RS>;
702     close RS;
703     open SYSLOG, '> /etc/syslog.conf' or
704         die "[*]  Unable to open /etc/syslog.conf: $!\n";
705     for my $line (@slines) {
706         unless ($line =~ /fwknopfifo/) {
707             print SYSLOG $line;
708         }
709     }
710     ### reinstate kernel logging to our named pipe
711     print SYSLOG '### Send kern.info messages to fwknopfifo for ',
712         "analysis by knopmd\n",
713         "kern.info\t\t|$fwknop_fifo\n";
714     close SYSLOG;
715     return;
716 }
717
718 sub append_fifo_syslog_ng() {
719     print "[+] Modifying /etc/syslog-ng/syslog-ng.conf to write kern.info ",
720         "messages to\n";
721     print "    $fwknop_fifo\n";
722     unless (-e '/etc/syslog-ng/syslog-ng.conf.orig') {
723         copy '/etc/syslog-ng/syslog-ng.conf',
724             '/etc/syslog-ng/syslog-ng.conf.orig';
725     }
726     &archive('/etc/syslog-ng/syslog-ng.conf');
727     open RS, '< /etc/syslog-ng/syslog-ng.conf' or
728         die "[*]  Unable to open /etc/syslog-ng/syslog-ng.conf: $!\n";
729     my @slines = <RS>;
730     close RS;
731
732     my $found_fifo = 0;
733     for my $line (@slines) {
734         $found_fifo = 1 if ($line =~ /fwknopfifo/);
735     }
736
737     unless ($found_fifo) {
738         open SYSLOGNG, '>> /etc/syslog-ng/syslog-ng.conf' or
739             die "[*] Unable to open /etc/syslog-ng/syslog-ng.conf: $!\n";
740         print SYSLOGNG "\n",
741             "destination fwknoppipe { pipe(\"/var/lib/fwknop/fwknopfifo\"); };\n",
742             "filter f_kerninfo { facility(kern) and level(info); };\n",
743             "log { source(src); filter(f_kerninfo); destination(fwknoppipe); };\n";
744         close SYSLOGNG;
745     }
746