--- /dev/null
+import java.awt.*;
+import java.util.*;
+
+public class CbButton extends Canvas
+{
+ public static final int LEFT = 0;
+ public static final int RIGHT = 1;
+ public static final int ABOVE = 2;
+ public static final int BELOW = 3;
+
+ Image image;
+ String string;
+ CbButtonCallback callback;
+ int imode;
+ int iwidth, iheight, pwidth, pheight, twidth, theight;
+ boolean inside, indent;
+
+ CbButtonGroup group;
+ boolean selected;
+
+ Color lc1 = Util.light_edge, lc2 = Util.body, lc3 = Util.dark_edge;
+ Color hc1 = Util.light_edge_hi, hc2 = Util.body_hi, hc3 = Util.dark_edge_hi;
+
+ public CbButton(Image i, CbButtonCallback cb)
+ {
+ this(i, null, LEFT, cb);
+ }
+
+ public CbButton(String s, CbButtonCallback cb)
+ {
+ this(null, s, LEFT, cb);
+ }
+
+ public CbButton(Image i, String s, int im, CbButtonCallback cb)
+ {
+ image = i;
+ string = s;
+ imode = im;
+ callback = cb;
+ if (image != null) {
+ iwidth = Util.getWidth(image);
+ iheight = Util.getHeight(image);
+ }
+ if (string != null) {
+ twidth = Util.fnm.stringWidth(string);
+ theight = Util.fnm.getHeight();
+ }
+ if (image != null && string != null) {
+ switch(imode) {
+ case LEFT:
+ case RIGHT:
+ pwidth = iwidth + twidth + 6;
+ pheight = Math.max(iheight , theight) + 4;
+ break;
+ case ABOVE:
+ case BELOW:
+ pwidth = Math.max(iwidth, twidth) + 4;
+ pheight = iheight + theight + 6;
+ break;
+ }
+ }
+ else if (image != null) {
+ pwidth = iwidth + 4;
+ pheight = iheight + 4;
+ }
+ else if (string != null) {
+ pwidth = twidth + 8;
+ pheight = theight + 8;
+ }
+ }
+
+ /**Make this button part of a mutual-exclusion group. Only one such
+ * button can be indented at a time
+ */
+ public void setGroup(CbButtonGroup g)
+ {
+ group = g;
+ group.add(this);
+ }
+
+ /**Make this button the selected one in it's group
+ */
+ public void select()
+ {
+ if (group != null)
+ group.select(this);
+ }
+
+ /**Display the given string
+ */
+ public void setText(String s)
+ {
+ string = s;
+ image = null;
+ twidth = Util.fnm.stringWidth(string);
+ theight = Util.fnm.getHeight();
+ repaint();
+ }
+
+ /**Display the given image
+ */
+ public void setImage(Image i)
+ {
+ string = null;
+ image = i;
+ iwidth = Util.getWidth(image);
+ iheight = Util.getHeight(image);
+ repaint();
+ }
+
+ /**Display the given image and text, with the given alignment mode
+ */
+ public void setImageText(Image i, String s, int m)
+ {
+ image = i;
+ string = s;
+ imode = m;
+ twidth = Util.fnm.stringWidth(string);
+ theight = Util.fnm.getHeight();
+ iwidth = Util.getWidth(image);
+ iheight = Util.getHeight(image);
+ repaint();
+ }
+
+ public void paint(Graphics g)
+ {
+ Color c1 = inside ? hc1 : lc1,
+ c2 = inside ? hc2 : lc2,
+ c3 = inside ? hc3 : lc3;
+ int w = size().width, h = size().height;
+ Color hi = indent||selected ? c3 : c1,
+ lo = indent||selected ? c1 : c3;
+ g.setColor(c2);
+ g.fillRect(0, 0, w-1, h-1);
+ g.setColor(hi);
+ g.drawLine(0, 0, w-2, 0);
+ g.drawLine(0, 0, 0, h-2);
+ g.setColor(lo);
+ g.drawLine(w-1, h-1, w-1, 1);
+ g.drawLine(w-1, h-1, 1, h-1);
+ if (inside) {
+ /* g.setColor(hi);
+ g.drawLine(1, 1, w-3, 1);
+ g.drawLine(1, 1, 1, h-3); */
+ g.setColor(lo);
+ g.drawLine(w-2, h-2, w-2, 2);
+ g.drawLine(w-2, h-2, 2, h-2);
+ }
+
+ g.setColor(c3);
+ g.setFont(Util.f);
+ if (image != null && string != null) {
+ if (imode == LEFT) {
+ Dimension is = imgSize(w-twidth-6, h-4);
+ g.drawImage(image, (w - is.width - twidth - 2)/2,
+ (h-is.height)/2, is.width, is.height, this);
+ g.drawString(string,
+ (w - is.width - twidth - 2)/2 +is.width +2,
+ (h + theight - Util.fnm.getDescent())/2);
+ }
+ else if (imode == RIGHT) {
+ }
+ else if (imode == ABOVE) {
+ //Dimension is = imgSize(w-4, h-theight-6);
+ g.drawImage(image, (w - iwidth)/2,
+ (h - iheight - theight - 2)/2,
+ iwidth, iheight, this);
+ g.drawString(string, (w - twidth)/2, iheight+Util.fnm.getHeight()+2);
+ }
+ else if (imode == BELOW) {
+ }
+ }
+ else if (image != null) {
+ Dimension is = imgSize(w-4, h-4);
+ g.drawImage(image, (w - is.width)/2, (h-is.height)/2,
+ is.width, is.height, this);
+ }
+ else if (string != null) {
+ g.drawString(string, (w - twidth)/2,
+ (h+theight-Util.fnm.getDescent())/2);
+ }
+ }
+
+ public void update(Graphics g) { paint(g); }
+
+ public boolean mouseEnter(Event e, int x, int y)
+ {
+ inside = true;
+ repaint();
+ return true;
+ }
+
+ public boolean mouseExit(Event e, int x, int y)
+ {
+ inside = false;
+ repaint();
+ return true;
+ }
+
+ public boolean mouseDown(Event e, int x, int y)
+ {
+ indent = true;
+ repaint();
+ return true;
+ }
+
+ public boolean mouseUp(Event e, int x, int y)
+ {
+ if (x >= 0 && y >= 0 && x < size().width && y < size().height) {
+ if (callback != null)
+ callback.click(this);
+ select();
+ }
+ indent = false;
+ repaint();
+ return true;
+ }
+
+ public Dimension preferredSize()
+ {
+ return new Dimension(pwidth, pheight);
+ }
+
+ public Dimension minimumSize()
+ {
+ return preferredSize();
+ }
+
+ private Dimension imgSize(int mw, int mh)
+ {
+ float ws = (float)mw/(float)iwidth,
+ hs = (float)mh/(float)iheight;
+ float s = ws < hs ? ws : hs;
+ if (s > 1) s = 1;
+ return new Dimension((int)(iwidth*s), (int)(iheight*s));
+ }
+}
+
+
+interface CbButtonCallback
+{
+ void click(CbButton b);
+}
+
+
+class CbButtonGroup
+{
+ Vector buttons = new Vector();
+
+ void add(CbButton b)
+ {
+ buttons.addElement(b);
+ }
+
+ void select(CbButton b)
+ {
+ for(int i=0; i<buttons.size(); i++) {
+ CbButton but = (CbButton)buttons.elementAt(i);
+ but.selected = (b == but);
+ but.repaint();
+ }
+ }
+}
+
--- /dev/null
+// LineInputStream
+// A stream with some useful stdio-like methods. Can be used either for
+// inheriting those methods into your own input stream, or for adding them
+// to some input stream.
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.EOFException;
+
+public class LineInputStream
+{
+ InputStream in;
+
+ LineInputStream(InputStream i)
+ { in = i; }
+ LineInputStream()
+ { }
+
+ public int read() throws IOException
+ { return in.read(); }
+ public int read(byte b[]) throws IOException
+ { return in.read(b); }
+ public int read(byte b[], int o, int l) throws IOException
+ { return in.read(b, o, l); }
+ public long skip(long n) throws IOException
+ { return in.skip(n); }
+ public int available() throws IOException
+ { return in.available(); }
+ public void close() throws IOException
+ { in.close(); }
+ public synchronized void mark(int readlimit)
+ { in.mark(readlimit); }
+ public synchronized void reset() throws IOException
+ { in.reset(); }
+ public boolean markSupported()
+ { return in.markSupported(); }
+
+ // gets
+ // Read a line and return it (minus the \n)
+ String gets() throws IOException, EOFException
+ {
+ StringBuffer buf = new StringBuffer();
+ int b;
+ while((b = read()) != '\n') {
+ if (b == -1) throw new EOFException();
+ buf.append((char)b);
+ }
+ if (buf.length() != 0 && buf.charAt(buf.length()-1) == '\r')
+ buf.setLength(buf.length()-1); // lose \r
+ return buf.toString();
+ }
+
+ // getw
+ // Read a single word, surrounded by whitespace
+ String getw() throws IOException, EOFException
+ {
+ StringBuffer buf = new StringBuffer();
+ // skip spaces
+ int b;
+ do {
+ if ((b = read()) == -1) throw new EOFException();
+ } while(Character.isSpace((char)b));
+ // add characters
+ do {
+ buf.append((char)b);
+ if ((b = read()) == -1) throw new EOFException();
+ } while(!Character.isSpace((char)b));
+ return buf.toString();
+ }
+
+ // readdata
+ // Fill the given array completely, even if read() only reads
+ // some max number of bytes at a time.
+ public int readdata(byte b[]) throws IOException, EOFException
+ {
+ int p = 0;
+ while(p < b.length)
+ p += read(b, p, b.length-p);
+ return b.length;
+ }
+}
+
--- /dev/null
+import java.awt.*;
+import java.net.*;
+import java.io.*;
+import java.util.*;
+import java.applet.*;
+
+public class LogViewer extends Applet implements Runnable,CbButtonCallback
+{
+ TextArea log;
+ StringBuffer logbuffer = new StringBuffer();
+ LineInputStream is;
+ Thread th;
+ CbButton pause, button;
+ boolean paused = false;
+
+ public void init()
+ {
+ // Create the UI
+ setLayout(new BorderLayout());
+ add("Center", log = new TextArea());
+ log.setEditable(false);
+ Util.setFont(new Font("TimesRoman", Font.PLAIN, 12));
+ Panel bot = new Panel();
+ bot.setBackground(Color.white);
+ bot.setForeground(Color.white);
+ bot.setLayout(new FlowLayout(FlowLayout.RIGHT));
+ if (getParameter("pause") != null) {
+ // Add button to pause display
+ bot.add(pause = new CbButton(" Pause ", this));
+ }
+ if (getParameter("buttonname") != null) {
+ // Add button for some other purpose
+ bot.add(button = new CbButton(getParameter("buttonname"),this));
+ }
+ add("South", bot);
+ }
+
+ public void start()
+ {
+ // Start download thread
+ log.setText("");
+ th = new Thread(this);
+ th.start();
+ }
+
+ public void stop()
+ {
+ // Stop download
+ try {
+ String killurl = getParameter("killurl");
+ if (killurl != null) {
+ // Call this CGI at stop time
+ try {
+ URL u = new URL(getDocumentBase(), killurl);
+ URLConnection uc = u.openConnection();
+ String session = getParameter("session");
+ if (session != null)
+ uc.setRequestProperty("Cookie", session);
+ uc.getInputStream().close();
+ }
+ catch(Exception e2) { }
+ }
+ if (is != null) is.close();
+ if (th != null) th.stop();
+ }
+ catch(Exception e) {
+ // ignore it
+ e.printStackTrace();
+ }
+ }
+
+ public void run()
+ {
+ try {
+ URL u = new URL(getDocumentBase(), getParameter("url"));
+ URLConnection uc = u.openConnection();
+ String session = getParameter("session");
+ if (session != null)
+ uc.setRequestProperty("Cookie", session);
+ is = new LineInputStream(uc.getInputStream());
+ while(true) {
+ String l = is.gets();
+ append(l);
+ }
+ }
+ catch(EOFException e) {
+ // end of file ..
+ }
+ catch(IOException e) {
+ // shouldn't happen!
+ e.printStackTrace();
+ append("IO error : "+e.getMessage());
+ }
+ }
+
+ int len = 0, oldlen = 0;
+
+ void append(String str) {
+ if (!paused) {
+ log.append((len == 0 ? "" : "\n")+str);
+ }
+ logbuffer.append((len == 0 ? "" : "\n")+str);
+ oldlen = len;
+ len += str.length()+1;
+ if (!paused) {
+ log.select(oldlen, oldlen);
+ }
+ }
+
+ public void click(CbButton b) {
+ if (b == pause) {
+ if (paused) {
+ // Resume display, and append missing text
+ pause.setText(" Pause ");
+ log.setText(logbuffer.toString());
+ log.select(oldlen, oldlen);
+ } else {
+ // Stop display
+ pause.setText("Resume");
+ }
+ paused = !paused;
+ } else if (b == button) {
+ // Open some page
+ try {
+ URL u = new URL(getDocumentBase(),
+ getParameter("buttonlink"));
+ getAppletContext().showDocument(u);
+ }
+ catch(Exception e) { }
+ }
+ }
+}
+
--- /dev/null
+LogViewer.class: LogViewer.java
+ javac -target 1.2 -source 1.2 -classpath . *.java
--- /dev/null
+import java.awt.*;
+import java.awt.image.*;
+
+class Util
+{
+ static Frame fr;
+ static Graphics g;
+ static Font f;
+ static FontMetrics fnm;
+ static Toolkit tk;
+
+ static Color light_edge = Color.white;
+ static Color dark_edge = Color.black;
+ static Color body = Color.lightGray;
+ static Color body_hi = new Color(210, 210, 210);
+ static Color light_edge_hi = Color.white;
+ static Color dark_edge_hi = Color.darkGray;
+ static Color dark_bg = new Color(150, 150, 150);
+ static Color text = Color.black;
+ static Color light_bg = Color.white;
+
+ static
+ {
+ fr = new Frame();
+ fr.addNotify();
+ g = fr.getGraphics();
+ setFont(new Font("TimesRoman", Font.PLAIN, 8));
+ tk = Toolkit.getDefaultToolkit();
+ }
+
+ static boolean waitForImage(Image i)
+ {
+ MediaTracker mt = new MediaTracker(fr);
+ mt.addImage(i, 0);
+ try { mt.waitForAll(); } catch(Exception e) { return false; }
+ return !mt.isErrorAny();
+ }
+
+ static boolean waitForImage(Image i, int w, int h)
+ {
+ MediaTracker mt = new MediaTracker(fr);
+ mt.addImage(i, w, h, 0);
+ try { mt.waitForAll(); } catch(Exception e) { return false; }
+ return !mt.isErrorAny();
+ }
+
+ static int getWidth(Image i)
+ {
+ waitForImage(i);
+ return i.getWidth(fr);
+ }
+
+ static int getHeight(Image i)
+ {
+ waitForImage(i);
+ return i.getHeight(fr);
+ }
+
+ static Image createImage(int w, int h)
+ {
+ return fr.createImage(w, h);
+ }
+
+ static Image createImage(ImageProducer p)
+ {
+ return fr.createImage(p);
+ }
+
+ static Object createObject(String name)
+ {
+ try {
+ Class c = Class.forName(name);
+ return c.newInstance();
+ }
+ catch(Exception e) {
+ System.err.println("Failed to create object "+name+" : "+
+ e.getClass().getName());
+ System.exit(1);
+ }
+ return null;
+ }
+
+ /**Create a new instance of some object
+ */
+ static Object createObject(Object o)
+ {
+ try { return o.getClass().newInstance(); }
+ catch(Exception e) {
+ System.err.println("Failed to reproduce object "+o+" : "+
+ e.getClass().getName());
+ System.exit(1);
+ }
+ return null;
+ }
+
+
+ static void dottedRect(Graphics g, int x1, int y1,
+ int x2, int y2, int s)
+ {
+ int i, s2 = s*2, t;
+ if (x2 < x1) { t = x1; x1 = x2; x2 = t; }
+ if (y2 < y1) { t = y1; y1 = y2; y2 = t; }
+ for(i=x1; i<=x2; i+=s2)
+ g.drawLine(i, y1, i+s > x2 ? x2 : i+s, y1);
+ for(i=y1; i<=y2; i+=s2)
+ g.drawLine(x2, i, x2, i+s > y2 ? y2 : i+s);
+ for(i=x2; i>=x1; i-=s2)
+ g.drawLine(i, y2, i-s < x1 ? x1 : i-s, y2);
+ for(i=y2; i>=y1; i-=s2)
+ g.drawLine(x1, i, x1, i-s < y1 ? y1 : i-s);
+ }
+
+ static void recursiveLayout(Container c)
+ {
+ c.layout();
+ for(int i=0; i<c.countComponents(); i++) {
+ Component cc = c.getComponent(i);
+ if (cc instanceof Container)
+ recursiveLayout((Container)cc);
+ }
+ }
+
+ static void recursiveBackground(Component c, Color b)
+ {
+ if (c instanceof TextField || c instanceof Choice ||
+ c instanceof TextArea)
+ return; // leave these alone
+ c.setBackground(b);
+ if (c instanceof Container) {
+ Container cn = (Container)c;
+ for(int i=0; i<cn.countComponents(); i++)
+ recursiveBackground(cn.getComponent(i), b);
+ }
+ }
+
+ static void recursiveBody(Component c)
+ {
+ recursiveBackground(c, Util.body);
+ }
+
+ static void setFont(Font nf)
+ {
+ f = nf;
+ g.setFont(f);
+ fnm = g.getFontMetrics();
+ }
+}
+
--- /dev/null
+
+if (!defined($services_file)) {
+ do 'itsecur-lib.pl';
+ }
+
+# acl_security_form(&options)
+# Output HTML for editing security options for the acl module
+sub acl_security_form
+{
+# Work out which features can be edited and which can be read
+local (@edit, @read);
+if (defined($_[0]->{'edit'})) {
+ if ($_[0]->{'edit'}) {
+ @edit = @read = split(/\s+/, $_[0]->{'features'});
+ }
+ else {
+ @read = split(/\s+/, $_[0]->{'features'});
+ }
+ }
+else {
+ @edit = split(/\s+/, $_[0]->{'features'});
+ @read = split(/\s+/, $_[0]->{'rfeatures'});
+ }
+
+local $w;
+foreach $w ([ \@edit, "features", "all" ],
+ [ \@read, "rfeatures", "rall" ]) {
+ local %can = map { $_, 1 } @{$w->[0]};
+ print "<tr> <td valign=top><b>",$text{'acl_'.$w->[1]},
+ "</b></td> <td>\n";
+ printf "<input type=radio name=$w->[2] value=1 %s> %s\n",
+ $can{"*"} ? "checked" : "", $text{'acl_all'};
+ printf "<input type=radio name=$w->[2] value=0 %s> %s<br>\n",
+ $can{"*"} ? "" : "checked", $text{'acl_sel'};
+ printf "<select name=$w->[1] multiple size=%d>\n",
+ scalar(@opts);
+ foreach $o (@opts, 'apply', 'bootup') {
+ printf "<option value=%s %s>%s\n",
+ $o, $can{$o} ? "selected" : "",
+ $text{"acl_".$o} || $text{$o."_title"};
+ }
+ print "</select></td> </tr>\n";
+ }
+}
+
+# acl_security_save(&options)
+# Parse the form for security options for the acl module
+sub acl_security_save
+{
+$_[0]->{'features'} = $in{'all'} ? "*" :
+ join(" ", split(/\0/, $in{'features'}));
+$_[0]->{'rfeatures'} = $in{'rall'} ? "*" :
+ join(" ", split(/\0/, $in{'rfeatures'}));
+delete($_[0]->{'edit'});
+}
+
+1;
+
--- /dev/null
+#!/usr/bin/perl
+# apply.cgi
+# Apply the firewall configuration
+
+require './itsecur-lib.pl';
+&can_edit_error("apply");
+&ReadParse();
+&header($text{'apply_title'}, "",
+ undef, undef, undef, undef, &apply_button());
+print "<hr>\n";
+
+print "<p>$text{'apply_doing'}<br>\n";
+&enable_routing();
+$err = &apply_rules();
+if ($err) {
+ print &text('apply_failed', $err),"<p>\n";
+ }
+else {
+ print "$text{'apply_done'}<p>\n";
+ }
+
+print "<hr>\n";
+if ($in{'return'}) {
+ &footer($ENV{'HTTP_REFERER'}, $text{'apply_return'});
+ }
+else {
+ &footer("", $text{'index_return'});
+ }
+&remote_webmin_log("apply");
--- /dev/null
+#!/usr/bin/perl
+# apply.pl
+# Apply the firewall configuration
+
+$ENV{'WEBMIN_CONFIG'} ||= "/etc/webmin";
+$ENV{'WEBMIN_VAR'} ||= "/var/webmin";
+$no_acl_check++;
+if ($0 =~ /^(.*\/)[^\/]+$/) {
+ chdir($1);
+ }
+require './itsecur-lib.pl';
+$module_name eq 'itsecur-firewall' || die "Command must be run with full path";
+
+print "$text{'apply_doing'}\n";
+&enable_routing();
+$err = &apply_rules();
+if ($err) {
+ print &text('apply_failed', $err),"\n";
+ exit(1);
+ }
+else {
+ print "$text{'apply_done'}\n";
+ exit(0);
+ }
+
--- /dev/null
+#!/usr/bin/perl
+# authdownload.cgi
+# Just dump log security file as text
+
+require './itsecur-lib.pl';
+&can_use_error("logs");
+$log = $config{'authlog'} || &get_authlog_file();
+print "Content-type: text/plain\n\n";
+open(LOG, $log);
+while(<LOG>) {
+ print $_ if (!&is_log_line($_));
+ }
+close(LOG);
+
--- /dev/null
+#!/usr/bin/perl
+
+$trust_unknown_referers = 1;
+require './itsecur-lib.pl';
+&can_use_error("logs");
+&ReadParse();
+$| = 1;
+$SIG{'HUP'} = sub { print "got HUP!\n"; };
+$log = $config{'authlog'} || &get_authlog_file();
+print "Content-type: text/plain\n\n";
+
+# Get all the firewall log lines
+open(LOG, $log);
+while(<LOG>) {
+ push(@log, $_) if (!&is_log_line($_));
+ shift(@log) if (@log > 20);
+ }
+
+# Show the last 20, and keep tailing
+print @log;
+while(1) {
+ sleep(1);
+ $line = <LOG>;
+ print $line if ($line && !&is_log_line($line));
+ }
+
--- /dev/null
+#!/usr/bin/perl
+# Actually do a backup
+
+require './itsecur-lib.pl';
+&can_edit_error("backup");
+&error_setup($text{'backup_err'});
+&ReadParse();
+
+# Validate inputs
+if ($in{'dest_mode'} == 0) {
+ $file = &tempname();
+ }
+elsif ($in{'dest_mode'} == 1) {
+ $orig_dest = $in{'dest'};
+ if (-d $in{'dest'}) {
+ $in{'dest'} .= "/firewall.zip";
+ }
+ $in{'dest'} =~ /^(.*)\// || &error($text{'backup_edest'});
+ -d $1 || &error($text{'backup_edestdir'});
+ $file = $in{'dest'};
+ $done = &text('backup_done1', $file);
+ }
+elsif ($in{'dest_mode'} == 2) {
+ gethostbyname($in{'ftphost'}) || &error($text{'backup_eftphost'});
+ $in{'ftpfile'} =~ /^\/\S+/ || &error($text{'backup_eftpfile'});
+ $in{'ftpuser'} =~ /\S/ || &error($text{'backup_eftpuser'});
+ $file = "ftp://$in{'ftpuser'}:$in{'ftppass'}\@$in{'ftphost'}$in{'ftpfile'}";
+ $done = &text('backup_done2', $in{'ftphost'}, $in{'ftpfile'});
+ }
+elsif ($in{'dest_mode'} == 3) {
+ $in{'email'} =~ /^\S+\@\S+$/ || &error($text{'backup_eemail'});
+ $file = "mailto:$in{'email'}";
+ $done = &text('backup_done3', $in{'email'});
+ }
+if (!$in{'pass_def'}) {
+ $in{'pass'} || &error($text{'backup_epass'});
+ }
+@what = split(/\0/, $in{'what'});
+@what || &error($text{'backup_ewhat'});
+
+if (!$in{'save'}) {
+ # Create the tar file
+ $err = &backup_firewall(\@what, $file, $in{'pass_def'} ? undef
+ : $in{'pass'});
+ &error($err) if ($err);
+ }
+
+# Save settings
+$config{'backup_dest'} = $in{'dest_mode'} == 0 ? undef : $file;
+$config{'backup_what'} = join(" ", @what);
+$config{'backup_pass'} = $in{'pass_def'} ? undef : $in{'pass'};
+&write_file($module_config_file, \%config);
+
+if ($in{'save'}) {
+ # Tell the user about the cron job
+ &header($text{'backup_title'}, "",
+ undef, undef, undef, undef, &apply_button());
+ print "<hr>\n";
+
+ print "<p>",&text('backup_donesched'),"<p>\n";
+
+ print "<hr>\n";
+ &footer("", $text{'index_return'});
+ }
+elsif ($in{'dest_mode'} == 0) {
+ # Send to browser
+ print "Content-type: application/octet-stream\n\n";
+ open(FILE, $file);
+ while(<FILE>) {
+ print;
+ }
+ close(FILE);
+ unlink($file);
+ &remote_webmin_log("backup");
+ }
+else {
+ # Tell the user
+ &header($text{'backup_title'}, "",
+ undef, undef, undef, undef, &apply_button());
+ print "<hr>\n";
+
+ print "<p>$done<p>\n";
+
+ print "<hr>\n";
+ &footer("", $text{'index_return'});
+ &remote_webmin_log("backup", undef, $in{'dest'});
+ }
+
+# Setup cron job
+$job = &find_backup_job();
+if ($job) {
+ &cron::delete_cron_job($job);
+ }
+if (!$in{'sched_def'}) {
+ $job = { 'special' => $in{'sched'},
+ 'user' => 'root',
+ 'command' => $cron_cmd,
+ 'active' => 1 };
+ &cron::create_wrapper($cron_cmd, $module_name, "backup.pl");
+ &cron::create_cron_job($job);
+ }
+
--- /dev/null
+#!/usr/bin/perl
+# Do a backup on schedule
+
+$no_acl_check++;
+require './itsecur-lib.pl';
+
+$file = $config{'backup_dest'};
+if (-d $file) {
+ $file .= "/firewall.zip";
+ }
+@what = split(/\s+/, $config{'backup_what'});
+$pass = $config{'backup_pass'};
+
+if ($file) {
+ &backup_firewall(\@what, $file, $pass);
+ }
--- /dev/null
+#!/usr/bin/perl
+# bootup.cgi
+# Enable or disable iptables at boot time
+
+require './itsecur-lib.pl';
+&can_edit_error("bootup");
+&ReadParse();
+&foreign_require("init", "init-lib.pl");
+&foreign_require("cron", "cron-lib.pl");
+
+# Create the wrapper script
+$start_wrapper_script = "$module_config_directory/apply.pl";
+$stop_wrapper_script = "$module_config_directory/stop.pl";
+&cron::create_wrapper($start_wrapper_script, $module_name, "apply.pl");
+&cron::create_wrapper($stop_wrapper_script, $module_name, "stop.pl");
+
+if ($in{'boot'}) {
+ &init::enable_at_boot("itsecur-firewall",
+ "Start or stop the ITsecur firewall",
+ $start_wrapper_script,
+ $stop_wrapper_script);
+ &remote_webmin_log("bootup");
+ }
+else {
+ &init::disable_at_boot("itsecur-firewall");
+ &remote_webmin_log("bootdown");
+ }
+
+&redirect("");
+
--- /dev/null
+type=iptables
+what=rules services groups nat pat spoof
+fw_any=0
+rusure=1
+show_desc=1
+perpage=40
+add_files=0
+open_log=1
+frags=0
--- /dev/null
+type=ipf
+what=rules services groups nat pat spoof
+fw_any=0
+rusure=1
+show_desc=1
+perpage=40
+add_files=0
+open_log=1
+frags=0
--- /dev/null
+line1=Configurable options,11
+fw_any=Include firewall in <b>Any</b> destination?,1,1-Yes,0-No
+frags=Block fragmented packets?,1,1-Yes,0-No
+auto_dir=Automatic backup directory,3,None
+rusure=Ask for confirmation before saving rule?,1,1-Yes,0-No
+show_desc=Show rule descriptions?,1,1-Yes,0-No
+perpage=Logs to show per page,0,5
+refresh=Seconds between log view refreshes,3,Never
+all_files=Include rotated versions of log file,1,1-Yes,0-No
+from=From: address for emails,3,Automatic (webmin@hostname)
+open_log=Open logs in new window?,1,1-Yes,0-No
+line2=System configuration,11
+type=Firewall type,1,iptables-IPtables,ipf-IPF
+log=Firewall log file,3,Automatic based on firewall type
+authlog=Security log file,3,Automatic based on OS
--- /dev/null
+ OLD @NET23
+ NET NET2
+ NET ARRAY(0x87a4b98)
+ NET ARRAY(0x87a09e4)
+ NET ARRAY(0x8429fc8)
--- /dev/null
+features=*
+rfeatures=*
--- /dev/null
+#!/usr/bin/perl
+# down.cgi
+# Move a rule down
+
+require './itsecur-lib.pl';
+&can_edit_error("rules");
+&ReadParse();
+&lock_itsecur_files();
+@rules = &list_rules();
+($rules[$in{'idx'}], $rules[$in{'idx'}+1]) =
+ ($rules[$in{'idx'}+1], $rules[$in{'idx'}]);
+&save_rules(@rules);
+&unlock_itsecur_files();
+&remote_webmin_log("move", "rule", $in{'idx'}+1, $rules[$in{'idx'}]);
+&redirect("list_rules.cgi");
+
--- /dev/null
+#!/usr/bin/perl
+# download.cgi
+# Just dump log file as text
+
+require './itsecur-lib.pl';
+&can_use_error("logs");
+$log = $config{'log'} || &get_log_file();
+print "Content-type: text/plain\n\n";
+open(LOG, $log);
+while(<LOG>) {
+ print $_ if (&is_log_line($_));
+ }
+close(LOG);
+
--- /dev/null
+#!/usr/bin/perl
+# edit_group.cgi
+# Show a form for editing or creating a group of hosts or nets
+
+require './itsecur-lib.pl';
+&can_use_error("groups");
+&ReadParse();
+if ($in{'new'}) {
+ &header($text{'group_title1'}, "",
+ undef, undef, undef, undef, &apply_button());
+ }
+else {
+ &header($text{'group_title2'}, "",
+ undef, undef, undef, undef, &apply_button());
+ @groups = &list_groups();
+ if (defined($in{'idx'})) {
+ $group = $groups[$in{'idx'}];
+ }
+ else {
+ ($group) = grep { $_->{'name'} eq $in{'name'} } @groups;
+ $in{'idx'} = $group->{'index'};
+ }
+ }
+print "<hr>\n";
+
+print "<form action=save_group.cgi>\n";
+print "<input type=hidden name=new value='$in{'new'}'>\n";
+print "<input type=hidden name=idx value='$in{'idx'}'>\n";
+print "<input type=hidden name=from value='$in{'from'}'>\n";
+print "<table border>\n";
+print "<tr $tb> <td><b>$text{'group_header'}</b></td> </tr>\n";
+print "<tr $cb> <td><table>\n";
+
+print "<tr> <td><b>$text{'group_name'}</b></td>\n";
+printf "<td><input name=name size=20 value='%s'></td> </tr>\n",
+ $group->{'name'};
+
+print "<tr> <td valign=top><b>$text{'group_members'}</b></td>\n";
+print "<td><table>\n";
+$i = 0;
+foreach $m (( grep { !/\!?\@/ } @{$group->{'members'}} ),
+ $blank, $blank, $blank, $blank, $blank, $blank) {
+ $neg = ($m =~ s/^\!//);
+ print "<input name=member_$i size=40 value='$m'>\n";
+ print "<input type=checkbox name=neg_$i value=! ",
+ $neg ? "checked" : "","> $text{'group_neg'}<br>\n";
+ $i++;
+ }
+print "</table>\n";
+print "<input type=checkbox name=resolv value=1> $text{'group_resolv'}\n";
+print "</td> </tr>\n";
+
+# Show member groups
+print "<tr> <td valign=top><b>$text{'group_members2'}</b></td>\n";
+print "<td><table>\n";
+$i = 0;
+foreach $m (( grep { /\!?\@/ } @{$group->{'members'}} ),
+ $blank, $blank, $blank, $blank, $blank, $blank) {
+ $neg = ($m =~ s/^\!//);
+ $m =~ s/^\@//;
+ print "<tr> <td>\n";
+ print &group_input("group_$i", $m, 1);
+ print "</td> </tr>\n";
+ $i++;
+ }
+print "</table></td> </tr>\n";
+
+print "</table></td></tr></table>\n";
+if ($in{'new'}) {
+ print "<input type=submit value='$text{'create'}'>\n";
+ }
+else {
+ print "<input type=submit value='$text{'save'}'>\n";
+ print "<input type=submit name=delete value='$text{'delete'}'>\n";
+ }
+print "</form>\n";
+&can_edit_disable("groups");
+
+print "<hr>\n";
+$from = $in{'from'} || "groups";
+&footer("list_${from}.cgi", $text{$from.'_return'});
+
--- /dev/null
+#!/usr/bin/perl
+# edit_rule.cgi
+# Show a form for editing or creating a rule
+
+require './itsecur-lib.pl';
+&can_use_error("rules");
+&ReadParse();
+@rules = &list_rules();
+if ($in{'new'}) {
+ &header(defined($in{'insert'}) ? $text{'rule_title3'}
+ : $text{'rule_title1'}, "",
+ undef, undef, undef, undef, &apply_button());
+ $rule = { 'enabled' => 1,
+ 'action' => &default_action(),
+ 'service' => '',
+ 'source' => '',
+ 'dest' => '',
+ 'time' => '*',
+ 'index' => scalar(@rules) };
+ }
+else {
+ &header($text{'rule_title2'}, "",
+ undef, undef, undef, undef, &apply_button());
+ $rule = $rules[$in{'idx'}];
+ }
+print "<hr>\n";
+
+print "<form action=save_rule.cgi>\n";
+print "<input type=hidden name=new value='$in{'new'}'>\n";
+print "<input type=hidden name=idx value='$in{'idx'}'>\n";
+print "<input type=hidden name=insert value='$in{'insert'}'>\n";
+print "<table border>\n";
+print "<tr $tb> <td><b>$text{'rule_header'}</b></td> </tr>\n";
+print "<tr $cb> <td><table>\n";
+
+# Show comment
+print "<tr> <td valign=top><b>$text{'rule_desc'}</b></td> <td colspan=2>\n";
+printf "<input name=desc size=60 value='%s'></td> </tr>\n",
+ $rule->{'desc'} eq "*" ? "" : $rule->{'desc'};
+
+# Show source and destination
+foreach $s ('source', 'dest') {
+ $not = ($rule->{$s} =~ s/^!//g);
+ $sm = $rule->{$s} eq '*' ? 0 :
+ $rule->{$s} =~ /^\@/ ? 2 :
+ $rule->{$s} =~ /^\%/ ? 3 : 1;
+
+ # Any address options
+ print "<tr> <td valign=top><b>",$text{'rule_'.$s},
+ "</b></td> <td colspan=2>\n";
+ print "<table>\n";
+ print "<tr><td colspan=2>";
+ printf "<input type=radio name=${s}_mode value=0 %s> %s\n",
+ $sm == 0 ? "checked" : "",
+ $text{'rule_anywhere'};
+ print "</td></tr>\n";
+
+ # Specific host option
+ print "<tr><td valign=top>";
+ printf "<input type=radio name=${s}_mode value=1 %s> %s\n",
+ $sm == 1 ? "checked" : "", $text{'rule_host'};
+ print "</td><td>";
+ printf "<input name=${s}_host size=30 value='%s'>\n",
+ $sm == 1 ? $rule->{$s} : "";
+ print "$text{'rule_named'}\n";
+ print "<input name=${s}_name size=15><br>\n";
+ print "<input type=checkbox name=${s}_resolv value=1> ",
+ "$text{'rule_resolv'}\n";
+ print "</td></tr>\n";
+
+ # Host group option
+ local $gv;
+ if ($rule->{$s} =~ /^\@(.*)$/) {
+ $gv = $rule->{$s};
+ $gv =~ s/(^|\s)@/$1/g;
+ }
+ $gi = &group_input("${s}_group", $gv, 0, 1);
+ if ($gi || $sm == 2) {
+ print "<tr><td valign=top>";
+ printf "<input type=radio name=${s}_mode value=2 %s> %s\n",
+ $sm == 2 ? "checked" : "", $text{'rule_group'};
+ print "</td><td>";
+ print $gi;
+ print "</td></tr>\n";
+ }
+
+ # Interface option
+ $ii = &iface_input("${s}_iface",
+ $rule->{$s} =~ /^\%(.*)$/ ? $1 : undef);
+ if ($ii || $sm == 3) {
+ print "<tr><td>";
+ printf "<input type=radio name=${s}_mode value=3 %s> %s\n",
+ $sm == 3 ? "checked" : "", $text{'rule_iface'};
+ print "</td><td>";
+ print $ii;
+ print "</td></tr>\n";
+ }
+
+ print "</table>\n";
+ print "</td> <td valign=top>\n";
+ #printf "<input type=checkbox name=${s}_not value=1 %s> %s\n",
+ # $not ? "checked" : "", $text{'rule_not'};
+ print "</td> </tr>\n";
+ }
+
+# Show service
+$not = ($rule->{'service'} =~ s/^!//g);
+print "<tr> <td valign=top><b>$text{'rule_service'}</b></td> <td>\n";
+printf "<input type=radio name=service_mode value=0 %s> %s\n",
+ $rule->{'service'} eq '*' ? "checked" : "", $text{'rule_anyserv'};
+printf "<input type=radio name=service_mode value=1 %s> %s<br>\n",
+ $rule->{'service'} eq '*' ? "" : "checked", $text{'rule_oneserv'};
+print &service_input("service",
+ $rule->{'service'} eq '*' ? undef : $rule->{'service'},
+ 0, 1);
+print "</td> <td valign=top>\n";
+#printf "<input type=checkbox name=snot value=1 %s> %s\n",
+# $not ? "checked" : "", $text{'rule_not'};
+print "</td> </tr>\n";
+
+# Show action upon match
+print "<tr> <td valign=top><b>$text{'rule_action'}</b></td> <td>\n";
+print &action_input("action", $rule->{'action'});
+print "</td> <td>\n";
+printf "<input type=checkbox name=log value=1 %s> %s\n",
+ $rule->{'log'} ? 'checked' : '', $text{'rule_log'};
+print "</td> </tr>\n";
+
+# Show time that this rule applies
+$inp = &time_input("time", $rule->{'time'} eq "*" ? undef : $rule->{'time'});
+if ($inp) {
+ print "<tr> <td valign=top><b>$text{'rule_time'}</b></td> <td>";
+ printf "<input type=radio name=time_def value=1 %s> %s\n",
+ $rule->{'time'} eq "*" ? "checked" : "", $text{'rule_anytime'};
+ printf "<input type=radio name=time_def value=0 %s> %s\n",
+ $rule->{'time'} eq "*" ? "" : "checked", $text{'rule_seltime'};
+ print $inp;
+ print "</td> </tr>\n";
+ }
+else {
+ print "<input type=hidden name=time_def value=1>\n";
+ }
+
+# Show enabled flag
+print "<tr> <td valign=top><b>$text{'rule_enabled'}</b></td> <td>\n";
+printf "<input type=radio name=enabled value=1 %s> %s\n",
+ $rule->{'enabled'} ? "checked" : "", $text{'yes'};
+printf "<input type=radio name=enabled value=0 %s> %s\n",
+ $rule->{'enabled'} ? "" : "checked", $text{'no'};
+print "</td> </tr>\n";
+
+# Show input for position of rule
+print "<tr> <td><b>$text{'rule_atpos'}</b></td> <td>\n";
+print "<select name=pos>\n";
+foreach $br (@rules) {
+ next if ($br eq $rule);
+ if ($br->{'sep'}) {
+ printf "<option value=%s %s>%s\n",
+ $br->{'index'},
+ !$in{'new'} &&
+ $rule->{'index'} == $br->{'index'}-1 ? "selected" : "",
+ &text('rule_spos', $br->{'desc'});
+ }
+ else {
+ printf "<option value=%s %s>%s\n",
+ $br->{'index'},
+ !$in{'new'} &&
+ $rule->{'index'} == $br->{'index'}-1 ? "selected" : "",
+ &text('rule_pos', $br->{'num'},
+ &group_name($br->{'source'}),
+ &group_name($br->{'dest'}));
+ }
+ }
+printf "<option value=%s %s>%s\n",
+ -1, $in{'new'} || $rule eq $rules[$#rules] ? "selected" : "",
+ $text{'rule_end'};
+print "</select></td> </tr>\n";
+
+print "</table></td></tr></table>\n";
+if ($in{'new'}) {
+ print "<input type=submit value='$text{'create'}'>\n";
+ }
+else {
+ print "<input type=submit value='$text{'save'}'>\n";
+ print "<input type=submit name=delete value='$text{'delete'}'>\n";
+ }
+print "</form>\n";
+&can_edit_disable("rules");
+
+print "<hr>\n";
+&footer("list_rules.cgi", $text{'rules_return'});
+
--- /dev/null
+#!/usr/bin/perl
+# Show a form for editing or creating a rule list section separator
+
+require './itsecur-lib.pl';
+&can_use_error("rules");
+&ReadParse();
+@rules = &list_rules();
+if ($in{'new'}) {
+ &header(defined($in{'insert'}) ? $text{'sep_title3'}
+ : $text{'sep_title1'}, "",
+ undef, undef, undef, undef, &apply_button());
+ $rule = { 'index' => scalar(@rules) };
+ }
+else {
+ &header($text{'sep_title2'}, "",
+ undef, undef, undef, undef, &apply_button());
+ $rule = $rules[$in{'idx'}];
+ }
+print "<hr>\n";
+
+print "<form action=save_sep.cgi>\n";
+print "<input type=hidden name=new value='$in{'new'}'>\n";
+print "<input type=hidden name=idx value='$in{'idx'}'>\n";
+print "<input type=hidden name=insert value='$in{'insert'}'>\n";
+print "<table border>\n";
+print "<tr $tb> <td><b>$text{'sep_header'}</b></td> </tr>\n";
+print "<tr $cb> <td><table>\n";
+
+# Show separator title
+print "<tr> <td valign=top><b>$text{'sep_desc'}</b></td> <td>\n";
+printf "<input name=desc size=60 value='%s'></td> </tr>\n",
+ $rule->{'desc'} eq "*" ? "" : $rule->{'desc'};
+
+# Show input for position of rule
+print "<tr> <td><b>$text{'rule_atpos'}</b></td> <td>\n";
+print "<select name=pos>\n";
+foreach $br (@rules) {
+ next if ($br eq $rule);
+ if ($br->{'sep'}) {
+ printf "<option value=%s %s>%s\n",
+ $br->{'index'},
+ !$in{'new'} &&
+ $rule->{'index'} == $br->{'index'}-1 ? "selected" : "",
+ &text('rule_spos', $br->{'desc'});
+ }
+ else {
+ printf "<option value=%s %s>%s\n",
+ $br->{'index'},
+ !$in{'new'} &&
+ $rule->{'index'} == $br->{'index'}-1 ? "selected" : "",
+ &text('rule_pos', $br->{'num'},
+ &group_name($br->{'source'}),
+ &group_name($br->{'dest'}));
+ }
+ }
+printf "<option value=%s %s>%s\n",
+ -1, $in{'new'} || $rule eq $rules[$#rules] ? "selected" : "",
+ $text{'rule_end'};
+print "</select></td> </tr>\n";
+
+print "</table></td></tr></table>\n";
+if ($in{'new'}) {
+ print "<input type=submit value='$text{'create'}'>\n";
+ }
+else {
+ print "<input type=submit value='$text{'save'}'>\n";
+ print "<input type=submit name=delete value='$text{'delete'}'>\n";
+ }
+print "</form>\n";
+&can_edit_disable("rules");
+
+print "<hr>\n";
+&footer("list_rules.cgi", $text{'rules_return'});
+
--- /dev/null
+#!/usr/bin/perl
+# edit_service.cgi
+# Show a form for editing or creating a user-defined
+
+require './itsecur-lib.pl';
+&can_use_error("services");
+&ReadParse();
+if ($in{'new'}) {
+ &header($text{'service_title1'}, "",
+ undef, undef, undef, undef, &apply_button());
+ }
+else {
+ &header($text{'service_title2'}, "",
+ undef, undef, undef, undef, &apply_button());
+ @services = &list_services();
+ #$service = $services[$in{'idx'}];
+ if (defined($in{'idx'})) {
+ $service = $services[$in{'idx'}];
+ }
+ else {
+ ($service) = grep { $_->{'name'} eq $in{'name'} } @services;
+ $in{'idx'} = $services->{'index'};
+ }
+ }
+print "<hr>\n";
+
+print "<form action=save_service.cgi>\n";
+print "<input type=hidden name=new value='$in{'new'}'>\n";
+print "<input type=hidden name=idx value='$in{'idx'}'>\n";
+print "<table border>\n";
+print "<tr $tb> <td><b>$text{'service_header'}</b></td> </tr>\n";
+print "<tr $cb> <td><table>\n";
+
+# Show service name input
+print "<tr> <td><b>$text{'service_name'}</b></td>\n";
+printf "<td><input name=name size=20 value='%s'></td> </tr>\n",
+ $service->{'name'};
+
+# Show protocols and ports
+print "<tr> <td valign=top><b>$text{'service_ports'}</b></td>\n";
+print "<td><table border>\n";
+print "<tr $tb> <td><b>$text{'service_proto'}</b></td> ",
+ "<td><b>$text{'service_port'}</b></td> </tr>\n";
+for($i=0; $i<@{$service->{'protos'}}+6; $i++) {
+ print "<tr>\n";
+ print "<td>",&protocol_input(
+ "proto_$i", $service->{'protos'}->[$i]),"</td>\n";
+ printf "<td><input name=port_%d size=20 value='%s'></td>\n",
+ $i, $service->{'ports'}->[$i];
+ print "</tr>\n";
+ }
+print "</table></td> </tr>\n";
+
+# Show member services
+print "<tr> <td valign=top><b>$text{'service_members'}</b></td>\n";
+print "<td>",&service_input("others",
+ join(",", @{$service->{'others'}}), 0, 1),"</td> </tr>\n";
+
+print "</table></td></tr></table>\n";
+if ($in{'new'}) {
+ print "<input type=submit value='$text{'create'}'>\n";
+ }
+else {
+ print "<input type=submit value='$text{'save'}'>\n";
+ print "<input type=submit name=delete value='$text{'delete'}'>\n";
+ }
+print "</form>\n";
+&can_edit_disable("services");
+
+print "<hr>\n";
+&footer("list_services.cgi", $text{'services_return'});
+
+
--- /dev/null
+#!/usr/bin/perl
+# edit_time.cgi
+# Show a form for editing or creating a time range
+
+require './itsecur-lib.pl';
+&can_use_error("times");
+&ReadParse();
+if ($in{'new'}) {
+ &header($text{'time_title1'}, "",
+ undef, undef, undef, undef, &apply_button());
+ $time = { 'hours' => '*',
+ 'days' => '*' };
+ }
+else {
+ &header($text{'time_title2'}, "",
+ undef, undef, undef, undef, &apply_button());
+ @times = &list_times();
+ if (defined($in{'idx'})) {
+ $time = $times[$in{'idx'}];
+ }
+ else {
+ ($time) = grep { $_->{'name'} eq $in{'name'} } @times;
+ $in{'idx'} = $time->{'index'};
+ }
+ }
+print "<hr>\n";
+
+print "<form action=save_time.cgi>\n";
+print "<input type=hidden name=new value='$in{'new'}'>\n";
+print "<input type=hidden name=idx value='$in{'idx'}'>\n";
+print "<table border>\n";
+print "<tr $tb> <td><b>$text{'time_header'}</b></td> </tr>\n";
+print "<tr $cb> <td><table>\n";
+
+# Show range name
+print "<tr> <td><b>$text{'time_name'}</b></td>\n";
+printf "<td><input name=name size=20 value='%s'></td> </tr>\n",
+ $time->{'name'};
+
+# Show hour range
+print "<tr> <td><b>$text{'time_hours'}</b></td> <td>\n";
+printf "<input type=radio name=hours_def value=1 %s> %s\n",
+ $time->{'hours'} eq "*" ? "checked" : "", $text{'time_allday'};
+printf "<input type=radio name=hours_def value=0 %s>\n",
+ $time->{'hours'} eq "*" ? "" : "checked";
+($from, $to) = $time->{'hours'} eq "*" ? ( ) : split(/\-/, $time->{'hours'});
+printf "%s <input name=from size=6 value='%s'>\n",
+ $text{'time_from'}, $from;
+printf "%s <input name=to size=6 value='%s'></td> </tr>\n",
+ $text{'time_to'}, $to;
+
+# Show days of week
+print "<tr> <td valign=top><b>$text{'time_days'}</b></td> <td>\n";
+printf "<input type=radio name=days_def value=1 %s> %s\n",
+ $time->{'days'} eq "*" ? "checked" : "", $text{'time_allweek'};
+printf "<input type=radio name=days_def value=0 %s> %s<br>\n",
+ $time->{'days'} eq "*" ? "" : "checked", $text{'time_sel'};
+%days = map { $_, 1 } split(/,/, $time->{'days'});
+print "<select name=days size=7 multiple>\n";
+for($i=0; $i<7; $i++) {
+ printf "<option value=%s %s>%s\n",
+ $i, $days{$i} ? "selected" : "", $text{'day_'.$i};
+ }
+print "</select></td> </tr>\n";
+
+print "</table></td></tr></table>\n";
+if ($in{'new'}) {
+ print "<input type=submit value='$text{'create'}'>\n";
+ }
+else {
+ print "<input type=submit value='$text{'save'}'>\n";
+ print "<input type=submit name=delete value='$text{'delete'}'>\n";
+ }
+print "</form>\n";
+&can_edit_disable("times");
+
+print "<hr>\n";
+&footer("list_times.cgi", $text{'times_return'});
+
--- /dev/null
+#!/usr/bin/perl
+# edit_user.cgi
+# Show one Webmin user
+
+require './itsecur-lib.pl';
+&foreign_require("acl", "acl-lib.pl");
+&can_use_error("users");
+@users = &acl::list_users();
+&ReadParse();
+
+if ($in{'new'}) {
+ &header($text{'user_title1'}, "",
+ undef, undef, undef, undef, &apply_button());
+ %gotmods = ( $module_name, 1 );
+ }
+else {
+ &header($text{'user_title2'}, "",
+ undef, undef, undef, undef, &apply_button());
+ ($user) = grep { $_->{'name'} eq $in{'name'} } @users;
+ %gotmods = map { $_, 1 } @{$user->{'modules'}};
+ }
+print "<hr>\n";
+
+print "<form action=save_user.cgi>\n";
+print "<input type=hidden name=new value='$in{'new'}'>\n";
+print "<input type=hidden name=old value='$in{'name'}'>\n";
+print "<table border>\n";
+print "<tr $tb> <td><b>$text{'user_header'}</b></td> </tr>\n";
+print "<tr $cb> <td><table>\n";
+
+# Show username
+print "<tr> <td nowrap><b>$text{'user_name'}</b></td> <td>\n";
+printf "<input name=name size=20 value='%s'></td> </tr>\n",
+ $user->{'name'};
+
+# Show password
+print "<tr> <td nowrap><b>$text{'user_pass'}</b></td> <td>\n";
+if (!$in{'new'}) {
+ print "<input type=radio name=same value=1 checked> ",
+ "$text{'user_same'}\n";
+ print "<input type=radio name=same value=0> ",
+ "$text{'user_change'}\n";
+ }
+print "<input name=pass type=password size=20></td> </tr>\n";
+
+# Show enabled flag
+print "<tr> <td nowrap><b>$text{'user_enabled'}</b></td> <td>\n";
+printf "<input type=radio name=enabled value=1 %s> %s\n",
+ $user->{'pass'} =~ /^\*LK\*/ ? "" : "checked", $text{'yes'};
+printf "<input type=radio name=enabled value=0 %s> %s</td> </tr>\n",
+ $user->{'pass'} =~ /^\*LK\*/ ? "checked" : "", $text{'no'};
+
+# Show allowed IPS
+print "<tr> <td valign=top nowrap><b>$acl::text{'edit_ips'}</b></td>\n";
+print "<td><table><tr>\n";
+printf "<td nowrap><input name=ipmode type=radio value=0 %s> %s<br>\n",
+ $user->{'allow'} || $user->{'deny'} ? '' : 'checked',
+ $acl::text{'edit_all'};
+printf "<input name=ipmode type=radio value=1 %s> %s<br>\n",
+ $user->{'allow'} ? 'checked' : '', $acl::text{'edit_allow'};
+printf "<input name=ipmode type=radio value=2 %s> %s</td> <td>\n",
+ $user->{'deny'} ? 'checked' : '', $acl::text{'edit_deny'};
+print "<textarea name=ips rows=4 cols=30>",
+ join("\n", split(/\s+/, $user->{'allow'} ? $user->{'allow'}
+ : $user->{'deny'})),
+ "</textarea></td>\n";
+print "</tr></table></td> </tr>\n";
+
+# Show allowed modules (from list for *this* user)
+print "<tr> <td valign=top nowrap><b>$text{'user_mods'}</b></td>\n";
+&read_acl(\%acl);
+@mymods = grep { $acl{$base_remote_user,$_->{'dir'}} } &get_all_module_infos();
+print "<td><select name=mods size=5 multiple>\n";
+foreach $m (sort { $a->{'desc'} cmp $b->{'desc'} } @mymods) {
+ printf "<option value=%s %s>%s\n",
+ $m->{'dir'}, $gotmods{$m->{'dir'}} ? "selected" : "",
+ $m->{'desc'};
+ }
+print "</select></td> </tr>\n";
+
+# Show access control
+print "<tr> <td colspan=2><hr></td> </tr>\n";
+require "./acl_security.pl";
+if ($in{'new'}) {
+ %uaccess = ( 'features' => 'rules services groups nat pat spoof logs apply',
+ 'rfeatures' => 'rules services groups nat pat spoof logs apply',
+ 'edit' => 1 );
+ }
+else {
+ %uaccess = &get_module_acl($user->{'name'});
+ }
+&acl_security_form(\%uaccess);
+
+print "</table></td></tr></table>\n";
+if ($in{'new'}) {
+ print "<input type=submit value='$text{'create'}'>\n";
+ }
+else {
+ print "<input type=submit value='$text{'save'}'>\n";
+ print "<input type=submit name=delete value='$text{'delete'}'>\n";
+ }
+print "</form>\n";
+&can_edit_disable("users");
+
+print "<hr>\n";
+&footer("list_users.cgi", $text{'users_return'});
+
--- /dev/null
+#!/usr/bin/perl
+# Enable, disable, log, un-log or delete a bunch of rules
+
+require './itsecur-lib.pl';
+&can_edit_error("rules");
+&ReadParse();
+@rules = &list_rules();
+@nums = split(/\0/, $in{'r'});
+
+&lock_itsecur_files();
+foreach $n (@nums) {
+ ($r) = grep { $_->{'index'} == $n } @rules;
+ if ($in{'enable'}) {
+ $r->{'enabled'} = 1;
+ }
+ elsif ($in{'disable'}) {
+ $r->{'enabled'} = 0;
+ }
+ elsif ($in{'logon'}) {
+ $r->{'log'} = 1;
+ }
+ elsif ($in{'logoff'}) {
+ $r->{'log'} = 0;
+ }
+ elsif ($in{'delete'}) {
+ @rules = grep { $_ ne $r } @rules;
+ }
+ }
+
+&automatic_backup();
+&save_rules(@rules);
+&unlock_itsecur_files();
+&remote_webmin_log($in{'enable'} ? "enable" :
+ $in{'disable'} ? "disable" :
+ $in{'logon'} ? "logon" :
+ $in{'logoff'} ? "logoff" : "delete", "rules", undef,
+ { 'count' => scalar(@nums) } );
+&redirect("list_rules.cgi");
+
--- /dev/null
+#!/usr/bin/perl
+# Actually do an import of host groups
+
+require './itsecur-lib.pl';
+&can_edit_error("import");
+&error_setup($text{'import_err'});
+&ReadParseMime();
+
+# Validate inputs
+if (!$in{'src_def'}) {
+ -r $in{'src'} || &error_cleanup($text{'restore_esrc'});
+ $data = `cat $in{'src'}`;
+ }
+else {
+ $in{'file'} || &error_cleanup($text{'restore_efile'});
+ $data = $in{'file'};
+ }
+
+%groups = map { $_->{'name'}, $_ } &list_groups();
+
+# Parse the CSV data
+$data =~ s/\r//g;
+$i = 0;
+foreach $line (split(/\n/, $data)) {
+ # Split into columns
+ $oldline = $line;
+ $i++;
+ next if (!$line);
+ local @row;
+ while($line && $line =~ /^,?("([^"]*)"|([^,]*))(.*)$/) {
+ push(@row, $2 || $3);
+ $line = $4;
+ }
+ @row >= 1 || &error(&text('import_erow', $i, $oldline));
+
+ # Create a service
+ $row[0] =~ /\S/ || &error(text('import_egroupname', $i));
+ $groups{$row[0]} && &error(text('import_egroupclash', $i, $row[0]));
+ $group = { 'name' => $row[0] };
+ if (@row == 1) {
+ # Group name is the host name
+ &valid_host($row[0]) ||
+ &error(text('import_ehost', $i, $row[0]));
+ $group->{'members'} = [ $row[0] ];
+ }
+ else {
+ # Hosts are listed
+ for($i=1; $i<@row; $i++) {
+ &valid_host($row[$i]) ||
+ &error(text('import_ehost', $i, $row[$i]));
+ push(@{$group->{'members'}}, $row[$i]);
+ }
+ }
+ push(@newgroups, $group);
+ }
+
+# Save the groups
+&lock_itsecur_files();
+@groups = &list_groups();
+push(@groups, @newgroups);
+&automatic_backup();
+&save_groups(@groups);
+&unlock_itsecur_files();
+
+# Tell the user
+&header($text{'import_title'}, "",
+ undef, undef, undef, undef, &apply_button());
+print "<hr>\n";
+
+print "<p>",&text('import_done3', scalar(@newgroups)),"<p>\n";
+
+print "<hr>\n";
+&footer("", $text{'index_return'});
+&remote_webmin_log("import", "services", $in{'src_def'} ? undef : $in{'src'});
+
--- /dev/null
+#!/usr/bin/perl
+# Actually do an import
+
+require './itsecur-lib.pl';
+&can_edit_error("import");
+&error_setup($text{'import_err'});
+&ReadParseMime();
+
+if (&foreign_check("net")) {
+ &foreign_require("net", "net-lib.pl");
+ foreach $i (&net::active_interfaces(), &net::boot_interfaces()) {
+ $iface{$i->{'fullname'}} = $i;
+ }
+ }
+%services = map { $_->{'name'}, $_ } &list_services();
+%times = map { $_->{'name'}, $_ } &list_times();
+
+# Validate inputs
+if (!$in{'src_def'}) {
+ -r $in{'src'} || &error_cleanup($text{'restore_esrc'});
+ $data = `cat $in{'src'}`;
+ }
+else {
+ $in{'file'} || &error_cleanup($text{'restore_efile'});
+ $data = $in{'file'};
+ }
+
+# Parse the CSV data
+$data =~ s/\r//g;
+$i = 0;
+foreach $line (split(/\n/, $data)) {
+ # Split into columns
+ $oldline = $line;
+ $i++;
+ next if (!$line);
+ local @row;
+ while($line && $line =~ /^,?("([^"]*)"|([^,]*))(.*)$/) {
+ push(@row, $2 || $3);
+ $line = $4;
+ }
+ @row >= 4 || &error(&text('import_erow', $i, $oldline));
+
+ # Create a rule
+ $rule = { 'enabled' => 1 };
+ $rule->{'source'} = &parse_srcdest($row[0]);
+ $rule->{'source'} || &error(text('import_esource', $i, $row[0]));
+ $rule->{'dest'} = &parse_srcdest($row[1]);
+ $rule->{'dest'} || &error(text('import_edest', $i, $row[1]));
+ @servs = split(/\s+/, $row[2]);
+ foreach $s (@servs) {
+ $services{$s} || &error(text('import_eservice', $i, $s));
+ }
+ $rule->{'service'} = @servs ? join(",", @servs) : "*";
+ if ($row[3] =~ s/\s+log$//i) {
+ $rule->{'log'} = 1;
+ }
+ else {
+ $rule->{'log'} = 0;
+ }
+ &indexof(lc($row[3]), @actions) >= 0 ||
+ &error(text('import_eaction', $i, $row[3]));
+ $rule->{'action'} = lc($row[3]);
+ $rule->{'desc'} = $row[4] || "*";
+ if ($row[5]) {
+ $times{$row[5]} || &error(text('import_etime', $i, $row[5]));
+ $rule->{'time'} = $row[5];
+ }
+ else {
+ $rule->{'time'} = "*";
+ }
+ push(@newrules, $rule);
+ }
+
+# Ensure that new rules are sane
+
+# Save the rules
+&lock_itsecur_files();
+@rules = &list_rules();
+push(@rules, @newrules);
+&automatic_backup();
+&save_rules(@rules);
+&unlock_itsecur_files();
+
+# Tell the user
+&header($text{'import_title'}, "",
+ undef, undef, undef, undef, &apply_button());
+print "<hr>\n";
+
+print "<p>",&text('import_done1', scalar(@newrules)),"<p>\n";
+
+print "<hr>\n";
+&footer("", $text{'index_return'});
+&remote_webmin_log("import", "rules", $in{'src_def'} ? undef : $in{'src'});
+
+sub parse_srcdest
+{
+if ($_[0] eq "") {
+ return "*";
+ }
+elsif (&valid_host($_[0])) {
+ return $_[0];
+ }
+elsif ($iface{lc($_[0])}) {
+ return "%".lc($_[0]);
+ }
+else {
+ return undef;
+ }
+}
--- /dev/null
+#!/usr/bin/perl
+# Actually do an import of services
+
+require './itsecur-lib.pl';
+&can_edit_error("import");
+&error_setup($text{'import_err'});
+&ReadParseMime();
+
+# Validate inputs
+if (!$in{'src_def'}) {
+ -r $in{'src'} || &error_cleanup($text{'restore_esrc'});
+ $data = `cat $in{'src'}`;
+ }
+else {
+ $in{'file'} || &error_cleanup($text{'restore_efile'});
+ $data = $in{'file'};
+ }
+
+%services = map { $_->{'name'}, $_ } &list_services();
+
+# Parse the CSV data
+$data =~ s/\r//g;
+$i = 0;
+foreach $line (split(/\n/, $data)) {
+ # Split into columns
+ $oldline = $line;
+ $i++;
+ next if (!$line);
+ local @row;
+ while($line && $line =~ /^,?("([^"]*)"|([^,]*))(.*)$/) {
+ push(@row, $2 || $3);
+ $line = $4;
+ }
+ @row >= 3 || &error(&text('import_erow', $i, $oldline));
+
+ # Create a service
+ $row[0] =~ /\S/ || &error(text('import_eservname', $i));
+ $services{$row[0]} && &error(text('import_eservclash', $i, $row[0]));
+ $serv = { 'name' => $row[0] };
+ for($i=1; $i<@row; $i+=2) {
+ getprotobyname($row[$i]) ||
+ &error(text('import_eproto', $i, $row[$i]));
+ $row[$i+1] =~ /^\d+$/ ||
+ &error(text('import_eservnum', $i, $row[$i]));
+ push(@{$serv->{'protos'}}, $row[$i]);
+ push(@{$serv->{'ports'}}, $row[$i+1]);
+ }
+ push(@newservs, $serv);
+ }
+
+# Save the services
+&lock_itsecur_files();
+@servs = &list_services();
+push(@servs, @newservs);
+&automatic_backup();
+&save_services(@servs);
+&unlock_itsecur_files();
+
+# Tell the user
+&header($text{'import_title'}, "",
+ undef, undef, undef, undef, &apply_button());
+print "<hr>\n";
+
+print "<p>",&text('import_done2', scalar(@newservs)),"<p>\n";
+
+print "<hr>\n";
+&footer("", $text{'index_return'});
+&remote_webmin_log("import", "services", $in{'src_def'} ? undef : $in{'src'});
+
--- /dev/null
+#!/usr/bin/perl
+# Actually do an import of time ranges
+
+require './itsecur-lib.pl';
+&can_edit_error("import");
+&error_setup($text{'import_err'});
+&ReadParseMime();
+
+# Validate inputs
+if (!$in{'src_def'}) {
+ -r $in{'src'} || &error_cleanup($text{'restore_esrc'});
+ $data = `cat $in{'src'}`;
+ }
+else {
+ $in{'file'} || &error_cleanup($text{'restore_efile'});
+ $data = $in{'file'};
+ }
+
+%times = map { $_->{'name'}, $_ } &list_times();
+%daynum = ( "sun", 0, "mon", 1, "tue", 2, "wed", 3, "thu", 4, "fri", 5, "sat", 6 );
+
+# Parse the CSV data
+$data =~ s/\r//g;
+$i = 0;
+foreach $line (split(/\n/, $data)) {
+ # Split into columns
+ $oldline = $line;
+ $i++;
+ next if (!$line);
+ local @row;
+ while($line && $line =~ /^,?("([^"]*)"|([^,]*))(.*)$/) {
+ push(@row, $2 || $3);
+ $line = $4;
+ }
+ @row >= 1 || &error(&text('import_erow', $i, $oldline));
+
+ # Create a service
+ $row[0] =~ /\S/ || &error(text('import_etimename', $i));
+ $times{$row[0]} && &error(text('import_etimeclash', $i, $row[0]));
+ $time = { 'name' => $row[0] };
+ if ($row[1]) {
+ # Week days are given
+ foreach $d (split(/[\s|,]+/, $row[1])) {
+ local $dn = $daynum{lc($d)};
+ defined($dn) || &error(text('import_etimeday', $i, $d));
+ push(@days, $dn);
+ }
+ $time->{'days'} = join(",", @days);
+ }
+ else {
+ $time->{'days'} = '*';
+ }
+ if ($row[2]) {
+ # Time range is given
+ $row[2] =~ /^(\d+):(\d+)\-(\d+):(\d+)$/ &&
+ $1 >= 0 && $1 < 24 &&
+ $2 >= 0 && $2 < 60 &&
+ $3 >= 0 && $3 < 24 &&
+ $4 >= 0 && $4 < 60 ||
+ &error(&text('import_etimehour', $i, $row[2]));
+ $time->{'hours'} = $row[2];
+ }
+ else {
+ $time->{'hours'} = '*';
+ }
+ $time->{'days'} eq '*' && $time->{'hours'} eq '*' &&
+ &error(text('import_etimenone', $i));
+ push(@newtimes, $time);
+ }
+
+# Save the groups
+&lock_itsecur_files();
+@times = &list_times();
+push(@times, @newtimes);
+&automatic_backup();
+&save_times(@times);
+&unlock_itsecur_files();
+
+# Tell the user
+&header($text{'import_title'}, "",
+ undef, undef, undef, undef, &apply_button());
+print "<hr>\n";
+
+print "<p>",&text('import_done4', scalar(@newtimes)),"<p>\n";
+
+print "<hr>\n";
+&footer("", $text{'index_return'});
+&remote_webmin_log("import", "times", $in{'src_def'} ? undef : $in{'src'});
+
--- /dev/null
+#!/usr/bin/perl
+# index.cgi
+# Show icons for rules, services, groups and NAT
+
+require './itsecur-lib.pl';
+&header($text{'index_title'}, "", undef, 1, 1, 0, &apply_button(), undef, undef,
+ &text('index_version', $module_info{'version'}));
+print "<hr>\n";
+
+# Icons table
+@can_opts = grep { $_ eq "backup" || $_ eq "restore" || $_ eq "remote" || $_ eq "import" ? &can_edit($_) : &can_use($_) } @opts;
+@links = map { "list_".$_.".cgi" } @can_opts;
+@titles = map { $text{$_."_title"} } @can_opts;
+@icons = map { "images/".$_.".gif" } @can_opts;
+@hrefs = map { ($_ eq "logs" || $_ eq "authlogs") && $config{'open_logs'} ? "target=_new" : "" } @can_opts;
+&itsecur_icons_table(\@links, \@titles, \@icons, 4, \@hrefs);
+
+if (&can_edit("apply") || &can_edit("bootup")) {
+ print "<hr>\n";
+ }
+
+print "<table width=100%>\n";
+
+if (&can_edit("apply")) {
+ # Apply button
+ print "<form action=apply.cgi><tr>\n";
+ print "<td><input type=submit value='$text{'index_apply'}'></td>\n";
+ print "<td>$text{'index_applydesc'}</td>\n";
+ print "</tr></form>\n";
+ }
+
+if (&can_edit("bootup")) {
+ &foreign_require("init", "init-lib.pl");
+ $atboot = &init::action_status("itsecur-firewall") == 2;
+
+ # At-boot button
+ print "<tr><form action=bootup.cgi>\n";
+ print "<td nowrap><input type=submit value='$text{'index_bootup'}'>\n";
+ printf "<input type=radio name=boot value=1 %s> %s\n",
+ $atboot ? "checked" : "", $text{'yes'};
+ printf "<input type=radio name=boot value=0 %s> %s\n",
+ $atboot ? "" : "checked", $text{'no'};
+ print "</td> <td>$text{'index_bootupdesc'}</td>\n";
+ print "</form></tr>\n";
+ }
+
+print "</table>\n";
+
+print "<hr>\n";
+&footer("/", $text{'index'});
+
+# itsecur_icons_table(&links, &titles, &icons, [columns], [href], [width], [height])
+# Renders a 4-column table of icons
+sub itsecur_icons_table
+{
+&load_theme_library();
+if (defined(&theme_icons_table)) {
+ &theme_icons_table(@_);
+ return;
+ }
+local ($i, $need_tr);
+local $cols = $_[3] ? $_[3] : 4;
+local $per = int(100.0 / $cols);
+print "<table width=100% cellpadding=5>\n";
+for($i=0; $i<@{$_[0]}; $i++) {
+ if ($i%$cols == 0) { print "<tr>\n"; }
+ print "<td width=$per% align=center valign=top>\n";
+ &generate_icon($_[2]->[$i], $_[1]->[$i], $_[0]->[$i],
+ ref($_[4]) ? $_[4]->[$i] : $_[4], $_[5], $_[6]);
+ print "</td>\n";
+ if ($i%$cols == $cols-1) { print "</tr>\n"; }
+ }
+while($i++%$cols) { print "<td width=$per%></td>\n"; $need_tr++; }
+print "</tr>\n" if ($need_tr);
+print "</table>\n";
+}
+
+
--- /dev/null
+# ipf-lib.pl
+# Defines firewall functions for IPF
+
+@actions = ( "allow", "deny", "reject" );
+$script_file = "$module_config_directory/ipf.sh";
+$nat_conf = "$module_config_directory/nat.conf";
+use Time::Local;
+
+# apply_rules(&rules, &hosts, &services)
+# Turns the firewall configuration into an IPF script
+sub apply_rules
+{
+&deactivate_all_interfaces(); # will add those needed later
+local $ipfw = &has_command("ipfw");
+
+# Open scripts
+open(SCRIPT, ">$script_file");
+print SCRIPT "#!/bin/sh\n";
+open(NATCONF, ">$nat_conf");
+
+# Clear existing rules
+print SCRIPT "$ipfw -f flush\n";
+
+# Add rules for spoofing
+local ($spoofiface, @nets) = &get_spoof();
+local $num = 1;
+if ($spoofiface) {
+ local $n;
+ foreach $n (@nets) {
+ print_ipfw("drop ip from $n to any recv $spoofiface");
+ }
+ }
+
+# Allow established connections
+$num = 2;
+print_ipfw("allow tcp from any to any established");
+
+# Always allow localhost
+$num = 3;
+print_ipfw("allow ip from any to any recv lo");
+
+if ($config{'frags'}) {
+ # Drop fragments
+ # XXX how?
+ }
+
+# Add primary rules
+local $r;
+local @rules = &list_rules();
+local %services = map { $_->{'name'}, $_ } &list_services();
+local @groups = &list_groups();
+foreach $r (@rules) {
+ next if (!$r->{'enabled'});
+ next if ($r->{'sep'});
+ $num = $r->{'num'}*10;
+
+ # Work out all source and destination hosts?
+ local @sources = &expand_hosts($r->{'source'}, \@groups);
+ local @dests = &expand_hosts($r->{'dest'}, \@groups);
+
+ # Need to output a rule for every possible combination
+ local ($source, $dest);
+ local $aarg = $r->{'action'};
+ local $logarg = $r->{'log'} ? "log" : "";
+ foreach $source (@sources) {
+ $source =~ s/^!(\S.*)$/not $1/;
+ local $sarg = $source eq '*' ? "from any" :
+ $source =~ /^%(.*)$/ ? "from any" :
+ "from $source";
+ local $siarg = $source =~ /^%(.*)$/ ? "xmit $1" : "";
+
+ foreach $dest (@dests) {
+ $dest =~ s/^!(\S.*)$/! $1/;
+ local $darg = $dest eq '*' && !$config{'fw_any'} &&
+ $r->{'action'} eq 'allow' ? "! -d me" :
+ $dest =~ /^%(.*)$/ ? "to any" :
+ "to $dest";
+ local $diarg = $dest =~ /^%(.*)$/ ? "recv $1" : "";
+
+ if ($r->{'service'} ne '*') {
+ # Output one rule for each service
+ local ($protos, $ports) =
+ &combine_services($r->{'service'},
+ \%services);
+ for($i=0; $i<@$protos; $i++) {
+ local $pr = lc($protos->[$i]);
+ local $pt = $ports->[$i];
+
+ local $parg;
+ local $opts;
+ local $prarg;
+ if ($pr eq "gre") {
+ # handle old GRE protocols
+ $pr = "ip";
+ $pr = "gre";
+ }
+ if ($pr eq "ip") {
+ $prarg = $pt;
+ }
+ else {
+ $prarg = $pr;
+ }
+ if ($pr eq "ip") {
+ # No port for IP
+ }
+ elsif ($pt =~ /^(\d+)$/ || $pt eq '*') {
+ if ($pr eq 'icmp') {
+ $opts = " icmptype $pt" if ($pt ne '*');
+ }
+ else {
+ $parg = $pt;
+ }
+ }
+ elsif ($pt =~ /^(\d+)\-(\d+)$/) {
+ $parg = "$1-$2";
+ }
+ else {
+ $parg = join(",", split(/\s+/, $pt));
+ }
+ print_ipfw("$aarg $logarg $prarg $sarg $darg $parg $opts $siarg $diarg");
+ }
+ }
+ else {
+ # Single service-independent rule
+ print_ipfw("$aarg $logarg ip $sarg $darg $siarg $diarg");
+ }
+ }
+ }
+ }
+
+# Add syn flood and spoofing rules
+local ($flood, $spoof, $fin) = &get_syn();
+if ($flood) {
+ # Configure kernel to use syn cookies
+ print SCRIPT "sysctl net.inet.tcp.syncookies=1\n";
+ }
+else {
+ # Configure kernel to disable syn cookies
+ print SCRIPT "sysctl net.inet.tcp.syncookies=0\n";
+ }
+if ($spoof) {
+ # Drop TCP connection starts without SYN set
+ $num = 60000;
+ print_ipfw("allow tcp from any to any established");
+ print_ipfw("deny tcp from any to any tcpflags !syn");
+ }
+if ($fin) {
+ # Drop TCP packets with both SYN and FIN set
+ $num = 61000;
+ print_ipfw("deny tcp from any to any tcpflags syn,fin");
+ }
+
+local ($natiface, @nets) = &get_nat();
+local @maps;
+if ($natiface) {
+ # Add rules for NAT
+ @maps = grep { ref($_) } @nets;
+ @nets = grep { !ref($_) } @nets;
+ local $m;
+ foreach $m (@maps) {
+ # Add rule for static NAT (internal to external host mapping)
+ print NATCONF "map $natiface $m->[1]/32 -> $m->[0]/32\n";
+ print NATCONF "map $natiface $m->[0]/32 -> $m->[1]/32\n";
+ if ($m->[2]) {
+ &activate_interface($m->[2], $m->[0]);
+ }
+ }
+ local $n;
+ foreach $n (@nets) {
+ # Add rule for dynamic NAT
+ local @sources = &expand_hosts("\@$n", \@groups);
+ local $source;
+ foreach $source (@sources) {
+ $source =~ s/^!(\S.*)$/! $1/;
+ print NATCONF "map $natiface $source -> 0/32\n";
+ }
+ }
+ }
+
+# Add rules for PAT (external port to internal host mapping)
+local @forwards = &get_pat();
+local $f;
+foreach $f (@forwards) {
+ next if (!$f->{'iface'});
+ local ($protos, $ports) = &combine_services($f->{'service'},
+ \%services);
+ local $i;
+ for($i=0; $i<@$protos; $i++) {
+ local $pr = lc($protos->[$i]);
+ local $pt = $ports->[$i];
+ next if ($pr ne 'tcp' && $pr ne 'udp');
+ print NATCONF "rdr $f->{'iface'} 0/32 port $pt -> $f->{'host'} port $pt $pr\n";
+ }
+ }
+
+# Allow all by default
+$num = 60001;
+print_ipfw("allow ip from any to any");
+close(SCRIPT);
+chmod(0755, $script_file);
+close(NATCONF);
+
+# Run the script
+#return "<pre>".`cat $script_file`."</pre>\n";
+local $out = `cd /; $script_file 2>&1 </dev/null`;
+if ($?) {
+ return "IPF script output : <pre>$out</pre>";
+ }
+
+# Run the NAT config
+$out = `cd /; ipnat -C >/dev/null ; ipnat -f $nat_conf 2>&1 </dev/null`;
+if ($? || $out) {
+ return "ipnat command output : <pre>$out</pre>";
+ }
+
+return undef;
+}
+
+sub print_ipfw
+{
+print SCRIPT "$ipfw add $num $_[0]\n";
+}
+
+# stop_rules()
+# Allow all traffic
+sub stop_rules
+{
+&deactivate_all_interfaces();
+system("cd /; ipfw -f flush; ipfw add allow ip from any to any");
+system("cd /; ipnat -C");
+}
+
+# enable_routing()
+# Enable routing under BSD
+sub enable_routing
+{
+system("sysctl net.inet.ip.forwarding=1 >/dev/null 2>&1");
+}
+
+# disable_routing()
+# Disable routing under BSD
+sub disable_routing
+{
+system("sysctl net.inet.ip.forwarding=0 >/dev/null 2>&1");
+}
+
+sub get_log_file
+{
+return "/var/log/security";
+}
+
+sub get_authlog_file
+{
+return "/var/log/security";
+}
+
+sub is_log_line
+{
+return $_[0] =~ /\sipfw:\s/;
+}
+
+$time_now = time();
+@time_now = localtime($time_now);
+%mmap = ( 'jan' => 0, 'feb' => 1, 'mar' => 2, 'apr' => 3,
+ 'may' => 4, 'jun' => 5, 'jul' => 6, 'aug' => 7,
+ 'sep' => 8, 'oct' => 9, 'nov' =>10, 'dec' =>11 );
+
+# parse_log_line(line)
+# Parses a line into a log info structure, or returns undef
+sub parse_log_line
+{
+if (&is_log_line($_[0])) {
+ local $info = { };
+ if ($_[0] =~ /^(\S+)\s+(\d+)\s+(\d+):(\d+):(\d+)/) {
+ local $tm = timelocal($5, $4, $3, $2, $mmap{lc($1)}, $time_now[5]);
+ if ($tm > $time_now + 24*60*60) {
+ # Was really last year
+ $tm = timelocal($5, $4, $3, $2, $mmap{lc($1)}, $time_now[5]-1);
+ }
+ $info->{'time'} = $tm;
+ }
+ if ($_[0] =~ /ipfw:\s+(\d+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(in|out)\s+\S+\s+(\S+)/) {
+ if ($1 >= 10 && $1 < 60000) {
+ $info->{'rule'} = int($1/10);
+ }
+ $info->{'action'} = lc($2);
+ $info->{'action'} = "allow" if ($info->{'action'} eq "accept");
+ $info->{'proto'} = uc($3);
+ if ($6 eq "in") {
+ $info->{'dst_iface'} = $7;
+ }
+ else {
+ $info->{'src_iface'} = $7;
+ }
+ local ($src, $dst) = ($4, $5);
+ if ($src =~ /^(\S+):(\d+)$/) {
+ $info->{'src'} = $1;
+ $info->{'src_port'} = $2;
+ }
+ else {
+ $info->{'src'} = $src;
+ }
+ if ($dst =~ /^(\S+):(\d+)$/) {
+ $info->{'dst'} = $1;
+ $info->{'dst_port'} = $2;
+ }
+ else {
+ $info->{'dst'} = $dst;
+ }
+ if ($info->{'proto'} =~ /^(ICMP):(\d+)/) {
+ $info->{'proto'} = $1;
+ $info->{'dst_port'} = $2;
+ }
+ }
+ return $info;
+ }
+else {
+ return undef;
+ }
+}
+
+sub allow_action
+{
+return $_[0]->{'action'} eq 'allow';
+}
+
+sub deny_action
+{
+return $_[0]->{'action'} eq 'deny';
+}
+
+sub default_action
+{
+return "deny";
+}
+
+sub supports_time
+{
+return 0;
+}
+
+sub supports_bandwidth
+{
+return 0;
+}
+
+1;
+
--- /dev/null
+# iptables-lib.pl
+# Defines firewall functions for IPtables
+
+@actions = ( 'accept', 'drop', 'reject', 'ignore' );
+$save_file = "$module_config_directory/iptables.save";
+$prerules = "$module_config_directory/prerules";
+$postrules = "$module_config_directory/postrules";
+$prenat = "$module_config_directory/prenat";
+$postnat = "$module_config_directory/postnat";
+$premangle = "$module_config_directory/premangle";
+$postmangle = "$module_config_directory/postmangle";
+
+
+use Time::Local;
+
+# apply_rules()
+# Turns the firewall configuration into an IPtables save file, and then
+# applies it.
+sub apply_rules
+{
+&deactivate_all_interfaces(); # will add those needed later
+
+local @dayname = ( "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" );
+
+# Create the groups
+open(SAVE, ">$save_file");
+print SAVE "*filter\n";
+print SAVE ":INPUT ACCEPT [0:0]\n";
+print SAVE ":OUTPUT ACCEPT [0:0]\n";
+print SAVE ":FORWARD ACCEPT [0:0]\n";
+print SAVE ":SYN-FLOOD -\n";
+
+# Disable bandwith monitor
+# Have a lots of issues.
+# AA 2006-02-21
+
+
+#if ($config{'bandwidth'}) {
+# # Add rules for bandwidth logging
+# print SAVE "-A INPUT -i $config{'bandwidth'} -j LOG --log-prefix BANDWIDTH_IN: --log-level debug\n";
+# print SAVE "-A FORWARD -i $config{'bandwidth'} -j LOG --log-prefix BANDWIDTH_IN: --log-level debug\n";
+# print SAVE "-A FORWARD -o $config{'bandwidth'} -j LOG --log-prefix BANDWIDTH_OUT: --log-level debug\n";
+# print SAVE "-A OUTPUT -o $config{'bandwidth'} -j LOG --log-prefix BANDWIDTH_OUT: --log-level debug\n";
+# }
+
+# Add rules for spoofing
+local ($spoofiface, @nets) = &get_spoof();
+if ($spoofiface) {
+ local $n;
+ foreach $n (@nets) {
+ print SAVE "-A INPUT -i $spoofiface -s $n -j DROP\n";
+ }
+ }
+
+# Always allow established connections
+print SAVE "-A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT\n";
+print SAVE "-A FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT\n";
+
+# Always allow localhost
+print SAVE "-A INPUT -i lo -j ACCEPT\n";
+print SAVE "-A OUTPUT -o lo -j ACCEPT\n";
+
+if ($config{'frags'}) {
+ # Drop fragments
+ print SAVE "-A INPUT -p ip -f -j DROP\n";
+ print SAVE "-A OUTPUT -p ip -f -j DROP\n";
+ print SAVE "-A FORWARD -p ip -f -j DROP\n";
+ }
+
+# Add syn flood and spoofing rules
+local ($flood, $spoof, $fin) = &get_syn();
+if ($flood) {
+ # Limit number of syns / second
+ print SAVE "-A SYN-FLOOD -m limit --limit 1/s --limit-burst 4 -j RETURN\n";
+ print SAVE "-A SYN-FLOOD -j DROP\n";
+ print SAVE "-A INPUT -p tcp -m tcp --syn -j SYN-FLOOD\n";
+ }
+if ($spoof) {
+ # Drop TCP connection starts without SYN set
+ print SAVE "-A INPUT -p tcp -m tcp ! --syn -m state --state NEW -j DROP\n";
+ }
+if ($fin) {
+ # Drop TCP packets with both SYN and FIN
+ print SAVE "-A INPUT -p tcp -m tcp --tcp-flags SYN,FIN SYN,FIN -j DROP\n";
+ }
+
+# Load PRErules
+open(STATICS, $prerules);
+while(<STATICS>) {
+ print SAVE "$_";
+ }
+close(STATICS);
+
+# Add primary rules
+local $r;
+local @rules = &list_rules();
+local %services = map { $_->{'name'}, $_ } &list_services();
+local %times = map { $_->{'name'}, $_ } &list_times();
+local @groups = &list_groups();
+foreach $r (@rules) {
+ next if (!$r->{'enabled'});
+ next if ($r->{'sep'});
+
+ # Work out all source and destination hosts?
+ local @sources = &expand_hosts($r->{'source'}, \@groups);
+ local @dests = &expand_hosts($r->{'dest'}, \@groups);
+
+ # Work out time args
+ local $timearg;
+ if ($r->{'time'} ne "*") {
+ local $time = $times{$r->{'time'}};
+ $timearg .= "-m time";
+ if ($time->{'hours'} ne "*") {
+ local ($from, $to) = split(/\-/, $time->{'hours'});
+ $timearg .= " --timestart $from --timestop $to";
+ }
+ if ($time->{'days'} ne "*") {
+ $timearg .= " --days ".
+ join(",", map { $dayname[$_] }
+ split(/,/, $time->{'days'}));
+ }
+ }
+
+ # Need to output a rule for every possible combination
+ local ($source, $dest);
+ local $aarg = "-j ".uc($r->{'action'});
+ local $n = $r->{'num'};
+ local $logpfx = "--log-prefix RULE_${n}:".uc($r->{'action'}).":";
+ foreach $source (@sources) {
+ $source =~ s/^!(\S.*)$/! $1/;
+ local $sarg = $source eq '*' ? "" :
+ $source =~ /^%(.*)$/ ? "-o $1" :
+ "-s $source";
+ local $me = &my_address_in($source);
+
+ foreach $dest (@dests) {
+ $dest =~ s/^!(\S.*)$/! $1/;
+ local $darg = $dest eq '*' && !$config{'fw_any'} &&
+ $r->{'action'} eq 'accept' ? "! -d $me" :
+ $dest eq '*' ? "" :
+ $dest =~ /^%(.*)$/ ? "-i $1" :
+ "-d $dest";
+
+ if ($r->{'service'} ne '*') {
+ # Output one rule for each real service
+ local ($protos, $ports) =
+ &combine_services($r->{'service'},
+ \%services);
+ for($i=0; $i<@$protos; $i++) {
+ local $pr = lc($protos->[$i]);
+ local $pt = $ports->[$i];
+ local $marg = $pr eq 'tcp' ||
+ $pr eq 'udp' || $pr eq 'icmp' ? "-m $pr" : "";
+ local $prarg;
+ if ($pr eq "gre") {
+ # handle old GRE protocols
+ $pr = "ip";
+ $pr = "gre";
+ }
+ if ($pr eq "ip") {
+ $prarg = "-p $pt";
+ }
+ else {
+ $prarg = "-p $pr";
+ }
+ local $parg;
+ if ($pr eq "ip") {
+ # No need for port number
+ }
+ elsif ($pt =~ /^(\d+)$/ || $pt eq '*') {
+ if ($pr eq 'icmp') {
+ $parg = "--icmp-type $pt" if ($pt ne '*');
+ }
+ else {
+ $parg = "--destination-port $pt";
+ }
+ }
+ elsif ($pt =~ /^(\d+)\-(\d+)$/) {
+ $parg = "--dport $1:$2";
+ }
+ else {
+ $parg = "--dports ".
+ join(",", split(/\s+/, $pt));
+ $marg .= " -m multiport";
+ }
+ if ($r->{'log'}) {
+ if ($source !~ /^%(.*)$/) {
+ #if ($dest !~ /^%(.*)$/) {
+ print SAVE "-A INPUT $marg $prarg $timearg $sarg $darg $parg -j LOG $logpfx\n";
+ }
+ print SAVE "-A FORWARD $marg $prarg $timearg $sarg $darg $parg -j LOG $logpfx\n";
+ }
+ if ($source !~ /^%(.*)$/) {
+ #if ($dest !~ /^%(.*)$/) {
+ print SAVE "-A INPUT $marg $prarg $timearg $sarg $darg $parg $aarg\n";
+ }
+ print SAVE "-A FORWARD $marg $prarg $timearg $sarg $darg $parg $aarg\n";
+ }
+ }
+ else {
+ # Single service-independent rule
+ if ($r->{'log'}) {
+ if ($source !~ /^%(.*)$/) {
+ #if ($dest !~ /^%(.*)$/) {
+ print SAVE "-A INPUT $timearg $sarg $darg -j LOG $logpfx\n";
+ }
+ print SAVE "-A FORWARD $timearg $sarg $darg -j LOG $logpfx\n";
+ }
+ if ($source !~ /^%(.*)$/) {
+ #if ($dest !~ /^%(.*)$/) {
+ print SAVE "-A INPUT $timearg $sarg $darg $aarg\n";
+ }
+ print SAVE "-A FORWARD $timearg $sarg $darg $aarg\n";
+ }
+ }
+ }
+ }
+# Load POSTrules
+open(STATICS, $postrules);
+while(<STATICS>) {
+ print SAVE "$_";
+ }
+close(STATICS);
+
+
+print SAVE "COMMIT\n";
+
+print SAVE "*nat\n";
+print SAVE ":PREROUTING ACCEPT [0:0]\n";
+print SAVE ":POSTROUTING ACCEPT [0:0]\n";
+print SAVE ":OUTPUT ACCEPT [0:0]\n";
+
+
+
+local ($natiface, @nets) = &get_nat();
+local @maps;
+if ($natiface) {
+ # Add rules for NAT
+ @maps = grep { ref($_) } @nets;
+ @nets = grep { !ref($_) } @nets;
+
+ # Add rules for NAT exclusions
+ local ($e,$my_e);
+ foreach $e (grep { $_ =~ /^\!/ } @nets) {
+ $my_e = $e;
+ $my_e =~ s/^\!//;
+ local @dests = &expand_hosts("\@$my_e", \@groups);
+ local $dest;
+
+ foreach $dest (@dests) {
+ $dest =~ s/^!(\S.*)$/! $1/;
+ #print SAVE "-A POSTROUTING -o $natiface -d $dest -j RETURN\n";
+ #print SAVE "-A PREROUTING -i $natiface -d $dest -j RETURN\n";
+ print SAVE "-A POSTROUTING -d $dest -j RETURN\n";
+ print SAVE "-A PREROUTING -d $dest -j RETURN\n";
+ }
+ }
+ #Clear the nets_copy
+
+ # Load PREnat After Return
+ open(STATICS, $prenat);
+ while(<STATICS>) {
+ print SAVE "$_";
+ }
+ close(STATICS);
+
+
+ # Add rules for static NAT
+ local $m;
+ local ($intf_i,$intf_o,$option_i,$option_o);
+
+ # local @dests = &expand_hosts("\@$my_e", \@groups);
+ local (@tmp,$internal,$external);
+
+
+ foreach $m (@maps) {
+ @tmp = &expand_hosts("\@$m->[1]", \@groups);
+ $internal=$tmp[0];
+ #@tmp = &expand_hosts("\@$m->[0]", \@groups);
+ $external="$m->[0]";
+ if ($m->[2]) {
+ $intf_i= " -i $m->[2] ";
+ $intf_o= " -o $m->[2] ";
+ } else {
+ $intf_i= "";
+ $intf_o= "";
+ }
+ if (&check_netaddress($external)) {
+ $option_i=" -j NETMAP ";
+ $option_o=" -j NETMAP ";
+ } elsif (&check_netaddress($internal)) {
+ $option_o=" -j SNAT ";
+ if ($m->[2]) {
+ &activate_interface($m->[2], $external);
+ }
+ } else {
+ $option_i=" -j DNAT ";
+ $option_o=" -j SNAT ";
+ if ($m->[2]) {
+ &activate_interface($m->[2], $external);
+ }
+ }
+ (! &check_netaddress($internal) ) && print SAVE "-A PREROUTING $intf_i -d $external $option_i --to $internal\n";
+ print SAVE "-A POSTROUTING $intf_o -s $internal $option_o --to $external\n";
+ }
+
+ # Load POSTnat
+ open(STATICS, $postnat);
+ while(<STATICS>) {
+ print SAVE "$_";
+ }
+ close(STATICS);
+
+ # Add rules for dynamic NAT
+
+ local $n;
+ foreach $n (grep { $_ !~ /^\!/ } @nets) {
+ local @sources = &expand_hosts("\@$n", \@groups);
+ local $source;
+ foreach $source (@sources) {
+ $source =~ s/^!(\S.*)$/! $1/;
+ print SAVE "-A POSTROUTING -o $natiface -s $source -j MASQUERADE\n";
+ }
+ }
+ }
+
+# Add rules for PAT
+local @forwards = &get_pat();
+local $f;
+foreach $f (@forwards) {
+ next if (!$f->{'iface'});
+ local ($protos, $ports) = &combine_services($f->{'service'},
+ \%services);
+ local $i;
+ for($i=0; $i<@$protos; $i++) {
+ local $pr = lc($protos->[$i]);
+ local $pt = $ports->[$i];
+ next if ($pr ne 'tcp' && $pr ne 'udp');
+ print SAVE "-A PREROUTING -m $pr -p $pr --dport $pt -i $f->{'iface'} -j DNAT --to-destination $f->{'host'}:$pt\n";
+ }
+ }
+
+print SAVE "COMMIT\n";
+
+print SAVE "*mangle\n";
+print SAVE ":PREROUTING ACCEPT [0:0]\n";
+print SAVE ":OUTPUT ACCEPT [0:0]\n";
+# Load PREmangle
+open(STATICS, $premangle);
+while(<STATICS>) {
+ print SAVE "$_";
+ }
+close(STATICS);
+# Add rules
+
+# Load POSTmangle
+open(STATICS, $postmangle);
+while(<STATICS>) {
+ print SAVE "$_";
+ }
+close(STATICS);
+print SAVE "COMMIT\n";
+close(SAVE);
+
+# Apply the save file
+local $out = `iptables-restore <$save_file 2>&1`;
+if ($?) {
+ return "iptables-restore output : <pre>$out</pre>";
+ }
+return undef;
+}
+
+# stop_rules()
+# Cancel all firewall rules and return to the default settings (allow all)
+sub stop_rules
+{
+&deactivate_all_interfaces();
+local $table;
+foreach $table ([ "filter", "INPUT", "OUTPUT", "FORWARD" ],
+ [ "nat", "PREROUTING", "POSTROUTING", "OUTPUT" ],
+ [ "mangle", "PREROUTING", "OUTPUT" ]) {
+ local ($name, @chains) = @$table;
+ local $cmd;
+ foreach $cmd ((map { "iptables -t $name -P $_ ACCEPT" } @chains),
+ "iptables -t $name -F",
+ "iptables -t $name -X",
+ "iptables -t $name -Z") {
+ local $out = `$cmd 2>&1`;
+ if ($?) {
+ return "$cmd output : $out";
+ }
+ }
+ }
+return undef;
+}
+
+# enable_routing()
+# Enable routing under Linux
+sub enable_routing
+{
+system("sysctl -w net.ipv4.ip_forward=1 >/dev/null 2>&1");
+}
+
+# disable_routing()
+# Disable routing under Linux
+sub disable_routing
+{
+system("sysctl -w net.ipv4.ip_forward=0 >/dev/null 2>&1");
+}
+
+sub get_log_file
+{
+return "/var/log/messages";
+}
+
+sub get_authlog_file
+{
+return -r "/var/log/secure" ? "/var/log/secure" :
+ -r "/var/log/security" ? "/var/log/security" :
+ -r "/var/log/authlog" ? "/var/log/authlog" :
+ "/var/log/auth";
+}
+
+sub is_log_line
+{
+return $_[0] =~ /IN=.*OUT=/;
+}
+
+$time_now = time();
+@time_now = localtime($time_now);
+%mmap = ( 'jan' => 0, 'feb' => 1, 'mar' => 2, 'apr' => 3,
+ 'may' => 4, 'jun' => 5, 'jul' => 6, 'aug' => 7,
+ 'sep' => 8, 'oct' => 9, 'nov' =>10, 'dec' =>11 );
+
+# parse_log_line(line)
+# Parses a line into a log info structure, or returns undef
+sub parse_log_line
+{
+if (&is_log_line($_[0])) {
+ local $info = { };
+ if ($_[0] =~ /RULE_(\d+):([^\s:]+)/) {
+ $info->{'rule'} = $1;
+ $info->{'action'} = lc($2);
+ }
+ if ($_[0] =~ /^(\S+)\s+(\d+)\s+(\d+):(\d+):(\d+)/) {
+ local $tm = timelocal($5, $4, $3, $2, $mmap{lc($1)}, $time_now[5]);
+ if ($tm > $time_now + 24*60*60) {
+ # Was really last year
+ $tm = timelocal($5, $4, $3, $2, $mmap{lc($1)}, $time_now[5]-1);
+ }
+ $info->{'time'} = $tm;
+ }
+ $info->{'src_iface'} = $1 if ($_[0] =~ /OUT=(\S*)/);
+ $info->{'dst_iface'} = $1 if ($_[0] =~ /IN=(\S*)/);
+ $info->{'src'} = $1 if ($_[0] =~ /SRC=(\S*)/);
+ $info->{'dst'} = $1 if ($_[0] =~ /DST=(\S*)/);
+ $info->{'size'} = $1 if ($_[0] =~ /LEN=(\S*)/);
+ $info->{'proto'} = $1 if ($_[0] =~ /PROTO=(\S*)/);
+ $info->{'src_port'} = $1 if ($_[0] =~ /SPT=(\S*)/);
+ $info->{'dst_port'} = $1 if ($_[0] =~ /DPT=(\S*)/);
+ $info->{'dst_port'} = $1 if ($_[0] =~ /TYPE=(\S*)/ &&
+ $info->{'proto'} eq 'ICMP');
+ return $info;
+ }
+else {
+ return undef;
+ }
+}
+
+sub allow_action
+{
+return $_[0]->{'action'} eq 'accept';
+}
+
+sub deny_action
+{
+return $_[0]->{'action'} eq 'drop';
+}
+
+sub default_action
+{
+return "drop";
+}
+
+sub supports_time
+{
+return 1;
+}
+
+sub supports_bandwidth
+{
+return &foreign_check("bandwidth");
+}
+
+1;
+
--- /dev/null
+# itsecure-lib.pl
+# Version
+# ITsecur
+# Common functions for all firewall types
+# XXX only backup firewall module users?
+
+BEGIN { push(@INC, ".."); };
+use WebminCore;
+&init_config();
+do "$config{'type'}-lib.pl";
+
+@opts = ( 'rules', 'services', 'groups', 'nat','nat2', 'pat', 'spoof', 'syn', 'logs',
+ 'authlogs', 'report',
+ 'users',
+ &supports_time() ? ('times') : (),
+ 'backup', 'restore',
+ 'remote', 'import' );
+# Take out to test
+# &supports_bandwidth() ? ('bandwidth') : (),
+@backup_opts = grep { $_ ne 'logs' && $_ ne 'backup' && $_ ne 'restore' }
+ (@opts, 'ipsec', 'searches', 'config');
+
+$groups_file = "$module_config_directory/groups";
+$standard_services_file = "$module_root_directory/standard-services";
+$services_file = "$module_config_directory/services";
+$rules_file = "$module_config_directory/rules";
+$nat_file = "$module_config_directory/nat";
+$nat2_file = "$module_config_directory/nat2";
+$pat_file = "$module_config_directory/pat";
+$spoof_file = "$module_config_directory/spoof";
+$syn_file = "$module_config_directory/syn";
+$times_file = "$module_config_directory/times";
+$active_interfaces = "$module_config_directory/active";
+$prerules = "$module_config_directory/prerules";
+$postrules = "$module_config_directory/postrules";
+$prenat = "$module_config_directory/prenat";
+$postnat = "$module_config_directory/postnat";
+$debug_file = "$module_config_directory/debug";
+
+$searches_dir = "$module_config_directory/searches";
+
+@config_files = ( $groups_file, $services_file,
+ $rules_file, $nat_file, $nat2_file, $pat_file, $spoof_file,
+ $syn_file, $times_file );
+
+%access = &get_module_acl();
+if (defined($access{'edit'})) {
+ if ($access{'edit'}) {
+ @edit_access = @read_access = split(/\s+/, $access{'features'});
+ }
+ else {
+ @read_access = split(/\s+/, $access{'features'});
+ }
+ }
+else {
+ @edit_access = split(/\s+/, $access{'features'});
+ @read_access = split(/\s+/, $access{'rfeatures'});
+ }
+%edit_access = map { $_, 1 } @edit_access;
+%read_access = map { $_, 1 } @read_access;
+
+$cron_cmd = "$module_config_directory/backup.pl";
+
+# list_groups([file])
+# Returns a list of groups. Each has a name and zero or more member hosts,
+# IP addresses, networks or other groups.
+sub list_groups
+{
+local @rv;
+open(GROUPS, $_[0] || $groups_file);
+while(<GROUPS>) {
+ s/\r|\n//g;
+ if (/^(\S+)\t+(.*)$/) {
+ local $group = { 'name' => $1,
+ 'members' => [ split(/\t+/, $2) ],
+ 'index' => scalar(@rv) };
+ push(@rv, $group);
+ }
+ }
+close(GROUPS);
+return @rv;
+}
+
+# save_groups(group, ...)
+# Updates the groups list
+sub save_groups
+{
+local $g;
+local @SortGroups=();
+foreach $g (@_) {
+ push(@SortGroups,$g->{'name'}."\t".join("\t", @{$g->{'members'}})."\n");
+ }
+open(GROUPS, ">$groups_file");
+print GROUPS sort { lc($a) cmp lc($b) } @SortGroups;
+close(GROUPS);
+&automatic_backup();
+}
+
+# list_services([file])
+# Returns a list of services, each of which has a name and multiple
+# protocols and port
+sub list_services
+{
+local ($sf, @rv);
+#if (!-r $standard_services_file) {
+# system("cp $module_root_directory/standard-services $standard_services_file");
+# }
+foreach $sf ($_[0] || $services_file, $standard_services_file) {
+ local @frv;
+ open(SERVS, $sf);
+ while(<SERVS>) {
+ s/\r|\n//g;
+ s/#.*$//;
+ s/\s+$//;
+ if (/^(\S+)\t+(.*)$/) {
+ local $serv = { 'name' => $1,
+ 'standard' =>
+ ($sf eq $standard_services_file),
+ 'index' => scalar(@frv) };
+ local @pps = split(/\s*\t+\s*/, $2);
+ local $i;
+ for($i=0; $i<@pps; $i+=2) {
+ if ($pps[$i] eq "other") {
+ push(@{$serv->{'others'}}, $pps[$i+1]);
+ }
+ else {
+ push(@{$serv->{'protos'}}, $pps[$i]);
+ push(@{$serv->{'ports'}}, $pps[$i+1]);
+ }
+ }
+ push(@frv, $serv);
+ }
+ }
+ close(SERVS);
+ if ($sf eq $standard_services_file) {
+ push(@rv, sort { lc($a->{'name'}) cmp lc($b->{'name'}) } @frv);
+ }
+ else {
+ push(@rv, @frv);
+ }
+ }
+return @rv;
+}
+
+# combine_services(comma-list, &services-hash)
+# Returns lists of protocols and port numbers taken from a comma-separated list
+# of service names
+sub combine_services
+{
+local (@protos, @ports);
+foreach $sn (split(/,/, $_[0])) {
+ local $serv = $_[1]->{$sn};
+ push(@protos, @{$serv->{'protos'}});
+ push(@ports, @{$serv->{'ports'}});
+ local ($cprotos, $cports) = &combine_services(join(",", @{$serv->{'others'}}), $_[1]);
+ push(@protos, @$cprotos);
+ push(@ports, @$cports);
+ }
+return (\@protos, \@ports);
+}
+
+# save_services(service, ...)
+sub save_services
+{
+#open(SERVS, ">$services_file");
+
+local @SortGroups;
+local $data;
+foreach $serv (@_) {
+ next if ($serv->{'standard'});
+ $data=$serv->{'name'};
+ local $i;
+ for($i=0; $i<@{$serv->{'protos'}}; $i++) {
+ $data = $data . "\t" . $serv->{'protos'}->[$i] . "\t" . $serv->{'ports'}->[$i];
+ }
+ for($i=0; $i<@{$serv->{'others'}}; $i++) {
+ if ( $serv->{'others'}->[$i] ne $serv->{'name'}) {
+ $data = $data . "\tother\t".$serv->{'others'}->[$i];
+ }
+ }
+ $data=$data . "\n";
+ push(@SortGroups,$data);
+ }
+
+
+open(SERVS, ">$services_file");
+print SERVS sort { lc($a) cmp lc($b) } @SortGroups;
+close(SERVS);
+
+}
+
+# list_rules([file])
+# Returns a list of rules, each of which has a source, destination, service,
+# action and log-flag
+sub list_rules
+{
+local @rv;
+open(RULES, $_[0] || $rules_file);
+local $rn = 1;
+while(<RULES>) {
+ s/\r|\n//g;
+ if (/^(#*)([^\t]+)\t+([^\t]+)\t+(\S+)\t+(\S+)\t+(\d+)(\t+(\S+))?(\t+(\S+))?$/) {
+ local $rule = { 'enabled' => !$1,
+ 'source' => $2,
+ 'dest' => $3,
+ 'service' => $4,
+ 'action' => $5,
+ 'log' => $6,
+ 'time' => $8 || "*",
+ 'desc' => &un_urlize($10 || "*"),
+ 'index' => scalar(@rv),
+ 'num' => $rn++ };
+ push(@rv, $rule);
+ }
+ elsif (/^(\S+)$/) {
+ local $sep = { 'sep' => 1,
+ 'desc' => &un_urlize($1),
+ 'index' => scalar(@rv) };
+ push(@rv, $sep);
+ }
+ }
+close(RULES);
+return @rv;
+}
+
+# save_rules(rule, ...)
+sub save_rules
+{
+open(RULES, ">$rules_file");
+local $rule;
+foreach $rule (@_) {
+ if ($rule->{'sep'}) {
+ print RULES &urlize($rule->{'desc'}),"\n";
+ }
+ else {
+ print RULES ($rule->{'enabled'} ? "" : "#"),
+ $rule->{'source'},"\t",
+ $rule->{'dest'},"\t",
+ $rule->{'service'},"\t",
+ $rule->{'action'},"\t",
+ $rule->{'log'},"\t",
+ $rule->{'time'},"\t",
+ $rule->{'desc'} eq "*" ? "*"
+ : &urlize($rule->{'desc'}),"\n";
+ }
+ }
+close(RULES);
+}
+
+# group_name(string, [direction])
+# Given a source or destination name that may be a group, makes it nice
+sub group_name
+{
+if ($_[0] =~ /^\@(.*)$/) {
+ # Host group
+ return "<font color=#0000ff>$1</font>";
+ }
+elsif ($_[0] =~ /^\!\@(.*)$/) {
+ # Negated host group
+ return "<font color=#0000ff>".&text('not', "$1")."</font>";
+ }
+elsif ($_[0] =~ /^\%(.*)$/) {
+ # Interface
+ return "<font color=#C0C0C0>".&text('iface', "$1")."</font>";
+ }
+elsif ($_[0] =~ /^\!\%(.*)$/) {
+ # Negated interface
+ return "<font color=#C0C0C0>".&text('iface_not', "$1")."</font>";
+ }
+elsif ($_[0] eq '*') {
+ # Anywhere
+ return $text{'anywhere'};
+ }
+elsif ($_[0] eq '!*') {
+ # Nowhere
+ return $text{'nowhere'};
+ }
+elsif ($_[0] =~ /^\!(.*\/.*)$/) {
+ # Negated network address
+ return &text('not', "<tt><font color=#008800>$1</font></tt>");
+ }
+elsif ($_[0] =~ /^\!([0-9\.]+)\-([0-9]+)$/) {
+ # Negated address range
+ return &text('not', "<tt><font color=#ffff00>$1-$2</font></tt>");
+ }
+elsif ($_[0] =~ /^\!(.*)$/) {
+ # Negated hostname or IP
+ return &text('not', "<tt>$1</tt>");
+ }
+elsif ($_[0] =~ /^(.*\/.*)$/) {
+ # Network address
+ return "<tt><font color=#008800>$_[0]</font></tt>";
+ }
+elsif ($_[0] =~ /^([0-9\.]+)\-([0-9]+)$/) {
+ # Address range
+ return "<tt><font color=#ffff00>$1-$2</font></tt>";
+ }
+else {
+ # Hostname or IP
+ return "<tt>$_[0]</tt>";
+ }
+}
+
+# group_names(string)
+sub group_names
+{
+return join(", ", map { &group_name($_) } split(/\s+/, $_[0]));
+}
+
+# group_names_link(dest, [from], [direction])
+sub group_names_link
+{
+local $g;
+local @rv;
+foreach $g (split(/\s+/, $_[0])) {
+ if ($g =~ /^\@(.*)$/ || $g =~ /^\!\@(.*)$/) {
+ push(@rv, "<a href='edit_group.cgi?name=$1&from=$_[1]'>".
+ &group_name($g, $_[2])."</a>");
+ }
+ else {
+ push(@rv, &group_name($g, $_[2]));
+ }
+ }
+return join(", ", @rv);
+}
+
+# group_input(name, [value], [blankoption], [multiple])
+sub group_input
+{
+local @groups = &list_groups();
+return undef if (!@groups);
+local $rv = $_[3] ? "<select name=$_[0] size=5 multiple>"
+ : "<select name=$_[0]>\n";
+if ($_[2]) {
+ $rv .= sprintf "<option value='' %s>%s\n",
+ $_[1] ? "" : "selected", $_[2] == 2 ? $text{'other'} : " ";
+ }
+local $g;
+local %vals = map { $_, 1 } split(/\s+/, $_[1]);
+foreach $g (@groups) {
+ $rv .= sprintf "<option value=%s %s>%s\n",
+ $g->{'name'}, $vals{$g->{'name'}} ? "selected" : "",
+ $g->{'name'};
+ }
+$rv .= "</select>\n";
+return $rv;
+}
+
+# service_input(name, value, [blankoption], [multiple], [norange])
+sub service_input
+{
+local @servs = &list_services();
+local %got = map { $_, 1 } split(/,/, $_[1]);
+local $rv = $_[3] ? "<select name=$_[0] size=5 multiple>"
+ : "<select name=$_[0]>\n";
+if ($_[2]) {
+ $rv .= sprintf "<option value='' %s>%s\n",
+ $_[1] ? "" : "selected", $_[2] == 2 ? $text{'other'} : " ";
+ }
+local $s;
+foreach $s (@servs) {
+ local $desc;
+ local @up = &unique(@{$s->{'protos'}});
+ local $i;
+ if (@up == 1) {
+ $desc = uc($up[0])." ".join(", ", @{$s->{'ports'}});
+ }
+ else {
+ for($i=0; $i<@{$s->{'protos'}}; $i++) {
+ $desc .= ", " if ($desc);
+ $desc .= uc($s->{'protos'}->[$i])."/".
+ $s->{'ports'}->[$i];
+ }
+ }
+ for($i=0; $i<@{$s->{'others'}}; $i++) {
+ $desc .= ", " if ($desc);
+ $desc .= $s->{'others'}->[$i];
+ }
+ $rv .= sprintf "<option value=%s %s>%s%s\n",
+ $s->{'name'}, $got{$s->{'name'}} ? "selected" : "",
+ $s->{'name'}, $_[4] ? "" : " ($desc)";
+ }
+$rv .= "</select>\n";
+return $rv;
+}
+
+# action_input(name, value, [select-mode])
+sub action_input
+{
+local $rv;
+local $a;
+if ($_[2]) {
+ $rv .= "<select name=$_[0]>\n";
+ foreach $a (@actions) {
+ $rv .= sprintf "<option value=%s %s>%s\n",
+ $a, $_[1] eq $a ? "selected" : "",
+ $text{"rule_".$a};
+ }
+ $rv .= "</select>\n";
+ }
+else {
+ foreach $a (@actions) {
+ $rv .= sprintf "<input type=radio name=%s value=%s %s>%s\n",
+ $_[0], $a, $_[1] eq $a ? "checked" : "",
+ $text{"rule_".$a};
+ }
+ }
+return $rv;
+}
+
+
+# protocol_input(name, value)
+sub protocol_input
+{
+local @protos = ( 'tcp', 'udp', 'icmp', 'ip' );
+#open(PROTOS, "/etc/protocols");
+#while(<PROTOS>) {
+# s/\r|\n//g;
+# s/#.*$//;
+# push(@protos, $1) if (/^(\S+)\s+(\d+)/);
+# }
+#close(PROTOS);
+local $p;
+local $rv = "<select name=$_[0]>\n";
+$rv .= sprintf "<option value='' %s> \n",
+ $_[1] eq '' ? "selected" : "";
+foreach $p (&unique(@protos)) {
+ $rv .= sprintf "<option value='%s' %s>%s\n",
+ $p, $_[1] eq $p && $p ? "selected" : "",
+ uc($p) || "-------";
+ }
+$rv .= "</select>\n";
+return $rv;
+}
+
+sub valid_host
+{
+
+if (&check_ipaddress($_[0])) {
+ return 1;
+ }
+elsif (gethostbyname($_[0])) {
+ return 2;
+ }
+elsif (&check_netaddress($_[0])) {
+ #$_[0] =~ /^(\d+)\.(\d+)\.(\d+)\.(\d+)\/(\d+)$/) {
+ return 3;
+ }
+elsif ($_[0] =~ /^(\d+)\.(\d+)\.(\d+)\.(\d+)\-(\d+)$/) {
+ return 4;
+ }
+else {
+ return 0;
+ }
+}
+
+# iface_input(name, value, [realonly], [nother], [nonemode])
+sub iface_input
+{
+local @ifaces;
+if (&foreign_check("net")) {
+ &foreign_require("net", "net-lib.pl");
+ local $i;
+ foreach $i (&net::active_interfaces(), &net::boot_interfaces()) {
+ push(@ifaces, $i->{'fullname'})
+ if (!$_[2] || $i->{'virtual'} eq '');
+ }
+ @ifaces = &unique(@ifaces);
+ }
+if (@ifaces) {
+ local $rv = "<select name=$_[0]>\n";
+ local ($i, $found);
+ if ($_[4]) {
+ $rv .= sprintf "<option value='' %s>%s\n",
+ $_[1] eq "" ? "selected" : "", "<None>";
+ $found++ if ($_[1] eq "");
+ }
+ foreach $i (@ifaces) {
+ $rv .= sprintf "<option value=%s %s>%s\n",
+ $i, $_[1] eq $i ? "selected" : "", $i;
+ $found++ if ($_[1] eq $i);
+ }
+ if ($_[3]) {
+ $rv .= "<option value=$_[1] selected>$_[1]\n" if (!$found && $_[1]);
+ }
+ else {
+ $rv .= sprintf "<option value='' %s> %s\n",
+ !$found && $_[1] ? "selected" : "", $text{'rule_oifc'};
+ $rv .= "</select>\n";
+ $rv .= sprintf "<input name=$_[0]_other size=6 value='%s'>\n",
+ !$found ? $_[1] : "";
+ }
+ return $rv;
+ }
+else {
+ return "<input name=$_[0] size=6 value='$_[1]'>";
+ }
+}
+
+# time_input(name, [value])
+sub time_input
+{
+local @times = &list_times();
+return undef if (!@times);
+local $rv = "<select name=$_[0]>\n";
+local $t;
+foreach $t (@times) {
+ $rv .= sprintf "<option value=%s %s>%s\n",
+ $t->{'name'}, $t->{'name'} eq $_[1] ? "selected" : "",
+ $t->{'name'};
+ }
+$rv .= "</select>\n";
+return $rv;
+}
+
+# get_nat([file])
+sub get_nat
+{
+local ($iface, @nets, @maps);
+open(NAT, $_[0] || $nat_file) || return ( );
+chop($iface = <NAT>);
+while(<NAT>) {
+ s/\r|\n//g;
+ if (/^(\S+)$/) {
+ push(@nets, $_);
+ }
+ elsif (/^(\S+)\t+(\S+)\t+(\S+)$/) {
+ push(@maps, [ $1, $2, $3 ]);
+ }
+ elsif (/^(\S+)\t+(\S+)$/) {
+ push(@maps, [ $1, $2 ]);
+ }
+ }
+close(NAT);
+return ( $iface, @nets, @maps );
+}
+
+# save_nat(iface, net, ..)
+sub save_nat
+{
+open(NAT, ">$nat_file");
+print NAT shift(@_),"\n";
+local $n;
+foreach $n (@_) {
+ if (ref($n)) {
+ print NAT join("\t", @$n),"\n";
+ }
+ else {
+ print NAT $n,"\n";
+ }
+ }
+close(NAT);
+}
+
+sub save_nat2
+{
+open(NAT, ">$nat2_file");
+print NAT shift(@_),"\n";
+local $n;
+foreach $n (@_) {
+ if (ref($n)) {
+ print NAT join("\t", @$n),"\n";
+ }
+ else {
+ print NAT $n,"\n";
+ }
+ }
+close(NAT);
+}
+
+
+# get_pat([file])
+sub get_pat
+{
+local ($defiface, @forwards);
+open(PAT, $_[0] || $pat_file) || return ( );
+chop($defiface = <PAT>);
+while(<PAT>) {
+ s/\r|\n//g;
+ if (/^(\S+)\t+(\S+)\t+(\S+)$/) {
+ push(@forwards, { 'service' => $1,
+ 'host' => $2,
+ 'iface' => $3 });
+ }
+ elsif (/^(\S+)\t+(\S+)$/) {
+ push(@forwards, { 'service' => $1,
+ 'host' => $2,
+ 'iface' => $defiface });
+ }
+ }
+close(PAT);
+return @forwards;
+}
+
+# save_pat(forward, ...)
+sub save_pat
+{
+open(PAT, ">$pat_file");
+print PAT (@_ ? $_[0]->{'iface'} : ""),"\n";
+local $f;
+foreach $f (@_) {
+ if ($f->{'iface'}) {
+ print PAT "$f->{'service'}\t$f->{'host'}\t$f->{'iface'}\n";
+ }
+ else {
+ print PAT "$f->{'service'}\t$f->{'host'}\n";
+ }
+ }
+close(PAT);
+}
+
+# get_spoof([file])
+sub get_spoof
+{
+local ($iface, @nets);
+open(PAT, $_[0] || $spoof_file) || return ( );
+chop($iface = <PAT>);
+while(<PAT>) {
+ s/\r|\n//g;
+ if (/^(\S+)$/) {
+ push(@nets, $_);
+ }
+ }
+close(PAT);
+return ( $iface, @nets );
+}
+
+# save_spoof(iface, net, ...)
+sub save_spoof
+{
+open(PAT, ">$spoof_file");
+print PAT shift(@_),"\n";
+local $s;
+foreach $s (@_) {
+ print PAT "$s\n";
+ }
+close(PAT);
+}
+
+# get_syn([file])
+sub get_syn
+{
+local ($flood, $spoof, $fin);
+open(SYN, $_[0] || $syn_file) || return ( );
+chop($flood = <SYN>);
+chop($spoof = <SYN>);
+chop($fin = <SYN>);
+close(SYN);
+return ($flood, $spoof, $fin);
+}
+
+# save_syn(flood, spoof, fin)
+sub save_syn
+{
+open(SYN, ">$syn_file");
+print SYN int($_[0]),"\n";
+print SYN int($_[1]),"\n";
+print SYN int($_[2]),"\n";
+close(SYN);
+}
+
+# list_times([file])
+# Returns a list of all time ranges
+sub list_times
+{
+local @rv;
+open(TIMES, $_[0] || $times_file);
+while(<TIMES>) {
+ s/\r|\n//g;
+ local @t = split(/\t/, $_);
+ if (@t >= 3) {
+ local $time = { 'index' => scalar(@rv),
+ 'name' => $t[0],
+ 'hours' => $t[1],
+ 'days' => $t[2] };
+ push(@rv, $time);
+ }
+ }
+close(TIMES);
+return @rv;
+}
+
+# save_times(time, ...)
+# Updates the time ranges list
+sub save_times
+{
+open(TIMES, ">$times_file");
+local $t;
+foreach $t (@_) {
+ print TIMES $t->{'name'},"\t",
+ $t->{'hours'},"\t",
+ $t->{'days'},"\n";
+ }
+close(TIMES);
+}
+
+# activate_interface(base, ip)
+sub activate_interface
+{
+&foreign_require("net", "net-lib.pl");
+local @active = &net::active_interfaces();
+local ($base) = grep { $_->{'fullname'} eq $_[0] } @active;
+local ($already) = grep { $_->{'address'} eq $_[1] } @active;
+if ($base && !$already) {
+ # Work out an interface number
+ local $vmax = 0;
+ foreach $a (@active) {
+ $vmax = $a->{'virtual'}
+ if ($a->{'name'} eq $base->{'name'} &&
+ $a->{'virtual'} > $vmax);
+ }
+
+ # Activate now
+ $virt = { 'address' => $_[1],
+ 'netmask' => $base->{'netmask'},
+ 'broadcast' => $base->{'broadcast'},
+ 'name' => $base->{'name'},
+ 'virtual' => $vmax+1,
+ 'up' => 1 };
+ $virt->{'fullname'} = $virt->{'name'}.":".$virt->{'virtual'};
+ &net::activate_interface($virt);
+
+ # Save for later
+ open(ACTIVE, ">>$active_interfaces");
+ print ACTIVE "$virt->{'fullname'}\t$virt->{'address'}\n";
+ close(ACTIVE);
+ }
+}
+
+# deactivate_all_interfaces()
+# Shuts down all interfaces activated by the above function
+sub deactivate_all_interfaces
+{
+&foreign_require("net", "net-lib.pl");
+open(ACTIVE, $active_interfaces);
+while(<ACTIVE>) {
+ if (/^(\S+)\s+(\S+)/) {
+ local $addr = $2;
+ local @active = &net::active_interfaces();
+ local ($virt) = grep { $_->{'address'} eq $addr } @active;
+ if ($virt && $virt->{'virtual'} ne '') {
+ &net::deactivate_interface($virt);
+ }
+ }
+ }
+close(ACTIVE);
+unlink($active_interfaces);
+}
+
+sub apply_button
+{
+if (&can_edit("apply")) {
+ return "<a href='apply.cgi?return=1'>$text{'apply_button'}</a>";
+ }
+else {
+ return undef;
+ }
+}
+
+# expand_hosts(names, &groups)
+# Give a list of host or group names, expands them to hosts
+sub expand_hosts
+{
+local ($e, @rv);
+local %groups = map { $_->{'name'}, $_ } @{$_[1]};
+foreach $e (split(/\s+/, $_[0])) {
+ if ($e =~ /^\@(.*)$/) {
+ # Expand to all group members
+ local $group = $groups{$1};
+ foreach $m (@{$group->{'members'}}) {
+ push(@rv, &expand_hosts($m, $_[1]));
+ }
+ }
+ elsif ($e =~ /^(\d+)\.(\d+)\.(\d+)\.(\d+)\-(\d+)$/) {
+ # Expand to all IPs in range
+ push(@rv, map { "$1.$2.$3.$_" } ($4 .. $5) );
+ }
+ else {
+ # Just a single IP, host or network
+ push(@rv, $e);
+ }
+ }
+return @rv;
+}
+
+# can_use(feature)
+sub can_use
+{
+return 1 if ($read_access{'*'} || $edit_access{'*'});
+return $read_access{$_[0]} || $edit_access{$_[0]};
+}
+
+# can_edit(feature)
+sub can_edit
+{
+return 0 if (!&can_use($_[0]));
+return $edit_access{'*'} || $edit_access{$_[0]};
+}
+
+# can_use_error(feature)
+sub can_use_error
+{
+&can_use($_[0]) || &error($text{$_[0]."_ecannot"} ||
+ &text('ecannot', $text{$_[0]."_title"}));
+}
+
+# can_edit_error(feature)
+sub can_edit_error
+{
+&can_edit($_[0]) || &error($text{$_[0]."_ecannot"} ||
+ &text('ecannot', $text{$_[0]."_title"}));
+}
+
+# can_edit_disable(feature)
+sub can_edit_disable
+{
+if (!&can_edit($_[0])) {
+ print "<script>\n";
+ print "l = document.forms[0].elements;\n";
+ print "for(i=0; i<l.length; i++) {\n";
+ print " if (l[i].name != \"burn\" && l[i].name != \"test\" &&\n";
+ print " l[i].type != \"hidden\") {\n";
+ print " l[i].disabled = true;\n";
+ print " }\n";
+ print "}\n";
+ print "</script>\n";
+ }
+}
+
+# protocol_name(proto, port)
+sub protocol_name
+{
+local $pr = uc($_[0]);
+local $pt = $_[1];
+if ($pr eq "TCP") {
+ return "<font color=#0000ff>$pr/$pt</font>";
+ }
+elsif ($pr eq "UDP") {
+ return "<font color=#008800>$pr/$pt</font>";
+ }
+elsif ($pr eq "ICMP") {
+ return "<font color=#f00000>$pr/$pt</font>";
+ }
+else {
+ return "$pr/$pt";
+ }
+}
+
+# protocol_names(comma-list, [&services])
+sub protocol_names
+{
+if ($_[0] eq "*") {
+ return $text{'rule_any'};
+ }
+else {
+ local %sn = map { $_->{'name'}, $_ }
+ ( $_[1] ? @{$_[1]} : &list_services() );
+ local $sn;
+ local @rv;
+ local ($editServO,$editServC);
+ foreach $sn (split(/,/, $_[0])) {
+ local $serv = $sn{$sn};
+ if (!$serv->{'standard'}){
+ $editServO="<a href='edit_service.cgi?name=".$serv->{'name'}."'>";
+ $editServC="</a>";
+ } else {
+ $editServO="";
+ $editServC="";
+ }
+ local $pr = @{$serv->{'protos'}} == 1 ? uc($serv->{'protos'}->[0]) : undef;
+ if ($pr eq "TCP") {
+ push(@rv, "$editServO<font color=#0000ff>$sn</font>$editServC");
+ }
+ elsif ($pr eq "UDP") {
+ push(@rv, "$editServO<font color=#008800>$sn</font>$editServC");
+ }
+ elsif ($pr eq "ICMP") {
+ push(@rv, "$editServO<font color=#f00000>$sn</font>$editServC");
+ }
+ else {
+ push(@rv, "$editServO $sn $editServC");
+ }
+ }
+ return join(", ", @rv);
+ }
+}
+
+# my_address_in(address/network)
+# Returns this system's IP address in some network
+sub my_address_in
+{
+local $net = $_[0];
+$net =~ s/^\!\s+//;
+if ($net =~ /[a-z]/i) {
+ $net = &to_ipaddress($net);
+ }
+$net =~ s/^(\d+\.\d+\.\d+).*$/$1/;
+&foreign_require("net", "net-lib.pl");
+local @ifaces = &net::active_interfaces();
+local $i;
+local $primary;
+foreach $i (@ifaces) {
+ if ($i->{'up'}) {
+ if (!$primary && $i->{'fullname'} !~ /^lo/) {
+ $primary = $i->{'address'};
+ }
+ local $addr = $i->{'address'};
+ $addr =~ s/^(\d+\.\d+\.\d+).*$/$1/;
+ if ($addr eq $net) {
+ return $i->{'address'};
+ }
+ }
+ }
+return $primary;
+}
+
+sub has_ipsec
+{
+return &foreign_installed("ipsec", 1);
+}
+
+# backup_firewall(&what, file, [password])
+# Backs up the firewall to some file
+sub backup_firewall
+{
+local ($mode, @dest) = &parse_backup_dest($_[1]);
+local $file = $mode == 1 ? $dest[0] : &tempname();
+local $ipsec_tmp = "$module_config_directory/ipsec.conf";
+local $secrets_tmp = "$module_config_directory/ipsec.secrets";
+local $users_tmp = "$module_config_directory/miniserv.users";
+local $acl_tmp = "$module_config_directory/webmin.acl";
+local $w;
+local (@files, @delfiles);
+foreach $w (@{$_[0]}) {
+ if ($w eq "ipsec") {
+ # Copy the ipsec.conf files
+ if (&has_ipsec()) {
+ system("cp $ipsec::config{'file'} $ipsec_tmp");
+ system("cp $ipsec::config{'secrets'} $secrets_tmp");
+ push(@delfiles, "ipsec.conf", "ipsec.secrets");
+ }
+ }
+ elsif ($w eq "users") {
+ # Copy all Webmin users
+ opendir(DIR, $module_config_directory);
+ push(@files, grep { /\.acl$/ } readdir(DIR));
+ closedir(DIR);
+ system("cp $config_directory/miniserv.users $users_tmp");
+ system("cp $config_directory/webmin.acl $acl_tmp");
+ push(@delfiles, "miniserv.users", "webmin.acl");
+ }
+ else {
+ push(@files, $w) if (-r "$module_config_directory/$w");
+ }
+ }
+push(@files, @delfiles);
+local $what = join(" ", @files);
+return $text{'backup_ewhat2'} if (!$what);
+local $pass = $_[2] ? "-P '$_[2]'" : "";
+local $out = &backquote_logged("(cd $module_config_directory ; zip -r $pass '$file' $what) 2>&1");
+return "<pre>$out</pre>" if ($?);
+unlink(map { "$module_config_directory/$_" } @delfiles);
+
+# Send to destination
+if ($mode == 2) {
+ # FTP somewhere
+ local $err;
+ &ftp_upload($dest[2], $dest[3], $file, \$err, undef, $dest[0], $dest[1]);
+ unlink($file);
+ return $err if ($err);
+ }
+elsif ($mode == 3) {
+ # Email somewhere
+ $data = `cat $file`;
+ unlink($file);
+ $host = &get_system_hostname();
+ $body = "The backup of the firewall configuration on $host is attached to this email.\n";
+ local $mail = { 'headers' =>
+ [ [ 'From', $config{'from'} || "webmin\@$host" ],
+ [ 'To', $dest[0] ],
+ [ 'Subject', "Firewall backup" ] ],
+ 'attach' =>
+ [ { 'headers' => [ [ 'Content-type', 'text/plain' ] ],
+ 'data' => $body },
+ { 'headers' => [ [ 'Content-type', 'application/zip' ],
+ [ 'Content-Transfer-Encoding', 'base64' ] ],
+ 'data' => $data } ] };
+ $main::errors_must_die = 1;
+ if (&foreign_check("mailboxes")) {
+ &foreign_require("mailboxes", "mailboxes-lib.pl");
+ eval { &mailboxes::send_mail($mail); };
+ }
+ else {
+ &foreign_require("sendmail", "sendmail-lib.pl");
+ &foreign_require("sendmail", "boxes-lib.pl");
+ eval { &sendmail::send_mail($mail); };
+ }
+ return $@ if ($@);
+ }
+
+return undef;
+}
+
+sub check_zip
+{
+&has_command("zip") && &has_command("unzip") ||
+ &error($text{'backup_ezipcmd'});
+}
+
+sub find_backup_job
+{
+&foreign_require("cron", "cron-lib.pl");
+local @jobs = &cron::list_cron_jobs();
+local ($job) = grep { $_->{'user'} eq 'root' &&
+ $_->{'command'} eq $cron_cmd } @jobs;
+return $job;
+}
+
+sub parse_backup_dest
+{
+if ($_[0] =~ /^mailto:(.*)/) {
+ return (3, $1);
+ }
+elsif ($_[0] =~ /^ftp:\/\/([^:]*):([^@]*)@([^\/]+)(\/.*)$/) {
+ return (2, $1, $2, $3, $4);
+ }
+elsif ($_[0] =~ /^\//) {
+ return (1, $_[0]);
+ }
+else {
+ return (0);
+ }
+}
+
+# ftp_upload(host, file, srcfile, [&error], [&callback], [user, pass])
+# Download data from a local file to an FTP site
+sub ftp_upload
+{
+local($buf, @n);
+local $cbfunc = $_[4];
+
+$download_timed_out = undef;
+local $SIG{ALRM} = "download_timeout";
+alarm(60);
+
+# connect to host and login
+&open_socket($_[0], 21, "SOCK", $_[3]) || return 0;
+alarm(0);
+if ($download_timed_out) {
+ if ($_[3]) { ${$_[3]} = $download_timed_out; return 0; }
+ else { &error($download_timed_out); }
+ }
+&ftp_command("", 2, $_[3]) || return 0;
+if ($_[5]) {
+ # Login as supplied user
+ local @urv = &ftp_command("USER $_[5]", [ 2, 3 ], $_[3]);
+ @urv || return 0;
+ if (int($urv[1]/100) == 3) {
+ &ftp_command("PASS $_[6]", 2, $_[3]) || return 0;
+ }
+ }
+else {
+ # Login as anonymous
+ local @urv = &ftp_command("USER anonymous", [ 2, 3 ], $_[3]);
+ @urv || return 0;
+ if (int($urv[1]/100) == 3) {
+ &ftp_command("PASS root\@".&get_system_hostname(), 2,
+ $_[3]) || return 0;
+ }
+ }
+&$cbfunc(1, 0) if ($cbfunc);
+
+&ftp_command("TYPE I", 2, $_[3]) || return 0;
+
+# get the file size and tell the callback
+local @st = stat($_[2]);
+if ($cbfunc) {
+ &$cbfunc(2, $st[7]);
+ }
+
+# send the file
+local $pasv = &ftp_command("PASV", 2, $_[3]);
+defined($pasv) || return 0;
+$pasv =~ /\(([0-9,]+)\)/;
+@n = split(/,/ , $1);
+&open_socket("$n[0].$n[1].$n[2].$n[3]", $n[4]*256 + $n[5], "CON", $_[3]) || return 0;
+&ftp_command("STOR $_[1]", 1, $_[3]) || return 0;
+
+# transfer data
+local $got;
+open(PFILE, $_[2]);
+while(read(PFILE, $buf, 1024) > 0) {
+ print CON $buf;
+ $got += length($buf);
+ &$cbfunc(3, $got) if ($cbfunc);
+ }
+close(PFILE);
+close(CON);
+if ($got != $st[7]) {
+ if ($_[3]) { ${$_[3]} = "Upload incomplete"; return 0; }
+ else { &error("Upload incomplete"); }
+ }
+&$cbfunc(4) if ($cbfunc);
+
+# finish off..
+&ftp_command("", 2, $_[3]) || return 0;
+&ftp_command("QUIT", 2, $_[3]) || return 0;
+close(SOCK);
+
+return 1;
+}
+
+# lock_itsecur_files()
+# Lock all firewall config files
+sub lock_itsecur_files
+{
+local $f;
+foreach $f (@config_files) {
+ &lock_file($f);
+ }
+}
+
+# unlock_itsecur_files()
+# Unlock all firewall config files
+sub unlock_itsecur_files
+{
+local $f;
+foreach $f (@config_files) {
+ &unlock_file($f);
+ }
+}
+
+sub remote_webmin_log
+{
+if ($config{'remote_log'} && !fork()) {
+ # Disconnect from TTY
+ untie(*STDIN);
+ untie(*STDOUT);
+ untie(*STDERR);
+ close(STDIN);
+ close(STDOUT);
+ close(STDERR);
+
+ # Send log to remote host
+ &remote_foreign_require($config{'remote_log'}, $module_name,
+ "itsecur-lib.pl");
+ local $d;
+ foreach $d (@main::locked_file_diff) {
+ &remote_foreign_call($config{'remote_log'}, $module_name,
+ "additional_log", $d->{'type'},
+ $d->{'object'}, $d->{'data'});
+ }
+ local $script_name = $0 =~ /([^\/]+)$/ ? $1 : '';
+ &remote_foreign_call($config{'remote_log'}, $module_name,
+ "webmin_log", @_[0..3], $module_name,
+ &get_system_hostname(),
+ $script_name,
+ $ENV{'REMOTE_HOST'});
+
+ exit(0);
+ }
+&webmin_log(@_);
+}
+
+# automatic_backup()
+# If a change has been made and an automatic backup directory set, save the
+# module's configuration
+sub automatic_backup
+{
+return if (!$config{'auto_dir'} || !-d $config{'auto_dir'});
+
+# Backup to a temp file
+local $temp = &tempname();
+local $err = &backup_firewall(\@backup_opts, $temp, undef);
+if ($err) {
+ unlink($temp);
+ return 0;
+ }
+
+# Make sure this backup is actually different from the last
+local $linkfile = "$config{'auto_dir'}/latest.zip";
+if (-r $linkfile) {
+ local $out = `diff '$config{'auto_dir'}/latest.zip' '$temp' 2>&1`;
+ if ($? == 0) {
+ # No change!
+ unlink($temp);
+ return 0;
+ }
+ }
+
+# Copy to directory, and update latest link
+use POSIX;
+local $newfile = strftime "$config{'auto_dir'}/firewall.%Y-%m-%d-%H:%M:%S.zip",
+ localtime(time());
+system("mv '$temp' '$newfile'");
+unlink($linkfile);
+symlink($newfile, $linkfile);
+
+return 1;
+}
+
+# parse_all_logs([base-only])
+# Returns a list of all log structures, newest first
+sub parse_all_logs
+{
+local $baselog = $config{'log'} || &get_log_file();
+local @rv;
+foreach $log ($config{'all_files'} && !$_[0] ? &all_log_files($baselog)
+ : ($baselog)) {
+ if ($log =~ /\.gz$/i) {
+ open(LOG, "gunzip -c ".quotemeta($log)." |");
+ }
+ elsif ($log =~ /\.Z$/i) {
+ open(LOG, "uncompress -c ".quotemeta($log)." |");
+ }
+ else {
+ open(LOG, $log);
+ }
+ while(<LOG>) {
+ local $info = &parse_log_line($_);
+ push(@rv, $info) if ($info);
+ }
+ close(LOG);
+ }
+return reverse(@rv);
+}
+
+# all_log_files(file)
+sub all_log_files
+{
+$_[0] =~ /^(.*)\/([^\/]+)$/;
+local $dir = $1;
+local $base = $2;
+local ($f, @rv);
+opendir(DIR, $dir);
+foreach $f (readdir(DIR)) {
+ if ($f =~ /^\Q$base\E/ && -f "$dir/$f") {
+ push(@rv, "$dir/$f");
+ }
+ }
+closedir(DIR);
+return @rv;
+}
+
+@search_fields = ("src", "dst", "dst_iface", "proto", "src_port", "dst_port",
+ "first", "last", "action", "rule");
+
+# filter_logs(&logs, &in, [&searchvars])
+sub filter_logs
+{
+local @logs = @{$_[0]};
+local %in = %{$_[1]};
+local $f;
+local @servs = &list_services();
+local @groups = &list_groups();
+local %servs = map { $_->{'name'}, $_ } @servs;
+foreach $f (@search_fields) {
+ if ($in{$f."_mode"}) {
+ # This search applies .. find all suitable match types
+ local %matches;
+ local $tm;
+ if (($f eq "src_port" || $f eq "dst_port") && $in{$f."_what"}) {
+ # Lookup all ports and protocols
+ local ($protos, $ports) =
+ &combine_services($in{$f."_what"}, \%servs);
+ local $i;
+ for($i=0; $i<@$protos; $i++) {
+ if ($ports->[$i] =~ /^(\d+)\-(\d+)$/) {
+ local $p;
+ foreach $p ($1 .. $2) {
+ $matches{lc($protos->[$i]),$p}++;
+ }
+ }
+ else {
+ $matches{lc($protos->[$i]),$ports->[$i]}++;
+ }
+ }
+ }
+ elsif (($f eq "src_port" || $f eq "dst_port") && !$in{$f."_what"}) {
+ # One specified port number
+ $matches{$in{$f."_other"}}++;
+ }
+ elsif (($f eq "src" || $f eq "dst") && $in{$f."_what"}) {
+ # Lookup all hosts
+ local @hosts = &expand_hosts(
+ '@'.$in{$f."_what"}, \@groups);
+ local $h;
+ foreach $h (@hosts) {
+ local $eh;
+ foreach $eh (&expand_net($h)) {
+ $matches{$eh}++;
+ }
+ }
+ }
+ elsif (($f eq "src" || $f eq "dst") && !$in{$f."_what"}) {
+ # One other host
+ local $eh;
+ foreach $eh (&expand_net($in{$f."_other"})) {
+ $matches{$eh}++;
+ }
+ }
+ elsif ($f eq "first" || $f eq "last") {
+ # A time range
+ eval { $tm = timelocal(
+ 0, $in{$f."_min"}, $in{$f."_hour"},
+ $in{$f."_day"}, $in{$f."_month"}-1,
+ $in{$f."_year"}-1900); };
+ }
+ else {
+ $matches{lc($in{$f."_what"})}++;
+ }
+
+ if ($f eq "first" && $tm) {
+ # Find those after start minute
+ @logs = grep { $_->{'time'} >= $tm } @logs;
+ }
+ elsif ($f eq "last" && $tm) {
+ # Find those before end minute
+ @logs = grep { $_->{'time'} < $tm+60 } @logs;
+ }
+ elsif ($in{$f."_mode"} == 1) {
+ # Find matching entries
+ @logs = grep {
+ $matches{lc($_->{$f})} ||
+ $matches{lc($_->{'proto'}),lc($_->{$f})} }
+ @logs;
+ }
+ elsif ($in{$f."_mode"} == 2) {
+ # Find non-matching entries
+ @logs = grep {
+ !($matches{lc($_->{$f})} ||
+ $matches{lc($_->{'proto'}),lc($_->{$f})}) }
+ @logs;
+ }
+ if ($_[2]) {
+ local $e;
+ foreach $e ("mode", "what", "other", "day",
+ "month", "year") {
+ if ($in{$f."_".$e} ne "") {
+ push(@{$_[2]}, $f."_".$e."=".
+ &urlize($in{$f."_".$e}));
+ }
+ }
+ }
+ }
+ }
+return @logs;
+}
+
+# expand_net(network)
+# Given a network address, hostname or IP address, returns a list of all
+# IP addresses it contains
+sub expand_net
+{
+if ($_[0] =~ /^(\d+)\.(\d+)\.(\d+)\.(\d+)\/(\d+)$/) {
+ local @rv;
+ local $first = ($1<<24) + ($2<<16) + ($3<<8) + ($4);
+ local $last = $first + (1<<(32-$5)) - 1;
+ for($ipnum=$first; $ipnum<=$last; $ipnum++) {
+ local @ip = ( ($ipnum>>24)&0xff,
+ ($ipnum>>16)&0xff,
+ ($ipnum>>8)&0xff,
+ ($ipnum)&0xff );
+ push(@rv, join(".", @ip));
+ }
+ return @rv;
+ }
+else {
+ return &to_ipaddress($_[0]);
+ }
+}
+
+# list_searches()
+# Returns a list of all saved searches
+sub list_searches
+{
+local @rv;
+opendir(DIR, $searches_dir);
+local $f;
+while($f = readdir(DIR)) {
+ if ($f ne "." && $f ne "..") {
+ local $search = &get_search($f);
+ push(@rv, $search) if ($search);
+ }
+ }
+closedir(DIR);
+return @rv;
+}
+
+sub get_search
+{
+local %search;
+if (&read_file("$searches_dir/$_[0]", \%search)) {
+ return \%search;
+ }
+else {
+ return undef;
+ }
+}
+
+# save_search(&search)
+sub save_search
+{
+mkdir($searches_dir, 0755);
+&write_file("$searches_dir/$_[0]->{'save_name'}", $_[0]);
+}
+
+# get_remote()
+# Returns the webmin servers object used for remote logging, or undef
+sub get_remote
+{
+return undef if (!$config{'remote_log'});
+&foreign_require("servers", "servers-lib.pl");
+local @servers = &servers::list_servers();
+local ($server) = grep { $_->{'host'} eq $config{'remote_log'} } @servers;
+return $server;
+}
+
+# save_remote(server, port, username, password, test, save)
+sub save_remote
+{
+local ($host, $port, $user, $pass, $test, $save) = @_;
+&foreign_require("servers", "servers-lib.pl");
+if ($host) {
+ # Enabling or updating
+ local @servers = &servers::list_servers();
+ local ($newserver) = grep { $_->{'host'} eq $host } @servers;
+ local $server = &get_remote();
+ if ($newserver && $server) {
+ if ($newserver ne $server) {
+ # Re-name would cause clash, so delete it
+ &servers::delete_server($newserver->{'id'});
+ }
+ }
+ elsif ($newserver && !$server) {
+ # Re-naming server
+ $server = $newserver;
+ }
+ elsif (!$newserver && $server) {
+ # Can just stick to old server
+ }
+ else {
+ # Totally new
+ $server = { 'id' => time(),
+ 'port' => $port,
+ 'ssl' => 0,
+ 'desc' => 'Firewall logging server',
+ 'type' => 'unknown',
+ 'fast' => 0 };
+ }
+ $server->{'host'} = $host;
+ $server->{'port'} = $port;
+ $server->{'user'} = $user;
+ $server->{'pass'} = $pass;
+ &servers::save_server($server);
+ $config{'remote_log'} = $server->{'host'};
+
+ if ($test) {
+ # Try a test connection
+ &remote_error_setup(\&test_error);
+ eval {
+ $SIG{'ALRM'} = sub { die "alarm\n" };
+ alarm(10);
+ &remote_foreign_require($server->{'host'}, "webmin",
+ "webmin-lib.pl");
+ alarm(0);
+ };
+ if ($@) {
+ &error(&text('remote_econnect', $text{'remote_etimeout'}));
+ }
+ elsif ($test_error_msg) {
+ &error(&text('remote_econnect', $test_error_msg));
+ }
+ }
+ }
+else {
+ # Disabling
+ delete($config{'remote_log'});
+ }
+if ($save) {
+ &lock_file($module_config_file);
+ &write_file($module_config_file, \%config);
+ &unlock_file($module_config_file);
+ }
+}
+
+sub test_error
+{
+$test_error_msg = join("", @_);
+}
+
+sub check_netaddress
+{
+return $_[0] =~ /^(\d+)\.(\d+)\.(\d+)\.(\d+)\/(\d+)$/ &&
+ $1 >= 0 && $1 <= 255 &&
+ $2 >= 0 && $2 <= 255 &&
+ $3 >= 0 && $3 <= 255 &&
+ $4 >= 0 && $4 <= 255 &&
+ $5 >= 0 && $5 <= 32;
+}
+
+sub is_one_host
+{
+local @groups = &list_groups();
+local @rv=&expand_hosts($_[0], \@groups);
+return $#rv;
+}
+
+1;
+
--- /dev/null
+index_title=Simple Firewall Creator
+index_version=Version $1
+index_iptables=Using iptables
+index_ipf=Using ipf
+index_apply=Apply Configuration
+index_applydesc=Click this button to apply the current firewall configuration, using the firewall installed on your operating system.
+index_bootup=Activate at boot
+index_bootupdesc=Change this option to control whether your firewall is activated at boot time or not.
+index_return=module index
+
+rules_title=Firewall Rules
+rules_none=No firewall rules have been defined yet. All traffic will be allowed through untouched.
+rules_add=Add a new firewall rule.
+rules_sadd=Add a new section separator.
+rules_return=rules list
+rules_log=and log
+rules_move=Move
+rules_service=Services
+rules_no=No.
+rules_enable=Enable Selected
+rules_disable=Disable Selected
+rules_logon=Log Selected
+rules_logoff=Don't Log Selected
+rules_delete=Delete Selected
+rules_desc=Comment
+
+rule_num=No.
+rule_desc=Rule comment
+rule_source=Source/Output Intf
+rule_dest=Destination/Input Intf
+rule_service=Destination services
+rule_action=Action
+rule_enabled=Enabled
+rule_any=Any
+rule_yes=$yes
+rule_no=<font color=#ff0000>$no</font>
+rule_accept=<font color=#00aa00>Accept</font>
+rule_allow=<font color=#00aa00>Allow</font>
+rule_drop=<font color=#ff0000>Drop</font>
+rule_deny=<font color=#ff0000>Deny</font>
+rule_reject=<font color=#ff4400>Reject</font>
+rule_ignore=Ignore
+rule_title1=Create Rule
+rule_title2=Edit Rule
+rule_title3=Insert Rule
+rule_header=Firewall rule details
+rule_anywhere=Any
+rule_anywheresource=Any host or network
+rule_anywheredest=Any host or network (except the firewall host)
+rule_host=Host or network
+rule_resolv=Resolve hostname to IP address
+rule_named=named
+rule_group=Host groups
+rule_iface=Network interface
+rule_oifc=Other..
+rule_anyserv=Any service
+rule_oneserv=Only services ..
+rule_log=Log as well?
+rule_not=Must not match
+rule_none=None
+rule_err=Failed to save rule
+rule_esource=Missing or invalid source hostname, IP address or network
+rule_edest=Missing or invalid destination hostname, IP address or network
+rule_before=Add Rule Before
+rule_after=Add Rule After
+rule_atpos=Position in list
+rule_end=End of list
+rule_pos=Before rule $1 ($2 -> $3)
+rule_spos=Before separator ($1)
+rule_ename=Invalid group name for host or network
+rule_egroups=No groups selected
+rule_eservices=No services selected
+rule_time=Times
+rule_anytime=Any
+rule_seltime=During selected time
+rule_rusured=Are you sure you want to delete this rule?
+rule_rusures=Are you sure you want to modify this rule?
+rule_goahead=Yes, Do It
+
+sep_title1=Create Section
+sep_title2=Edit Section
+sep_title3=Insert Section
+sep_header=Firewall rule list section details
+sep_desc=Section name
+sep_err=Failed to save section
+sep_edesc=Missing section name
+
+services_title=Services and Protocols
+services_header1=User-defined services
+services_header2=Standard services
+services_add=Add a new service.
+services_return=services list
+
+service_name=Name
+service_ports=Protocols and ports
+service_proto=Protocol
+service_port=Port or port range
+service_title1=Create Service
+service_title2=Edit Service
+service_header=User-defined service details
+service_err=Failed to save service
+service_ename=Missing service name
+service_eport=Missing or invalid TCP or UDP port number, range (like 100-200) or list of ports in row $1
+service_eicmp=Missing or invalid ICMP type number in row $1
+service_eip=Missing or invalid IP protocol number in row $1
+service_enone=No protocols and ports entered
+service_eclash=A service with the same name already exists
+service_eprotos=All protocols must be the same
+service_err2=Failed to delete service
+service_einuse=This service is being used by a rule
+service_einuse2=This service is a member of another service
+service_members=Member services
+
+groups_title=Host and Network Groups
+groups_add=Add a new host and network group.
+groups_none=No host groups have been defined yet.
+groups_return=groups list
+
+group_name=Group name
+group_members=Member hosts / networks
+group_members2=Member groups
+group_title1=Create Group
+group_title2=Edit Group
+group_header=Host and network group details
+group_err=Failed to save group
+group_ename=Missing or invalid group name
+group_eclash=A group with the same name already exists
+group_emember='$1' is not a valid hostname, IP address or network
+group_emembers=No group members entered
+group_neg=Negate
+group_err2=Failed to delete group
+group_einuse=This group is in use by a rule
+group_in_use_nat=This group is in use by a nat rule
+group_in_use_group=This group is in use by the group
+group_eself=A group cannot contain itself as a member
+group_resolv=Resolve hostnames to IP addresses
+group_eneg=Negation cannot be used with the network range $1
+
+anywhere=Anywhere
+anywhere_but=Anywhere except firewall
+nowhere=Nowhere
+not=Not $1
+iface=Interface $1
+iface_not=Not interface $1
+
+nat_title=Network Address Translation
+nat2_title=Failover NAT
+nat_desc=NAT status
+nat_nets=Networks to translate dynamically
+nat_excl=Except for destinations
+nat_disabled=Disabled
+nat_enabled=Enabled, on external interface
+nat_header=Current NAT settings
+nat_err=Failed to save NAT settings
+nat_eiface=Missing or invalid external interface
+nat_maps=Static external to internal translations
+nat_mapsdesc=If an external interface is selected,<br>a virtual interface will be added<br>to it for the external IP address<br>when the firewall is activated.
+nat_ext=External IP address
+nat_int=Internal IP address
+nat_virt=External interface
+nat_eext=The external name/group has more then 1 IP in row $1
+nat_eint=The internal name/group has more then 1 IP in row $1
+
+
+
+logs_title=View Live Firewall Log
+logs_viewing=Viewing the firewall log file $1 ..
+logs_download=Download
+
+authlogs_title=View Live Security Log
+
+pat_title=Port Address Translation
+pat_desc=PAT status
+pat_disabled=Disabled
+pat_enabled=Enabled, using external interface
+pat_forward=External services to forward
+pat_service=Service
+pat_host=To internal host
+pat_iface=External interface
+pat_header=Current PAT settings
+pat_err=Failed to save PAT settings
+pat_ehost=Missing or invalid internal host in row $1
+pat_eiface=Missing or invalid external interface in row $1
+
+spoof_title=Address Spoofing Prevention
+spoof_desc=Prevention status
+spoof_disabled=Disabled
+spoof_enabled=Enabled, on external interface
+spoof_nets=Internal networks
+spoof_header=Current spoofing prevention settings
+spoof_err=Failed to save address spoofing settings
+spoof_enet='$1' is not a valid network address - must be like 192.168.1.0/24
+spoof_enets=No internal networks were entered
+
+syn_title=Syn Attack Prevention
+syn_header=Current <tt>syn</tt> attack prevention setting
+syn_flood=Block <tt>syn</tt> flood attacks?
+syn_spoof=Block TCP connections that do not start with <tt>syn</tt> packet?
+syn_fin=Block TCP packets with both <tt>syn</tt> and <tt>fin</tt> set?
+
+apply_title=Applying Configuration
+apply_doing=Now applying firewall configuration ..
+apply_done=.. done. Firewall rules are now active, and routing has been enabled.
+apply_failed=.. failed : $1
+apply_return=previous page
+apply_button=Apply Configuration
+apply_ecannot=You are not allowed to apply the firewall configuration
+
+stop_title=Stopping Firewall
+stop_doing=Disabling firewall ..
+stop_done=.. done. All traffic will now be allowed, and but routing has been disabled.
+stop_failed=.. failed : $1
+
+backup_title=Backup Configuration
+backup_header=Firewall settings backup options
+backup_dest=Backup destination
+backup_dest0=Download in browser
+backup_dest1=Save to file on server
+backup_dest3=Email to address
+backup_dest2=FTP to server
+backup_ftpfile=save as file
+backup_ftpuser=Login as user
+backup_ftppass=with password
+backup_what=Objects to backup
+backup_ok=Save and Backup Now
+backup_save=Save Settings
+backup_err=Failed to backup configuration
+backup_edest=Missing or invalid backup destination file
+backup_edestdir=Directory for destination file does not exist
+backup_ewhat=Nothing selected to backup
+backup_ewhat2=None of the selected objects are in use on this firewall
+backup_done1=A backup of the firewall configuration has been successfully saved to $1.
+backup_done2=A backup of the firewall configuration has been successfully uploaded to the FTP server $1 as $2.
+backup_done3=A backup of the firewall configuration has been successfully emailed to $1.
+backup_donesched=The schedule backup settings have been saved.
+backup_pass=Password for backup file
+backup_nopass=None
+backup_epass=No password entered
+backup_ezipcmd=The <tt>zip</tt> and <tt>unzip</tt> commands are needed for the backup and restore functions to work, but are not installed on your system.
+backup_sched=Backup on schedule?
+backup_nosched=No
+backup_interval=Yes, on schedule
+backup_eemail=Missing or invalid-looking email address
+backup_eftphost=Missing or invalid FTP server
+backup_eftpfile=Missing FTP filename
+backup_eftpuser=Missing FTP login name
+
+restore_title=Restore Configuration
+restore_header=Firewall settings restore options
+restore_src=Backup source
+restore_src1=Uploaded file
+restore_src0=File on server
+restore_what=Objects to restore
+restore_ok=Restore Now
+restore_err=Failed to restore configuration
+restore_esrc=The source file on the server does not exist
+restore_efile=No uploaded file was selected
+restore_ewhat=Nothing selected to restore
+restore_etar=The selected backup source file is not in a valid format
+restore_cerr=The backup could not be restored, as the following consistency errors were detected in the restored configuration :
+restore_enat=The group <tt>$1</tt> used for Network Address Translation does not exist.
+restore_epat=The service <tt>$1</tt> used for Port Address Translation does not exist.
+restore_eservice=The service <tt>$1</tt> used in rule $2 does not exist.
+restore_etime=The time range <tt>$1</tt> used in rule $2 does not exist.
+restore_egroup=The group <tt>$1</tt> used in rule $2 does not exist.
+restore_done=The firewall configuration has been successfully restored from the chosen backup file.
+restore_pass=Password for backup file
+restore_epass=Password is incorrect
+restore_epass2=The backup is password protected, but no password was entered
+
+acl_features=Editable module features
+acl_rfeatures=Viewable module features
+acl_all=All
+acl_sel=Selected below ..
+ecannot=You are not allowed to use the <tt>$1</tt> page
+acl_apply=Apply Configuration
+acl_bootup=Activate at boot time
+acl_edit=Can edit firewall settings?
+
+users_desc=The users listed on this page have access to firewall module, with the selected privileges.
+users_title=Firewall Users
+users_add=Add a new firewall user.
+users_name=Username
+users_ips=Allowed IPs
+users_enabled=Enabled?
+users_allow=Only $1
+users_deny=All except $1
+users_all=All
+users_edit=Can edit?
+users_none=No users with access to only the firewall have been created yet.
+users_return=user list
+
+user_title1=Create User
+user_title2=Edit User
+user_header=Firewall user details
+user_name=Login name
+user_pass=Password
+user_same=Don't change
+user_change=Set to
+user_enabled=Login allowed?
+user_err=Failed to save user
+user_ename=Missing username
+user_mods=Available Webmin modules
+
+bootup_ecannot=You are not allowed to enable or disable the firewall at boot time
+
+log_create_rule=Created rule for $1 to $2
+log_update_rule=Modified rule for $1 to $2
+log_delete_rule=Deleted rule for $1 to $2
+log_move_rule=Moved rule for $1 to $2
+log_create_service=Created service named $1
+log_update_service=Modified service named $1
+log_delete_service=Deleted service named $1
+log_create_group=Created host group named $1
+log_update_group=Modified host group named $1
+log_delete_group=Deleted host group named $1
+log_create_user=Created firewall user $1
+log_update_user=Modified firewall user $1
+log_delete_user=Deleted firewall user $1
+log_create_time=Created time range $1
+log_update_time=Modified time range $1
+log_delete_time=Deleted time range $1
+log_create_sep=Created separator $1
+log_update_sep=Modified separator $1
+log_delete_sep=Deleted separator $1
+log_update_nat=Updated NAT setttings
+log_update_pat=Updated PAT setttings
+log_update_spoof=Updated anti-spoofing setttings
+log_syn=Updated syn attack settings
+log_apply=Applied Configuration
+log_bootup=Enabled firewall at boot time
+log_bootdown=Disabled firewall at boot time
+log_backup=Backed up firewall to file $1
+log_backup_file=Backed up firewall to browser
+log_restore=Restored firewall from file $1
+log_restore_file=Restored firewall from uploaded file
+log_oldenable_rules=Enabled $1 rules and disabled $2 rules
+log_enable_rules=Enabled $1 rules
+log_disable_rules=Disabled $1 rules
+log_logon_rules=Turned on logging for $1 rules
+log_logoff_rules=Turned off logging for $1 rules
+log_delete_rules=Deleted $1 rules
+log_import_rules=Imported rules
+log_import_services=Imported services
+log_import_groups=Imported groups
+log_import_times=Imported time ranges
+
+ipsec_title=FreeSWAN Configuration
+
+times_title=Time Ranges
+times_name=Range name
+times_hours=Hours of day
+times_days=Days of week
+times_all=All
+times_add=Add a new time range.
+times_none=No time ranges have been defined yet.
+times_return=time ranges
+
+time_title1=Create Time Range
+time_title2=Edit Time Range
+time_name=Time range name
+time_header=Time range details
+time_hours=Hours of the day
+time_allday=All day
+time_from=From
+time_to=to
+time_days=Days of the week
+time_allweek=All week
+time_sel=Selected days ..
+time_err=Failed to save time range
+time_ename=Missing or invalid range name
+time_eclash=A time range with the same name already exists
+time_efrom=Missing or invalid starting time - must be in HH:MM format
+time_eto=Missing or invalid ending time - must be in HH:MM format
+time_ehourfrom=Invalid hour in start time
+time_ehourto=Invalid hour in end time
+time_eminfrom=Invalid minute in start time
+time_eminto=Invalid minute in end time
+time_edays=No days of the week selected
+time_err2=Failed to delete time range
+time_einuse=This time range is being used by a firewall rule
+
+remote_title=Remote Logging
+remote_header=Remote firewall logging settings
+remote_host=Send logs to remote host?
+remote_port=on port
+remote_to=Yes, to
+remote_user=Login as user
+remote_pass=Login with password
+remote_err=Failed to save remote logging settings
+remote_ehost=Missing or invalid hostname
+remote_euser=Missing username
+remote_econnect=Could not connect to host : $1
+remote_etimeout=Timed out
+
+import_title=Import Objects
+import_header1=Rule import options
+import_desc1=This form can be used to add firewall rules from a file in CSV format. The file must have the following columns:<br><table> <tr><td><b>Source</b></td> <td>The source IP address, hostname or network, or blank for any</td></tr> <tr><td><b>Destination</b></td> <td>The destination IP address, hostname or network, or blank for any</td></tr> <tr><td><b>Services</b></td> <td>The names of services to match, or blank for any</td></tr> <tr><td><b>Action</b></td> <td>The action to take for matching packets. If the action is followed by <i>log</i>, then the rule will be logged too.</b></td></tr> <tr><td><b>Comment</b></td> <td>An optional comment for this rule</td></tr> <tr><td><b>Time</b></td> <td>An optional time range name that the rule applies in</td></tr> </table>
+import_header2=Service import options
+import_desc2=This form can be used to add services from a file in CSV format. The file must have the following columns:<br><table> <tr><td><b>Name</b></td> <td>Name of the service</td> </tr> <tr> <td><b>Protocol</b></td> <td>A protocol like TCP or UDP</td> </tr> <tr> <td><b>Port</b></td> <td>A port number</td> </tr> </table>
+import_header3=Group import options
+import_desc3=This form can be used to add host groups from a file in CSV format. The file must have the following columns:<br><table> <tr><td><b>Name</b></td> <td>Name of the group</td> </tr> <tr> <td><b>Member</b></td> <td>A member IP address, network or host. Multiple member columns can be specified.</td> </tr> </table>
+import_header4=Time range import options
+import_desc4=This form can be used to add time ranges from a file in CSV format. The file must have the following columns:<br><table> <tr><td><b>Name</b></td> <td>Name of the range</td> </tr> <tr><td><b>Days</b></td> <td>Days of the week this range applies, or empty for all.</td></tr> <tr><td><b>Times</b></td> <td>Starting and ending times separated by a -, or empty for all.</td></tr> </table>
+import_src=CSV file source
+import_ok=Import Now
+import_err=Import failed
+import_erow=Line $1 of the CSV file is invalid : <tt>$2</tt>
+import_esource=Invalid source address or network on line $1 : <tt>$2</tt>
+import_edest=Invalid destination address or network on line $1 : <tt>$2</tt>
+import_eservice=Unknown service on line $1 : <tt>$2</tt>
+import_etime=Unknown time range on line $1 : <tt>$2</tt>
+import_eaction=Unknown action on line $1 : <tt>$2</tt>
+import_eservname=Missing service name on line $1
+import_eservclash=Service name is already in use on line $1 : <tt>$2</tt>
+import_eproto=Missing or unknown protocol on line $1 : <tt>$2</tt>
+import_eport=Missing or invalid port number on line $1 : <tt>$2</tt>
+import_egroupname=Missing group name on line $1
+import_egroupclash=Group name is already in use on line $1 : <tt>$2</tt>
+import_ehost=Invalid host name on line $1 : <tt>$2</tt>
+import_etimename=Missing time name on line $1
+import_etimeclash=Time name is already in use on line $1 : <tt>$2</tt>
+import_etimeday=Invalid day of the week on line $1 : <tt>$2</tt>
+import_etimehour=Invalid time range line $1 : <tt>$2</tt>
+import_etimenone=No days or times specified on line $1
+import_done1=$1 firewall rules have been successfully imported.
+import_done2=$1 services have been successfully imported.
+import_done3=$1 groups have been successfully imported.
+import_done4=$1 time ranges have been successfully imported.
+
+report_title=Search Log
+report_pos=Log entries $1 to $2 of $3
+report_action=Action
+report_date=Date
+report_time=Time
+report_src=Source
+report_dst=Destination
+report_dst_iface=Interface
+report_proto=Protocol
+report_src_port=Source port
+report_dst_port=Dest port
+report_first=Log time
+report_last=Log time
+report_rule=Rule no.
+report_rule2=Rule
+report_none=No matching firewall log entries were found.
+report_none2=No firewall log entries have been recorded yet.
+report_search=Find log entries where ..
+report_reset=Show all entries
+report_mode0=Ignored
+report_mode1=Equals
+report_mode2=Not equals
+report_mode1first=After
+report_mode1last=Before
+report_welf=Export in WELF Format
+report_welfdesc=Click this button to export all the matching firewall log entries in WELF format, for analysis using programs that support this format.
+report_err=Failed to export logs
+report_done=Successfully exported $1 log entries in WELF format to $2.
+report_save=Save Search
+report_savedesc=Enter a name below and click this button to save this search for later user.
+report_savename=Search name
+report_load=Load Search
+report_loaddesc=Select a saved search below and click this button to display matching log entries.
+report_esave=Missing or invalid name for saved search
+report_usesaved=Use saved search
+report_return=firewall log
+
+other=Other..
+
+searches_title=Saved Searches
+config_title=Module Configuration
+
+welf_title=WELF Export
+welf_header=WELF log entries export
+welf_dest=Send WELF file to
+welf_err=Failed to export logs
+welf_done1=Firewall logs in WELF format have been successfully saved to $1.
+welf_done2=Firewall logs in WELF format have been successfully uploaded to the FTP server $1 as $2.
+welf_done3=Firewall logs in WELF format have been successfully emailed to $1.
+welf_ok=Export Now
+
+bandwidth_title=Bandwidth Monitoring
+bandwidth_header=Setup bandwidth usage monitoring
+bandwidth_enabled=Monitor network traffic for bandwidth reporting?
+bandwidth_yes=Yes, on interface
+
+monitor_type=Simple Firewall Rule
+monitor_rule=Fail when rule is hit
+monitor_num=Rule $1 ($2 -> $3)
+
--- /dev/null
+#!/usr/bin/perl
+# list_logs.cgi
+# Real-time view of the security log file
+
+require './itsecur-lib.pl';
+&can_use_error("authlogs");
+$theme_no_table++;
+$| = 1;
+&header($text{'authlogs_title'}, "");
+print "<hr>\n";
+
+$log = $config{'authlog'} || &get_authlog_file();
+print "<b>",&text('logs_viewing', "<tt>$log</tt>"),"</b><p>\n";
+print "<applet code=LogViewer width=90% height=70%>\n";
+print "<param name=url value='authtail.cgi'>\n";
+print "<param name=pause value=1>\n";
+print "<param name=buttonlink value=authdownload.cgi>\n";
+print "<param name=buttonname value='$text{'logs_download'}'>\n";
+if ($session_id) {
+ print "<param name=session value=\"sid=$session_id\">\n";
+ }
+print "</applet>\n";
+print "</form>\n";
+
+print "<hr>\n";
+&footer("", $text{'index_return'});
+
--- /dev/null
+#!/usr/bin/perl
+# Show a form for backing up some or all firewall objects
+
+require './itsecur-lib.pl';
+&can_edit_error("backup");
+&check_zip();
+&header($text{'backup_title'}, "",
+ undef, undef, undef, undef, &apply_button());
+print "<hr>\n";
+
+print "<form action=backup.cgi/firewall.zip method=post>\n";
+print "<table border>\n";
+print "<tr $tb> <td><b>$text{'backup_header'}</b></td> </tr>\n";
+print "<tr $cb> <td><table>\n";
+
+# Show destination
+($mode, @dest) = &parse_backup_dest($config{'backup_dest'});
+print "<tr> <td valign=top><b>$text{'backup_dest'}</b></td>\n";
+print "<td><table cellpadding=0 cellspacing=0>\n";
+printf "<tr> <td><input type=radio name=dest_mode value=0 %s></td> <td>%s</td> </tr>\n",
+ $mode == 0 ? "checked" : "", $text{'backup_dest0'};
+
+printf "<tr> <td><input type=radio name=dest_mode value=1 %s></td> <td>%s</td>\n",
+ $mode == 1 ? "checked" : "", $text{'backup_dest1'};
+printf "<td colspan=3><input name=dest size=40 value='%s'> %s</td> </tr>\n",
+ $mode == 1 ? $dest[0] : "", &file_chooser_button("dest");
+
+printf "<tr> <td><input type=radio name=dest_mode value=3 %s></td> <td>%s</td>\n",
+ $mode == 3 ? "checked" : "", $text{'backup_dest3'};
+printf "<td colspan=3><input name=email size=40 value='%s'></td> </tr>\n",
+ $mode == 3 ? $dest[0] : "";
+
+printf "<tr> <td><input type=radio name=dest_mode value=2 %s></td>\n",
+ $mode == 2 ? "checked" : "";
+printf "<td>%s</td> <td><input name=ftphost size=20 value='%s'></td>\n",
+ $text{'backup_dest2'}, $mode == 2 ? $dest[2] : "";
+printf "<td>%s</td> <td><input name=ftpfile size=20 value='%s'></td> </tr>\n",
+ $text{'backup_ftpfile'}, $mode == 2 ? $dest[3] : "";
+printf "<tr> <td></td> <td>%s</td> <td><input name=ftpuser size=15 value='%s'></td>\n",
+ $text{'backup_ftpuser'}, $mode == 2 ? $dest[0] : "";
+printf "<td>%s</td> <td><input name=ftppass type=password size=15 value='%s'></td> </tr>\n",
+ $text{'backup_ftppass'}, $mode == 2 ? $dest[1] : "";
+print "</table></td> </tr>\n";
+
+# Show password
+print "<tr> <td valign=top><b>$text{'backup_pass'}</b></td> <td>\n";
+printf "<input type=radio name=pass_def value=1 %s> %s\n",
+ $config{'backup_pass'} ? "" : "checked", $text{'backup_nopass'};
+printf "<input type=radio name=pass_def value=0 %s>\n",
+ $config{'backup_pass'} ? "checked" : "";
+printf "<input type=password name=pass value='%s'></td> </tr>\n",
+ $config{'backup_pass'};
+
+# Show what to backup
+%what = map { $_, 1 } split(/\s+/, $config{'backup_what'});
+print "<tr> <td valign=top><b>$text{'backup_what'}</b></td> <td>\n";
+foreach $w (@backup_opts) {
+ printf "<input type=checkbox name=what value=%s %s> %s<br>\n",
+ $w, $what{$w} ? "checked" : "", $text{$w."_title"};
+ }
+if (defined(&select_all_link)) {
+ print &select_all_link("what", 0),"\n";
+ print &select_invert_link("what", 0),"\n";
+ }
+print "</td> </tr>\n";
+
+# Show schedule
+$job = &find_backup_job();
+print "<tr> <td valign=top><b>$text{'backup_sched'}</b></td> <td>\n";
+printf "<input type=radio name=sched_def value=1 %s> %s\n",
+ $job ? "" : "checked", $text{'backup_nosched'};
+printf "<input type=radio name=sched_def value=0 %s> %s\n",
+ $job ? "checked" : "", $text{'backup_interval'};
+print "<select name=sched>\n";
+foreach $s ("hourly", "daily", "weekly", "monthly", "yearly") {
+ printf "<option value=%s %s>%s\n",
+ $s, $job && $job->{'special'} eq $s ? "selected" : "",
+ ucfirst($s);
+ }
+print "</select></td> </tr>\n";
+
+print "</table></td></tr></table>\n";
+print "<input type=submit value='$text{'backup_ok'}'>\n";
+print "<input type=submit name=save value='$text{'backup_save'}'></form>\n";
+
+print "<hr>\n";
+&footer("", $text{'index_return'});
+
--- /dev/null
+#!/usr/bin/perl
+# Show a form for setting up bandwidth monitoring
+
+require './itsecur-lib.pl';
+&can_edit_error("bandwidth");
+&header($text{'bandwidth_title'}, "",
+ undef, undef, undef, undef, &apply_button());
+print "<hr>\n";
+
+print "<form action=save_bandwidth.cgi method=post>\n";
+print "<table border>\n";
+print "<tr $tb> <td><b>$text{'bandwidth_header'}</b></td> </tr>\n";
+print "<tr $cb> <td><table>\n";
+
+print "<tr> <td><b>$text{'bandwidth_enabled'}</b></td> <td>\n";
+printf "<input type=radio name=enabled value=0 %s> %s\n",
+ $config{'bandwidth'} ? "" : "checked", $text{'no'};
+printf "<input type=radio name=enabled value=1 %s> %s\n",
+ $config{'bandwidth'} ? "checked" : "", $text{'bandwidth_yes'};
+print &iface_input("iface", $config{'bandwidth'}, 1, 1, 0);
+print "</td> </tr>\n";
+
+print "</table></td></tr></table>\n";
+print "<input type=submit value='$text{'save'}'></form>\n";
+
+print "<hr>\n";
+&footer("", $text{'index_return'});
+
--- /dev/null
+#!/usr/bin/perl
+# list_groups.cgi
+# Displays a list of host and network groups
+
+require './itsecur-lib.pl';
+&can_use_error("groups");
+&header($text{'groups_title'}, "",
+ undef, undef, undef, undef, &apply_button());
+print "<hr>\n";
+
+@groups = &list_groups();
+$edit = &can_edit("groups");
+if (@groups) {
+ print "<a href='edit_group.cgi?new=1'>$text{'groups_add'}</a><br>\n"
+ if ($edit);
+ print "<table border>\n";
+ print "<tr $tb> <td><b>$text{'group_name'}</b></td> ",
+ "<td><b>$text{'group_members'}</b></td> </tr>\n";
+ foreach $g (@groups) {
+ print "<tr $cb>\n";
+ print "<td><a href='edit_group.cgi?idx=$g->{'index'}'>",
+ "$g->{'name'}</a></td>\n";
+ @mems = @{$g->{'members'}};
+ if (@mems > 5) {
+ @mems = (@mems[0..4], "...");
+ }
+ print "<td>",join(" , ",
+ map { &group_name($_) } @mems),"</td>\n";
+ print "</tr>\n";
+ }
+ print "</table>\n";
+ }
+else {
+ print "<b>$text{'groups_none'}</b><p>\n";
+ }
+print "<a href='edit_group.cgi?new=1'>$text{'groups_add'}</a><p>\n"
+ if ($edit);
+
+print "<hr>\n";
+&footer("", $text{'index_return'});
--- /dev/null
+#!/usr/bin/perl
+# Show a form for importing rules in CSV format
+
+require './itsecur-lib.pl';
+&can_edit_error("import");
+&check_zip();
+&header($text{'import_title'}, "",
+ undef, undef, undef, undef, &apply_button());
+
+foreach $i (1 .. (&supports_time() ? 4 : 3)) {
+ $prog = $i == 1 ? "import_rules.cgi" :
+ $i == 2 ? "import_servs.cgi" :
+ $i == 3 ? "import_groups.cgi" :
+ $i == 4 ? "import_times.cgi" : undef;
+ print "<hr>\n";
+ print $text{'import_desc'.$i},"<p>\n";
+ print "<form action=$prog enctype=multipart/form-data method=post>\n";
+ print "<table border>\n";
+ print "<tr $tb> <td><b>",$text{'import_header'.$i},"</b></td> </tr>\n";
+ print "<tr $cb> <td><table>\n";
+
+ # Show source
+ print "<tr> <td valign=top><b>$text{'import_src'}</b></td> <td>\n";
+ printf "<input type=radio name=src_def value=1 %s> %s\n",
+ $mode != 1 ? "checked" : "", $text{'restore_src1'};
+ print "<input name=file type=file size=20><br>\n";
+ printf "<input type=radio name=src_def value=0 %s> %s\n",
+ $mode == 1 ? "checked" : "", $text{'restore_src0'};
+ printf "<input name=src size=40 value='%s'> %s</td> </tr>\n",
+ $mode == 1 ? $dest[0] : undef, &file_chooser_button("src");
+
+ print "</table></td></tr></table>\n";
+ print "<input type=submit value='$text{'import_ok'}'></form>\n";
+ }
+
+print "<hr>\n";
+&footer("", $text{'index_return'});
+
--- /dev/null
+#!/usr/bin/perl
+# list_logs.cgi
+# Real-time view of a log file
+
+require './itsecur-lib.pl';
+&can_use_error("logs");
+$theme_no_table++;
+$| = 1;
+&header($text{'logs_title'}, "");
+print "<hr>\n";
+
+$log = $config{'log'} || &get_log_file();
+print "<b>",&text('logs_viewing', "<tt>$log</tt>"),"</b><p>\n";
+print "<applet code=LogViewer width=90% height=70%>\n";
+print "<param name=url value='tail.cgi'>\n";
+print "<param name=pause value=1>\n";
+print "<param name=buttonlink value=download.cgi>\n";
+print "<param name=buttonname value='$text{'logs_download'}'>\n";
+if ($session_id) {
+ print "<param name=session value=\"sid=$session_id\">\n";
+ }
+print "</applet>\n";
+print "</form>\n";
+
+print "<hr>\n";
+&footer("", $text{'index_return'});
+
--- /dev/null
+#!/usr/bin/perl
+# list_nat.cgi
+# Show NAT enable form
+
+require './itsecur-lib.pl';
+&can_use_error("nat");
+&header($text{'nat_title'}, "",
+ undef, undef, undef, undef, &apply_button());
+print "<hr>\n";
+
+print "<form action=save_nat.cgi>\n";
+print "<table border>\n";
+print "<tr $tb> <td><b>$text{'nat_header'}</b></td> </tr>\n";
+print "<tr $cb> <td><table>\n";
+
+($iface, @nets) = &get_nat();
+@maps = grep { ref($_) } @nets;
+@nets = grep { !ref($_) } @nets;
+print "<tr> <td valign=top><b>$text{'nat_desc'}</b></td> <td colspan=3>\n";
+printf "<input type=radio name=nat value=0 %s> %s<br>\n",
+ $iface ? "" : "checked", $text{'nat_disabled'};
+printf "<input type=radio name=nat value=1 %s> %s\n",
+ $iface ? "checked" : "", $text{'nat_enabled'};
+print &iface_input("iface", $iface);
+print "</td> </tr>\n";
+
+print "<tr> <td valign=top><b>$text{'nat_nets'}</b></td>\n";
+print "<td valign=top><table>\n";
+$i = 0;
+foreach $n ((grep { $_ !~ /^\!/ } @nets), undef, undef, undef) {
+ print "<tr> <td>",&group_input("net_$i", $n, 1),"</td> </tr>\n";
+ $i++;
+ }
+print "</table></td>\n";
+
+print "<td valign=top><b>$text{'nat_excl'}</b></td>\n";
+print "<td valign=top><table>\n";
+$i = 0;
+foreach $n ((grep { $_ =~ /^\!/ } @nets), undef, undef, undef) {
+ print "<tr> <td>",&group_input("excl_$i", $n =~ /^\!(.*)/ ? $1 : undef, 1),"</td> </tr>\n";
+ $i++;
+ }
+print "</table></td> </tr>\n";
+
+print "<tr> <td valign=top><b>$text{'nat_maps'}</b>",
+ "<br>$text{'nat_mapsdesc'}</td> <td colspan=3>\n";
+print "<table>\n";
+print "<tr> <td><b>$text{'nat_ext'}</b></td> ",
+ "<td><b>$text{'nat_int'}</b></td> ",
+ "<td><b>$text{'nat_virt'}</b></td> </tr>\n";
+$i = 0;
+foreach $m (@maps, [ ], [ ], [ ]) {
+ #print "<tr>\n";
+ #printf "<td><input name=ext_%d size=20 value='%s'></td>\n",
+ # $i, $m->[0];
+ #printf "<td><input name=int_%d size=20 value='%s'></td>\n",
+ # $i, $m->[1];
+ #print "<td>",&iface_input("virt_$i", $m->[2], 1, 1, 1),"</td>\n";
+ #print "</tr>\n";
+ print "<tr>" ;
+ printf "<td><input name=ext_%d size=20 value='%s'></td>\n",
+ $i, $m->[0];
+ print "<td>",&group_input("int_$i", $m->[1], 1),"</td>\n";
+ print "<td>",&iface_input("virt_$i", $m->[2], 1, 1, 1),"</td>\n";
+ print "</tr>\n";
+ $i++;
+ }
+print "</table></td> </tr>\n";
+
+print "</table></td></tr></table>\n";
+print "<input type=submit value='$text{'save'}'></form>\n";
+&can_edit_disable("nat");
+
+print "<hr>\n";
+&footer("", $text{'index_return'});
--- /dev/null
+#!/usr/bin/perl
+# list_nat.cgi
+# Show NAT enable form
+
+require './itsecur-lib.pl';
+&can_use_error("nat2");
+&header($text{'nat2_title'}, "",
+ undef, undef, undef, undef, &apply_button());
+print "<hr>\n";
+
+print "<form action=save_nat2.cgi>\n";
+print "<table border>\n";
+print "<tr $tb> <td><b>$text{'nat_header'}</b></td> </tr>\n";
+print "<tr $cb> <td><table>\n";
+
+($iface, @nets) = &get_nat($nat2_file);
+@maps = grep { ref($_) } @nets;
+@nets = grep { !ref($_) } @nets;
+print "<tr> <td valign=top><b>$text{'nat_desc'}</b></td> <td colspan=3>\n";
+printf "<input type=radio name=nat value=0 %s> %s<br>\n",
+ $iface ? "" : "checked", $text{'nat_disabled'};
+printf "<input type=radio name=nat value=1 %s> %s\n",
+ $iface ? "checked" : "", $text{'nat_enabled'};
+print &iface_input("iface", $iface);
+print "</td> </tr>\n";
+
+print "<tr> <td valign=top><b>$text{'nat_nets'}</b></td>\n";
+print "<td valign=top><table>\n";
+$i = 0;
+foreach $n ((grep { $_ !~ /^\!/ } @nets), undef, undef, undef) {
+ print "<tr> <td>",&group_input("net_$i", $n, 1),"</td> </tr>\n";
+ $i++;
+ }
+print "</table></td>\n";
+
+print "<td valign=top><b>$text{'nat_excl'}</b></td>\n";
+print "<td valign=top><table>\n";
+$i = 0;
+foreach $n ((grep { $_ =~ /^\!/ } @nets), undef, undef, undef) {
+ print "<tr> <td>",&group_input("excl_$i", $n =~ /^\!(.*)/ ? $1 : undef, 1),"</td> </tr>\n";
+ $i++;
+ }
+print "</table></td> </tr>\n";
+
+print "<tr> <td valign=top><b>$text{'nat_maps'}</b>",
+ "<br>$text{'nat_mapsdesc'}</td> <td colspan=3>\n";
+print "<table>\n";
+print "<tr> <td><b>$text{'nat_ext'}</b></td> ",
+ "<td><b>$text{'nat_int'}</b></td> ",
+ "<td><b>$text{'nat_virt'}</b></td> </tr>\n";
+$i = 0;
+foreach $m (@maps, [ ], [ ], [ ]) {
+ print "<tr>\n";
+ printf "<td><input name=ext_%d size=20 value='%s'></td>\n",
+ $i, $m->[0];
+ printf "<td><input name=int_%d size=20 value='%s'></td>\n",
+ $i, $m->[1];
+ print "<td>",&iface_input("virt_$i", $m->[2], 1, 1, 1),"</td>\n";
+ print "</tr>\n";
+ $i++;
+ }
+print "</table></td> </tr>\n";
+
+print "</table></td></tr></table>\n";
+print "<input type=submit value='$text{'save'}'></form>\n";
+&can_edit_disable("nat");
+
+print "<hr>\n";
+&footer("", $text{'index_return'});
--- /dev/null
+#!/usr/bin/perl
+# list_pat.cgi
+# Show table of incoming forwarded ports
+
+require './itsecur-lib.pl';
+&can_use_error("pat");
+&header($text{'pat_title'}, "",
+ undef, undef, undef, undef, &apply_button());
+print "<hr>\n";
+
+@forwards = &get_pat();
+print "<form action=save_pat.cgi>\n";
+print "<table border>\n";
+print "<tr $tb> <td><b>$text{'pat_header'}</b></td> </tr>\n";
+print "<tr $cb> <td><table>\n";
+
+print "<tr> <td valign=top><b>$text{'pat_forward'}</b></td> ",
+ "<td><table border>\n";
+print "<tr $tb> <td><b>$text{'pat_service'}</b></td> ",
+ "<td><b>$text{'pat_host'}</b></td> ",
+ "<td><b>$text{'pat_iface'}</b></td> </tr>\n";
+$j = 0;
+foreach $f (@forwards, { }, { }, { }) {
+ print "<tr $cb>\n";
+ print "<td>",&service_input("service_$j", $f->{'service'}, 1),"</td>\n";
+ print "<td><input name=host_$j size=30 value='$f->{'host'}'></td>\n";
+ print "<td>",&iface_input("iface_$j", $f->{'iface'},
+ 0, 1, 1),"</td>\n";
+ print "</tr>\n";
+ $j++;
+ }
+print "</table></td> </tr>\n";
+
+print "</table></td></tr></table>\n";
+print "<input type=submit value='$text{'save'}'></form>\n";
+&can_edit_disable("pat");
+
+print "<hr>\n";
+&footer("", $text{'index_return'});
--- /dev/null
+#!/usr/bin/perl
+# Show a form for setting up remote logging
+
+require './itsecur-lib.pl';
+&foreign_require("servers", "servers-lib.pl");
+&can_edit_error("remote");
+&header($text{'remote_title'}, "",
+ undef, undef, undef, undef, &apply_button());
+print "<hr>\n";
+
+print "<form action=save_remote.cgi method=post>\n";
+print "<table border>\n";
+print "<tr $tb> <td><b>$text{'remote_header'}</b></td> </tr>\n";
+print "<tr $cb> <td><table>\n";
+
+@servers = &servers::list_servers();
+($server) = grep { $_->{'host'} eq $config{'remote_log'} } @servers;
+
+# Show target host
+print "<tr> <td><b>$text{'remote_host'}</b></td> <td>\n";
+printf "<input type=radio name=host_def value=1 %s> %s\n",
+ $server ? "" : "checked", $text{'no'};
+printf "<input type=radio name=host_def value=0 %s> %s\n",
+ $server ? "checked" : "", $text{'remote_to'};
+printf "<input name=host size=20 value='%s'> %s\n",
+ $server ? $server->{'host'} : "", $text{'remote_port'};
+printf "<input name=port size=10 value='%s'></td> </tr>\n",
+ $server ? $server->{'port'} : 10000;
+
+# Show login and password
+print "<tr> <td><b>$text{'remote_user'}</b></td> <td>\n";
+printf "<input name=user size=20 value='%s'></td> </tr>\n",
+ $server ? $server->{'user'} : "";
+
+print "<tr> <td><b>$text{'remote_pass'}</b></td> <td>\n";
+printf "<input name=pass type=password size=20 value='%s'></td> </tr>\n",
+ $server ? $server->{'pass'} : "";
+
+print "</table></td></tr></table>\n";
+print "<input type=submit value='$text{'save'}'></form>\n";
+
+print "<hr>\n";
+&footer("", $text{'index_return'});
+
--- /dev/null
+#!/usr/bin/perl
+# Show last few log entries, nicely parsed, with search form
+
+require './itsecur-lib.pl';
+&can_use_error("report");
+use POSIX;
+&ReadParse();
+print "Refresh: $config{'refresh'}\r\n"
+ if ($config{'refresh'});
+&header($text{'report_title'}, "");
+print "<hr>\n";
+
+if ($in{'reset'}) {
+ # Clear all inputs
+ %in = ( );
+ }
+elsif ($in{'save_name'}) {
+ # Load up an old search
+ $search = &get_search($in{'save_name'});
+ if ($search) {
+ $oldstart = $in{'start'};
+ $oldend = $in{'end'};
+ %in = %$search;
+ $in{'start'} = $oldstart;
+ $in{'end'} = $oldend;
+ }
+ }
+
+# Show search form
+print "<form action=list_report.cgi>\n";
+print "<table width=100%>\n";
+print "<tr>\n";
+print "<td colspan=4><input type=submit value='$text{'report_search'}'></td>\n";
+print "<td colspan=4 align=right><input type=submit name=reset value='$text{'report_reset'}'></td>\n";
+print "</tr>\n";
+$i = 0;
+foreach $f (@search_fields) {
+ print "<tr>\n" if ($i%2 == 0);
+ print "<td><b>",$text{'report_'.$f},"</b></td>\n";
+ print "<td><select name=${f}_mode>\n";
+ if ($f eq "first" || $f eq "last") {
+ foreach $m (0 .. 1) {
+ printf "<option value=%d %s>%s\n",
+ $m, $in{"${f}_mode"} == $m ? "selected" : "",
+ $text{'report_mode'.$m.$f} ||
+ $text{'report_mode'.$m};
+ }
+ }
+ else {
+ foreach $m (0 .. 2) {
+ printf "<option value=%d %s>%s\n",
+ $m, $in{"${f}_mode"} == $m ? "selected" : "",
+ $text{'report_mode'.$m};
+ }
+ }
+ print "</select></td>\n";
+ if ($f eq "dst_iface") {
+ print "<td>",&iface_input($f."_what", $in{$f."_what"}),"</td>\n";
+ }
+ elsif ($f eq "proto") {
+ print "<td>",&protocol_input($f."_what", $in{$f."_what"}),"</td>\n";
+ }
+ elsif ($f eq "dst_port" || $f eq "src_port") {
+ print "<td>",&service_input($f."_what", $in{$f."_what"}, 2, 0, 1);
+ printf "<input name=%s_other size=6 value='%s'>\n",
+ $f, $in{$f."_other"};
+ print "</td>\n";
+ }
+ elsif ($f eq "src" || $f eq "dst") {
+ print "<td>",&group_input($f."_what", $in{$f."_what"}, 2, 0);
+ printf "<input name=%s_other size=10 value='%s'>\n",
+ $f, $in{$f."_other"};
+ print "</td>\n";
+ }
+ elsif ($f eq "first" || $f eq "last") {
+ print "<td>";
+ &date_input($in{$f."_day"}, $in{$f."_month"},
+ $in{$f."_year"}, $f);
+ if ($f eq "first") {
+ &hourmin_input($in{$f."_hour"} || "00",
+ $in{$f."_min"} || "00", $f);
+ }
+ else {
+ &hourmin_input($in{$f."_hour"} || "23",
+ $in{$f."_min"} || "59", $f);
+ }
+ print "</td>";
+ }
+ elsif ($f eq "action") {
+ print "<td>",&action_input($f."_what",
+ $in{$f."_what"}, 1),"</td>\n";
+ }
+ elsif ($f eq "rule") {
+ printf "<td><input name=%s_what size=5 value='%s'></td>\n",
+ $f, $in{$f."_what"};
+ }
+ else {
+ printf "<td><input name=%s_what size=20 value='%s'></td>\n",
+ $f, $in{$f."_what"};
+ }
+ print "<td> </td>\n";
+ print "</tr>\n" if ($i++%2 == 1);
+ }
+
+# Show saved search
+@searches = &list_searches();
+if (@searches) {
+ print "<tr> <td></td> </tr>\n";
+ print "<tr> <td><b>$text{'report_usesaved'}</b></td>\n";
+ print "<td colspan=3><select name=save_name>\n";
+ printf "<option value='' %s>%s\n",
+ $in{'save_name'} eq "" ? "selected" : "", " ";
+ foreach $s ( @searches) {
+ printf "<option value='%s' %s>%s\n",
+ $s->{'save_name'},
+ $in{'save_name'} eq $s->{'save_name'} ? "selected" : "",
+ $s->{'save_name'};
+ }
+ print "</select></td> </tr>\n";
+ }
+
+print "</table>\n";
+
+print "</form>\n";
+print "<hr>\n";
+
+# Find those matching current search
+@logs = &parse_all_logs();
+$anylogs = @logs;
+@logs = &filter_logs(\@logs, \%in, \@searchvars);
+if ($in{'save_name'}) {
+ push(@searchvars, "save_name=".&urlize($in{'save_name'}));
+ }
+
+# Show matching log entries
+if (@logs) {
+ if (@searchvars) {
+ $prog = "list_report.cgi?".join("&", @searchvars)."&";
+ }
+ else {
+ $prog = "list_report.cgi?";
+ }
+ if (@logs > $config{'perpage'}) {
+ # Need to show arrows
+ print "<center>\n";
+ $s = int($in{'start'});
+ $e = $in{'start'} + $config{'perpage'} - 1;
+ $e = @logs-1 if ($e >= @logs);
+ if ($s) {
+ printf "<a href='%sstart=%d'>%s</a>\n",
+ $prog, 0,
+ "<img src=images/lleft.gif border=0 align=middle alt='First page'>";
+ printf "<a href='%sstart=%d'>%s</a>\n",
+ $prog, $s - $config{'perpage'},
+ "<img src=/images/left.gif border=0 align=middle alt='Previous page'>";
+ }
+ print "<font size=+1>",&text('report_pos', $s+1, $e+1,
+ scalar(@logs)),"</font>\n";
+ if ($e < @logs-1) {
+ printf "<a href='%sstart=%d'>%s</a>\n",
+ $prog, $s + $config{'perpage'},
+ "<img src=/images/right.gif border=0 align=middle alt='Next page'>";
+ printf "<a href='%sstart=%d'>%s</a>\n",
+ $prog, int((@logs-1)/$config{'perpage'})*$config{'perpage'},
+ "<img src=images/rright.gif border=0 align=middle alt='Last page'>";
+ }
+ print "</center>\n";
+ }
+ else {
+ # Can show them all
+ $s = 0;
+ $e = @logs - 1;
+ }
+
+ print "<table border width=100%>\n";
+ print "<tr $tb> <td><b>$text{'report_action'}</b></td> ",
+ "<td><b>$text{'report_rule2'}</b></td> ",
+ "<td><b>$text{'report_date'}</b></td> ",
+ "<td><b>$text{'report_time'}</b></td> ",
+ "<td><b>$text{'report_src'}</b></td> ",
+ "<td><b>$text{'report_dst'}</b></td> ",
+ "<td><b>$text{'report_dst_iface'}</b></td> ",
+ "<td><b>$text{'report_proto'}</b></td> ",
+ "<td><b>$text{'report_src_port'}</b></td> ",
+ "<td><b>$text{'report_dst_port'}</b></td> ",
+ "</tr>\n";
+ for($i=$s; $i<=$e; $i++) {
+ $l = $logs[$i];
+ print "<tr $cb>\n";
+ print "<td>",$text{'rule_'.$l->{'action'}},"</td>\n";
+ print "<td>",$l->{'rule'} || "<br>","</td>\n";
+ local @tm = localtime($l->{'time'});
+ print "<td>",strftime("%d/%m/%Y", @tm),"</td>\n";
+ print "<td>",strftime("%H:%M:%S", @tm),"</td>\n";
+ print "<td>",$l->{'src'},"</td>\n";
+ print "<td>",$l->{'dst'},"</td>\n";
+ print "<td>",$l->{'dst_iface'} || "<br>","</td>\n";
+ print "<td>",$l->{'proto'} || "<br>","</td>\n";
+ print "<td>",$l->{'src_port'} || "<br>","</td>\n";
+ print "<td>",$l->{'dst_port'} || "<br>","</td>\n";
+ print "</tr>\n";
+ }
+ print "</table>\n";
+ }
+elsif ($anylogs) {
+ print "<b>$text{'report_none'}</b><p>\n";
+ }
+else {
+ print "<b>$text{'report_none2'}</b><p>\n";
+ }
+
+
+print "<hr>\n";
+print "<table width=100%>\n";
+
+if (@logs && &can_edit("report")) {
+ # Show export button
+ print "<form action=list_welf.cgi>\n";
+ foreach $i (keys %in) {
+ print "<input type=hidden name=$i value='",
+ &html_escape($in{$i}),"'>\n";
+ }
+ print "<tr> <td valign=top><input type=submit value='$text{'report_welf'}'></td>\n";
+ print "<td>$text{'report_welfdesc'}</td>\n";
+ print "</tr></form>\n";
+ $anyrows++;
+ }
+
+if (@searchvars && &can_edit("report")) {
+ # Show button to save this search
+ print "<form action=save_search.cgi>\n";
+ foreach $i (keys %in) {
+ print "<input type=hidden name=$i value='",
+ &html_escape($in{$i}),"'>\n";
+ }
+ print "<tr> <td valign=top><input type=submit value='$text{'report_save'}'></td>\n";
+ print "<td>$text{'report_savedesc'}<br>\n";
+ print "<b>$text{'report_savename'}</b>\n";
+ printf "<input name=save_name size=30 value='%s'>\n",
+ $in{'save_name'};
+ print "</td>\n";
+ print "</tr></form>\n";
+ $anyrows++;
+ }
+
+# Show button to select an old search
+#@searches = &list_searches();
+#if (@searches) {
+# print "<form action=list_report.cgi>\n";
+# print "<tr> <td valign=top><input type=submit value='$text{'report_load'}'></td>\n";
+# print "<td>$text{'report_loaddesc'}<br>\n";
+# print "<b>$text{'report_savename'}</b>\n";
+# print "<select name=save_name>\n";
+# foreach $s (@searches) {
+# printf "<option %s>%s\n",
+# $s->{'save_name'} eq $in{'save_name'} ? "selected" : "",
+# &html_escape($s->{'save_name'});
+# }
+# print "</select>\n";
+# print "</td>\n";
+# print "</tr></form>\n";
+# $anyrows++;
+# }
+
+print "</table>\n";
+
+print "<hr>\n" if ($anyrows);
+&footer("", $text{'index_return'});
+
+# date_input(day, month, year, prefix)
+sub date_input
+{
+print "<input name=$_[3]_day size=2 value='$_[0]'>";
+print "/<select name=$_[3]_month>\n";
+local $m;
+foreach $m (1..12) {
+ printf "<option value=%d %s>%s\n",
+ $m, $_[1] eq $m ? 'selected' : '', $text{"smonth_$m"};
+ }
+print "</select>";
+print "/<input name=$_[3]_year size=4 value='$_[2]'>";
+print &date_chooser_button("$_[3]_day", "$_[3]_month", "$_[3]_year");
+print "\n";
+}
+
+# hourmin_input(hour, min, prefix)
+sub hourmin_input
+{
+print "<input name=$_[2]_hour size=2 value='$_[0]'>";
+print ":";
+print "<input name=$_[2]_min size=2 value='$_[1]'>";
+print "\n";
+}
--- /dev/null
+#!/usr/bin/perl
+# Show a form for restoring some or all firewall objects
+
+require './itsecur-lib.pl';
+&can_edit_error("restore");
+&check_zip();
+&header($text{'restore_title'}, "",
+ undef, undef, undef, undef, &apply_button());
+print "<hr>\n";
+
+($mode, @dest) = &parse_backup_dest($config{'backup_dest'});
+print "<form action=restore.cgi enctype=multipart/form-data method=post>\n";
+print "<table border>\n";
+print "<tr $tb> <td><b>$text{'restore_header'}</b></td> </tr>\n";
+print "<tr $cb> <td><table>\n";
+
+# Show source
+print "<tr> <td valign=top><b>$text{'restore_src'}</b></td> <td>\n";
+printf "<input type=radio name=src_def value=1 %s> %s\n",
+ $mode != 1 ? "checked" : "", $text{'restore_src1'};
+print "<input name=file type=file size=20><br>\n";
+printf "<input type=radio name=src_def value=0 %s> %s\n",
+ $mode == 1 ? "checked" : "", $text{'restore_src0'};
+printf "<input name=src size=40 value='%s'> %s</td> </tr>\n",
+ $mode == 1 ? $dest[0] : undef, &file_chooser_button("src");
+
+# Show password
+print "<tr> <td valign=top><b>$text{'restore_pass'}</b></td> <td>\n";
+printf "<input type=radio name=pass_def value=1 %s> %s\n",
+ $config{'backup_pass'} ? "" : "checked", $text{'backup_nopass'};
+printf "<input type=radio name=pass_def value=0 %s>\n",
+ $config{'backup_pass'} ? "checked" : "";
+printf "<input type=password name=pass value='%s'></td> </tr>\n",
+ $config{'backup_pass'};
+
+# Show what to restore
+%what = map { $_, 1 } split(/\s+/, $config{'backup_what'});
+print "<tr> <td valign=top><b>$text{'restore_what'}</b></td> <td>\n";
+foreach $w (@backup_opts) {
+ printf "<input type=checkbox name=what value=%s %s> %s<br>\n",
+ $w, $what{$w} ? "checked" : "", $text{$w."_title"};
+ }
+if (defined(&select_all_link)) {
+ print &select_all_link("what", 0),"\n";
+ print &select_invert_link("what", 0),"\n";
+ }
+print "</td> </tr>\n";
+
+print "</table></td></tr></table>\n";
+print "<input type=submit value='$text{'restore_ok'}'></form>\n";
+
+print "<hr>\n";
+&footer("", $text{'index_return'});
+
--- /dev/null
+#!/usr/bin/perl
+# list_rules.cgi
+# Display a list of all active rules
+require './itsecur-lib.pl';
+
+&can_use_error("rules");
+&header($text{'rules_title'}, "",
+ undef, undef, undef, undef, &apply_button());
+print "<hr>\n";
+
+
+# 0-No. 1-Source,2-Destination, 3-Services, 4-Time, 5-Action, 6-Enabled, 7-Comment
+local @CW=( "5%", "15%", "15%", "20%", "5%", "5%", "5%", "20%");
+$C_drop="#FFCCcc";
+$C_reject="#FFDDAA";
+$C_accept="";
+$C_disabled="#FF3333";
+$C_separator="#ffffcc";
+
+local $Row_Color="";
+
+@rules = &list_rules();
+@servs = &list_services();
+$edit = &can_edit("rules");
+$times = &supports_time() && &list_times() > 0;
+if (@rules) {
+ if ($edit) {
+ print "<a href='edit_rule.cgi?new=1'>$text{'rules_add'}</a>\n";
+ print " " x 2;
+ print "<a href='edit_sep.cgi?new=1'>$text{'rules_sadd'}</a>\n";
+ print "<br>\n";
+ print "<form action=enable_rules.cgi method=post>\n";
+ }
+ $cols = $times ? 8 : 7;
+ print "<table border>\n";
+ print "<tr $tb> ",
+ "<td width=$CW[0]><b>$text{'rule_num'}</b></td> ",
+ "<td width=$CW[1]><b>$text{'rule_source'}</b></td> ",
+ "<td width=$CW[2]><b>$text{'rule_dest'}</b></td> ",
+ "<td width=$CW[3]><b>$text{'rules_service'}</b></td> ",
+ ($times ? "<td><b>$text{'rule_time'}</b></td> " : ""),
+ "<td width=$CW[5]><b>$text{'rule_action'}</b></td> ",
+ "<td width=$CW[6]><b>$text{'rule_enabled'}</b></td> ",
+ ($config{'show_desc'} ? "<td width=$CW[7]><b>$text{'rules_desc'}</b></td> " :
+ "<td width=10><b>$text{'rules_move'}</b></td>"),
+ "</tr>\n";
+ foreach $r (@rules) {
+ if ($r->{'sep'}){
+ $Row_Color="bgcolor=\"$C_separator\" ";
+ } elsif (!$r->{'enabled'}){
+ $Row_Color="bgcolor=\"$C_disabled\" ";
+ } elsif ( $r->{'action'} eq "drop" ){
+ $Row_Color="bgcolor=\"$C_drop\" ";
+ } elsif ( $r->{'action'} eq "reject" ){
+ $Row_Color="bgcolor=\"$C_reject\" ";
+ } else {
+ $Row_Color="";
+ }
+
+ # case('accept') {}
+ # case('allow') {}
+ # case('drop') {}
+ #case('reject') {}
+ #case('ignore') {}
+
+
+
+ print "<tr $Row_Color $cb>\n";
+ if ($r->{'sep'}) {
+ # Actually a separator - just show it's description
+ print "<td colspan=$cols><b><a href='edit_sep.cgi?idx=$r->{'index'}'>$r->{'desc'}</b></a></td>\n";
+ }
+ else {
+ # Show full rule details
+
+
+ print "<td width=$CW[0]>";
+ if ($edit) {
+ print "<input type=checkbox name=r value=$r->{'index'}> ";
+ }
+ print "<a href='edit_rule.cgi?",
+ "idx=$r->{'index'}'>$r->{'num'}</a></td>\n";
+ print "<td width=$CW[1]>",
+ &group_names_link($r->{'source'}, 'rules'),
+ "</td>\n";
+ print "<td width=$CW[2]>",
+ &group_names_link($r->{'dest'}, 'rules',
+ &allow_action($r) ? 'dest' : undef),
+ "</td>\n";
+ print "<td width=$CW[3]>",&protocol_names($r->{'service'},\@servs),"</td>\n";
+ if ($times) {
+ print "<td>",$r->{'time'} eq '*' ?
+ $text{'rule_anytime'} :
+ $r->{'time'},"</td>\n";
+ }
+ print "<td width=$CW[5]>",$text{'rule_'.$r->{'action'}},
+ $r->{'log'} ? " $text{'rules_log'}" : "","</td>\n";
+ print "<td width=$CW[6]>",$r->{'enabled'} ? $text{'yes'} :
+ "<font color=#ff0000>$text{'no'}</font>",
+ "</td>\n";
+ if ($config{'show_desc'}) {
+ print "<td width=$CW[7]>",$r->{'desc'} eq "*" ? "<br>"
+ : $r->{'desc'},"</td>\n";
+ }
+ else {
+ if ($r eq $rules[0] || !$edit) {
+ print "<td><img src=images/gap.gif>\n";
+ }
+ else {
+ print "<td><a href='up.cgi?idx=$r->{'index'}'>",
+ "<img src=images/up.gif border=0></a>\n";
+ }
+ if ($r eq $rules[$#rules] || !$edit) {
+ print "<img src=images/gap.gif></td>\n";
+ }
+ else {
+ print "<a href='down.cgi?idx=$r->{'index'}'>",
+ "<img src=images/down.gif border=0></a></td>\n";
+ }
+ }
+ }
+ print "</tr>\n";
+ }
+ print "</table>\n";
+ }
+else {
+ print "<b>$text{'rules_none'}</b><p>\n";
+ }
+if ($edit) {
+ print "<a href='edit_rule.cgi?new=1'>$text{'rules_add'}</a>\n";
+ print " " x 2;
+ print "<a href='edit_sep.cgi?new=1'>$text{'rules_sadd'}</a>\n";
+ print "<p>\n";
+ }
+if ($edit && @rules) {
+ print "<input type=submit name=enable value='$text{'rules_enable'}'>\n";
+ print "<input type=submit name=disable value='$text{'rules_disable'}'>\n";
+
+ print " \n";
+ print "<input type=submit name=logon value='$text{'rules_logon'}'>\n";
+ print "<input type=submit name=logoff value='$text{'rules_logoff'}'>\n";
+ print " \n";
+ print "<input type=submit name=delete value='$text{'rules_delete'}'>\n";
+ print "</form>\n";
+ }
+
+print "<hr>\n";
+&footer("", $text{'index_return'});
+
--- /dev/null
+#!/usr/bin/perl
+# list_services.cgi
+# Displays a list of standard and custom services
+
+require './itsecur-lib.pl';
+&can_use_error("services");
+&header($text{'services_title'}, "",
+ undef, undef, undef, undef, &apply_button());
+print "<hr>\n";
+
+@services = &list_services();
+$edit = &can_edit("services");
+print "<a href='edit_service.cgi?new=1'>$text{'services_add'}</a><br>\n"
+ if ($edit);
+print "<table border>\n";
+print "<tr $tb> <td><b>$text{'service_name'}</b></td> ",
+ "<td><b>$text{'service_ports'}</b></td> </tr>\n";
+if (!$services[0]->{'standard'}) {
+ print "<tr $tb> <td colspan=3><b>$text{'services_header1'}</b></td> </tr>\n";
+ }
+foreach $s (@services) {
+ if ($s->{'standard'} && !$doneheader) {
+ print "<tr $tb> <td colspan=3><b>$text{'services_header2'}</b></td> </tr>\n";
+ $doneheader++;
+ }
+ print "<tr $cb>\n";
+ if ($s->{'standard'}) {
+ print "<td>$s->{'name'}</td>\n";
+ }
+ else {
+ print "<td><a href='edit_service.cgi?idx=$s->{'index'}'>",
+ "$s->{'name'}</a></td>\n";
+ }
+ print "<td>";
+ for($i=0; $i<@{$s->{'protos'}}; $i++) {
+ print &protocol_name($s->{'protos'}->[$i], $s->{'ports'}->[$i]);
+ print "\n";
+ }
+ for($i=0; $i<@{$s->{'others'}}; $i++) {
+ print "<b>$s->{'others'}->[$i]</b>\n";
+ }
+ print "</td>\n";
+ print "</tr>\n";
+ }
+print "</table>\n";
+print "<a href='edit_service.cgi?new=1'>$text{'services_add'}</a><p>\n"
+ if ($edit);
+
+print "<hr>\n";
+&footer("", $text{'index_return'});
--- /dev/null
+#!/usr/bin/perl
+# list_spoof.cgi
+# Show spoofing prevention form
+
+require './itsecur-lib.pl';
+&can_use_error("spoof");
+&header($text{'spoof_title'}, "",
+ undef, undef, undef, undef, &apply_button());
+print "<hr>\n";
+
+print "<form action=save_spoof.cgi>\n";
+print "<table border>\n";
+print "<tr $tb> <td><b>$text{'spoof_header'}</b></td> </tr>\n";
+print "<tr $cb> <td><table>\n";
+
+($iface, @nets) = &get_spoof();
+print "<tr> <td valign=top><b>$text{'spoof_desc'}</b></td> <td>\n";
+printf "<input type=radio name=spoof value=0 %s> %s<br>\n",
+ $iface ? "" : "checked", $text{'spoof_disabled'};
+printf "<input type=radio name=spoof value=1 %s> %s\n",
+ $iface ? "checked" : "", $text{'spoof_enabled'};
+print &iface_input("iface", $iface);
+print "</td> </tr>\n";
+
+print "<tr> <td valign=top><b>$text{'spoof_nets'}</b></td> <td>\n";
+print "<textarea name=nets rows=5 cols=40>",
+ join("\n", @nets),"</textarea></td> </tr>\n";
+
+print "</table></td></tr></table>\n";
+print "<input type=submit value='$text{'save'}'></form>\n";
+&can_edit_disable("spoof");
+
+print "<hr>\n";
+&footer("", $text{'index_return'});
--- /dev/null
+#!/usr/bin/perl
+# list_syn.cgi
+# Show syn attack prevention form
+
+require './itsecur-lib.pl';
+&can_use_error("syn");
+&header($text{'syn_title'}, "",
+ undef, undef, undef, undef, &apply_button());
+print "<hr>\n";
+
+print "<form action=save_syn.cgi>\n";
+print "<table border>\n";
+print "<tr $tb> <td><b>$text{'syn_header'}</b></td> </tr>\n";
+print "<tr $cb> <td><table>\n";
+
+($flood, $spoof, $fin) = &get_syn();
+
+print "<tr> <td><b>$text{'syn_flood'}</b></td> <td>\n";
+printf "<input type=radio name=flood value=1 %s> %s\n",
+ $flood ? "checked" : "", $text{'yes'};
+printf "<input type=radio name=flood value=0 %s> %s</td> </tr>\n",
+ $flood ? "" : "checked", $text{'no'};
+
+print "<tr> <td><b>$text{'syn_spoof'}</b></td> <td>\n";
+printf "<input type=radio name=spoof value=1 %s> %s\n",
+ $spoof ? "checked" : "", $text{'yes'};
+printf "<input type=radio name=spoof value=0 %s> %s</td> </tr>\n",
+ $spoof ? "" : "checked", $text{'no'};
+
+print "<tr> <td><b>$text{'syn_fin'}</b></td> <td>\n";
+printf "<input type=radio name=fin value=1 %s> %s\n",
+ $fin ? "checked" : "", $text{'yes'};
+printf "<input type=radio name=fin value=0 %s> %s</td> </tr>\n",
+ $fin ? "" : "checked", $text{'no'};
+
+print "</table></td></tr></table>\n";
+print "<input type=submit value='$text{'save'}'></form>\n";
+&can_edit_disable("syn");
+
+print "<hr>\n";
+&footer("", $text{'index_return'});
--- /dev/null
+#!/usr/bin/perl
+# list_times.cgi
+# Display a list of time ranges that can be used in rules
+
+require './itsecur-lib.pl';
+&can_use_error("times");
+&header($text{'times_title'}, "",
+ undef, undef, undef, undef, &apply_button());
+print "<hr>\n";
+
+@times = &list_times();
+$edit = &can_edit("times");
+if (@times) {
+ print "<a href='edit_time.cgi?new=1'>$text{'times_add'}</a><br>\n"
+ if ($edit);
+ print "<table border>\n";
+ print "<tr $tb> <td><b>$text{'times_name'}</b></td> ",
+ "<td><b>$text{'times_hours'}</b></td> ",
+ "<td><b>$text{'times_days'}</b></td> </tr>\n";
+ foreach $t (@times) {
+ print "<tr $cb>\n";
+ print "<td><a href='edit_time.cgi?idx=$t->{'index'}'>",
+ "$t->{'name'}</a></td>\n";
+ print "<td>",$t->{'hours'} eq "*" ? $text{'times_all'} :
+ $t->{'hours'},"</td>\n";
+ print "<td>",$t->{'days'} eq "*" ? $text{'times_all'} :
+ join(" ", map { $text{'sday_'.$_} } split(/,/, $t->{'days'})),"</td>\n";
+ print "</tr>\n";
+ }
+ print "</table>\n";
+ }
+else {
+ print "<b>$text{'times_none'}</b><p>\n";
+ }
+print "<a href='edit_time.cgi?new=1'>$text{'times_add'}</a><p>\n"
+ if ($edit);
+
+print "<hr>\n";
+&footer("", $text{'index_return'});
+
--- /dev/null
+#!/usr/bin/perl
+# list_users.cgi
+# Show all Webmin users with access to this module only
+
+require './itsecur-lib.pl';
+&foreign_require("acl", "acl-lib.pl");
+&can_use_error("users");
+&header($text{'users_title'}, "",
+ undef, undef, undef, undef, &apply_button());
+print "<hr>\n";
+
+# Work out which users have access to this module
+@users = &acl::list_users();
+foreach $u (@users) {
+ @m = @{$u->{'modules'}};
+ if ($u->{'name'} ne "root" &&
+ &indexof($module_name, @m) >= 0) {
+ push(@musers, $u);
+ }
+ }
+
+#print "$text{'users_desc'}<p>\n";
+$edit = &can_edit("users");
+if (@musers) {
+ print "<a href='edit_user.cgi?new=1'>$text{'users_add'}</a><br>\n"
+ if ($edit);
+ print "<table border>\n";
+ print "<tr $tb> ",
+ "<td><b>$text{'users_name'}</b></td> ",
+ "<td><b>$text{'users_ips'}</b></td> ",
+ "<td><b>$text{'users_enabled'}</b></td> ",
+ "</tr>\n";
+ foreach $u (@musers) {
+ print "<tr $cb>\n";
+ print "<td><a href='edit_user.cgi?",
+ "name=$u->{'name'}'>$u->{'name'}</a></td>\n";
+ print "<td>\n";
+ if ($u->{'allow'}) {
+ print &text('users_allow', $u->{'allow'});
+ }
+ elsif ($u->{'deny'}) {
+ print &text('users_deny', $u->{'deny'});
+ }
+ else {
+ print $text{'users_all'};
+ }
+ print "</td>\n";
+ print "<td>",$u->{'pass'} =~ /^\*LK\*/ ? $text{'rule_no'} : $text{'rule_yes'},"</td>\n";
+ %uaccess = &get_module_acl($u->{'name'});
+ print "</tr>\n";
+ }
+ print "</table>\n";
+ }
+else {
+ print "<b>$text{'users_none'}</b><p>\n";
+ }
+print "<a href='edit_user.cgi?new=1'>$text{'users_add'}</a><p>\n"
+ if ($edit);
+
+print "<hr>\n";
+&footer("", $text{'index_return'});
--- /dev/null
+#!/usr/bin/perl
+# Show a form for exporting a log in WELF format
+
+require './itsecur-lib.pl';
+&can_edit_error("report");
+&ReadParse();
+&header($text{'welf_title'}, "",
+ undef, undef, undef, undef, &apply_button());
+print "<hr>\n";
+
+print "<form action=welf.cgi/logs.welf method=post>\n";
+foreach $i (keys %in) {
+ print "<input type=hidden name=$i value='",
+ &html_escape($in{$i}),"'>\n";
+ }
+
+print "<table border>\n";
+print "<tr $tb> <td><b>$text{'welf_header'}</b></td> </tr>\n";
+print "<tr $cb> <td><table>\n";
+
+# Show destination
+($mode, @dest) = &parse_backup_dest($config{'welf_dest'});
+print "<tr> <td valign=top><b>$text{'welf_dest'}</b></td>\n";
+print "<td><table cellpadding=0 cellspacing=0>\n";
+printf "<tr> <td><input type=radio name=dest_mode value=0 %s></td> <td>%s</td> </tr>\n",
+ $mode == 0 ? "checked" : "", $text{'backup_dest0'};
+
+printf "<tr> <td><input type=radio name=dest_mode value=1 %s></td> <td>%s</td>\n",
+ $mode == 1 ? "checked" : "", $text{'backup_dest1'};
+printf "<td colspan=3><input name=dest size=40 value='%s'> %s</td> </tr>\n",
+ $mode == 1 ? $dest[0] : "", &file_chooser_button("dest");
+
+printf "<tr> <td><input type=radio name=dest_mode value=3 %s></td> <td>%s</td>\n",
+ $mode == 3 ? "checked" : "", $text{'backup_dest3'};
+printf "<td colspan=3><input name=email size=40 value='%s'></td> </tr>\n",
+ $mode == 3 ? $dest[0] : "";
+
+printf "<tr> <td><input type=radio name=dest_mode value=2 %s></td>\n",
+ $mode == 2 ? "checked" : "";
+printf "<td>%s</td> <td><input name=ftphost size=20 value='%s'></td>\n",
+ $text{'backup_dest2'}, $mode == 2 ? $dest[2] : "";
+printf "<td>%s</td> <td><input name=ftpfile size=20 value='%s'></td> </tr>\n",
+ $text{'backup_ftpfile'}, $mode == 2 ? $dest[3] : "";
+printf "<tr> <td></td> <td>%s</td> <td><input name=ftpuser size=15 value='%s'></td>\n",
+ $text{'backup_ftpuser'}, $mode == 2 ? $dest[0] : "";
+printf "<td>%s</td> <td><input name=ftppass type=password size=15 value='%s'></td> </tr>\n",
+ $text{'backup_ftppass'}, $mode == 2 ? $dest[1] : "";
+print "</table></td> </tr>\n";
+
+print "</table></td></tr></table>\n";
+print "<input type=submit value='$text{'welf_ok'}'></form>\n";
+
+print "<hr>\n";
+&footer("", $text{'index_return'});
+
--- /dev/null
+# log_parser.pl
+# Functions for parsing this module's logs
+
+do 'itsecur-lib.pl';
+
+# parse_webmin_log(user, script, action, type, object, ¶ms)
+# Converts logged information from this module into human-readable form
+sub parse_webmin_log
+{
+local ($user, $script, $action, $type, $object, $p) = @_;
+if ($type eq "rule") {
+ local $source = &group_names($p->{'source'});
+ local $dest = &group_names($p->{'dest'});
+ return &text('log_'.$action.'_'.$type, $source, $dest);
+ }
+elsif ($type eq "service" || $type eq "group" || $type eq "user" ||
+ $type eq "time" || $type eq "sep") {
+ return &text('log_'.$action.'_'.$type,
+ "<tt>".&html_escape($object)."</tt>");
+ }
+elsif ($type eq "nat" || $type eq "pat" || $type eq "spoof") {
+ return $text{'log_'.$action.'_'.$type};
+ }
+elsif ($action eq "backup" || $action eq "restore") {
+ return $object ? &text('log_'.$action, "<tt>".&html_escape($object)."</tt>") : $text{'log_'.$action.'_file'};
+ }
+elsif ($action eq "import") {
+ return $text{'log_import_'.$type};
+ }
+elsif ($type eq "rules") {
+ if (defined($p->{'enabled'})) {
+ return &text('log_oldenable_rules',
+ $p->{'enabled'}, $p->{'disabled'});
+ }
+ else {
+ return &text('log_'.$action.'_rules', $p->{'count'});
+ }
+ }
+else {
+ return $text{'log_'.$action};
+ }
+}
+
--- /dev/null
+$nat_file="/etc/webmin/itsecur-firewall/nat";
+$groups_file="/etc/webmin/itsecur-firewall/groups";
+
+local ($iface, @nets, @maps);
+
+open(NAT, $nat_file) || return ( );
+open(GROUPS, ">>$groups_file");
+
+chop($iface = <NAT>);
+while(<NAT>) {
+ s/\r|\n//g;
+ if (/^(\S+)$/) {
+ }
+ elsif (/^(\S+)\t+(\S+)\t+(\S+)$/) {
+ print GROUPS "$2\t$2\n";
+ }
+ elsif (/^(\S+)\t+(\S+)$/) {
+ print GROUPS "$2\t$2\n";
+ }
+ }
+close(NAT);
+close(GROUPS);
+
--- /dev/null
+desc=Simple Firewall Creator
+os_support=*-linux freebsd
+category=net
+depends=init cron net acl 1.121
+version=2.59
--- /dev/null
+#!/usr/bin/perl
+# Actually do a restore
+
+require './itsecur-lib.pl';
+&can_edit_error("restore");
+&error_setup($text{'restore_err'});
+&ReadParseMime();
+
+# Validate inputs
+if (!$in{'src_def'}) {
+ if (-d $in{'src'}) {
+ $in{'src'} .= "/firewall.zip";
+ }
+ -r $in{'src'} || &error_cleanup($text{'restore_esrc'});
+ $file = $in{'src'};
+ }
+else {
+ $in{'file'} || &error_cleanup($text{'restore_efile'});
+ $file = &tempname();
+ open(FILE, ">$file");
+ print FILE $in{'file'};
+ close(FILE);
+ }
+if (!$in{'pass_def'}) {
+ $in{'pass'} || &error_cleanup($text{'backup_epass'});
+ }
+@what = split(/\0/, $in{'what'});
+@what || &error_cleanup($text{'restore_ewhat'});
+%what = map { $_, 1 } @what;
+
+# Extract the zip file
+$tempdir = &tempname();
+mkdir($tempdir, 0700);
+$pass = $in{'pass_def'} ? undef : "-P '$in{'pass'}'";
+$out = &backquote_logged("(cd $tempdir && unzip $pass '$file') 2>&1 </dev/null");
+&error_cleanup($text{'restore_epass2'}) if ($? && $out =~ /password/ &&
+ $in{'pass_def'});
+&error_cleanup($text{'restore_epass'}) if ($? && $out =~ /password/);
+&error_cleanup($text{'restore_etar'}) if ($?);
+
+# Work out the new state
+@rules = &list_rules(&if_exists("rules"));
+@services = &list_services(&if_exists("services"));
+@groups = &list_groups(&if_exists("groups"));
+($natiface, @nats) = &get_nat(&if_exists("nat"));
+@pats = &get_pat(&if_exists("pat"));
+($spoofiface, @spoofs) = &get_spoof(&if_exists("spoof"));
+($flood, $spoof) = &get_syn(&if_exists("syn"));
+@times = &list_times(&if_exists("times"));
+
+# Ensure that the new state would be consistent
+%groups = map { $_->{'name'}, $_ } @groups;
+%services = map { $_->{'name'}, $_ } @services;
+%times = map { $_->{'name'}, $_ } @times;
+foreach $r (@rules) {
+ foreach $g (split(/\s+/, $r->{'source'}), split(/\s+/, $r->{'dest'})) {
+ if ($g =~ /^\!?\@(.*)$/ && !$groups{$1}) {
+ push(@cerrs, &text('restore_egroup', "$1",
+ $r->{'num'}));
+ }
+ }
+ foreach $s (split(/,/, $r->{'service'})) {
+ if ($s ne "*" && !$services{$s}) {
+ push(@cerrs, &text('restore_eservice', $s,
+ $r->{'num'}));
+ }
+ }
+ if ($r->{'time'} ne "*" && !$times{$r->{'time'}}) {
+ push(@cerrs, &text('restore_etime', $r->{'time'},
+ $r->{'num'}));
+ }
+ }
+foreach $n (@nats) {
+ if (!ref($n) && $n =~ /^\!?(.*)$/ && !$groups{$1}) {
+ push(@cerrs, &text('restore_enat', $1));
+ }
+ }
+foreach $p (@pats) {
+ if (!$services{$p->{'service'}}) {
+ push(@cerrs, &text('restore_epat', $p->{'service'}));
+ }
+ }
+foreach $n (@nats) {
+ if (!ref($n) && $n =~ /^\!?(.*)$/ && !$groups{$1}) {
+ push(@cerrs, &text('restore_enat', $1));
+ }
+ }
+if (@cerrs) {
+ # Tell the user
+ &header($text{'restore_title'}, "",
+ undef, undef, undef, undef, &apply_button());
+ print "<hr>\n";
+
+ print "<p>$text{'restore_cerr'}<br>\n";
+ print "<ul>\n";
+ foreach $c (@cerrs) {
+ print "<li>$c\n";
+ }
+ print "</ul>\n";
+
+ print "<hr>\n";
+ &footer("", $text{'index_return'});
+ exit;
+ }
+
+# Copy to the config directory
+&automatic_backup();
+&lock_itsecur_files();
+foreach $w (@what) {
+ if ($w eq "ipsec") {
+ # Copy ipsec config to proper location
+ if (&has_ipsec() && -r "$tempdir/ipsec.conf") {
+ &lock_file($ipsec::config{'file'});
+ &lock_file($ipsec::config{'secrets'});
+ system("cp $tempdir/ipsec.conf $ipsec::config{'file'}");
+ system("cp $tempdir/ipsec.secrets $ipsec::config{'secrets'}");
+ &unlock_file($ipsec::config{'file'});
+ &unlock_file($ipsec::config{'secrets'});
+ }
+ }
+ elsif ($w eq "users") {
+ # Copy Webmin user files
+ &lock_file("$config_directory/miniserv.users");
+ &lock_file("$config_directory/webmin.acl");
+ system("cp $tempdir/miniserv.users $config_directory/miniserv.users");
+ system("cp $tempdir/webmin.acl $config_directory/webmin.acl");
+ foreach $a (glob("$tempdir/*.acl")) {
+ local $fn = $a;
+ $fn =~ s/^.*\///;
+ if ($fn ne "webmin.acl") {
+ &lock_file("$module_config_directory/$fn");
+ system("cp $a $module_config_directory/$fn");
+ &unlock_file("$module_config_directory/$fn");
+ }
+ }
+ &unlock_file("$config_directory/miniserv.users");
+ &unlock_file("$config_directory/webmin.acl");
+ &restart_miniserv();
+ }
+ elsif ($w eq "searches") {
+ # Copy searches directory
+ mkdir($searches_directory, 0755);
+ system("cp $tempdir/searches/* $searches_directory >/dev/null 2>&1");
+ }
+ elsif ($w eq "config") {
+ # Update module config - except system type
+ local %newconfig;
+ &read_file("$tempdir/config", \%newconfig);
+ $newconfig{'type'} = $config{'type'};
+ &write_file("$module_config_directory/config", \%newconfig);
+ }
+ else {
+ if (-r "$tempdir/$w") {
+ system("cp $tempdir/$w $module_config_directory");
+ }
+ }
+ }
+&unlock_itsecur_files();
+
+# Tell the user
+&header($text{'restore_title'}, "",
+ undef, undef, undef, undef, &apply_button());
+print "<hr>\n";
+
+print "<p>",&text('restore_done'),"<p>\n";
+&cleanup();
+
+print "<hr>\n";
+&footer("", $text{'index_return'});
+&remote_webmin_log("restore", undef, $in{'src_def'} ? undef : $in{'src'});
+
+sub error_cleanup
+{
+&cleanup();
+&error(@_);
+}
+
+sub cleanup
+{
+unlink($file) if ($in{'src_def'});
+system("rm -rf $tempdir") if ($tempdir);
+}
+
+sub if_exists
+{
+return -r "$tempdir/$_[0]" && $what{$_[0]} ? "$tempdir/$_[0]" : undef;
+}
+
--- /dev/null
+#!/usr/bin/perl
+# Save bandwidth monitoring settings
+
+require './itsecur-lib.pl';
+&can_edit_error("bandwidth");
+&ReadParse();
+&foreign_require("bandwidth", "bandwidth-lib.pl");
+
+if ($in{'enabled'}) {
+ # Enable in config, so that log rules are generated
+ $config{'bandwidth'} = $in{'iface'};
+ &save_module_config();
+
+ # Setup firewall and bandwidth modules
+ $bandwidth::config{'iface'} = $in{'iface'};
+ &bandwidth::save_module_config();
+ $firewall::config{'direct'} = 1;
+ &firewall::save_module_config();
+
+ # Set up syslog.conf entry
+ $conf = &syslog::get_config();
+ $sysconf = &bandwidth::find_sysconf($conf);
+ if (!$sysconf) {
+ &lock_file($syslog::config{'syslog_conf'});
+ &syslog::create_log({ 'file' => $bandwidth::bandwidth_log,
+ 'active' => 1,
+ 'sel' => [ "kern.=debug" ] });
+ &unlock_file($syslog::config{'syslog_conf'});
+ $err = &syslog::restart_syslog();
+ &error($err) if ($err);
+ }
+
+ # Set up cron job
+ $job = &bandwidth::find_cron_job();
+ if (!$job) {
+ &cron::create_wrapper($bandwidth::cron_cmd, $bandwidth::module_name, "rotate.pl");
+ $job = { 'user' => 'root',
+ 'active' => 1,
+ 'command' => $bandwidth::cron_cmd,
+ 'special' => 'hourly' };
+ &lock_file(&cron::cron_file($job));
+ &cron::create_cron_job($job);
+ &unlock_file(&cron::cron_file($job));
+ }
+ }
+else {
+ # Disable in config
+ $config{'bandwidth'} = undef;
+ &save_module_config();
+
+ # Remove cron job
+ $job = &bandwidth::find_cron_job();
+ if ($job) {
+ &lock_file(&cron::cron_file($job));
+ &cron::delete_cron_job($job);
+ &unlock_file(&cron::cron_file($job));
+ }
+
+
+ }
+
+&redirect("");
+
--- /dev/null
+#!/usr/bin/perl
+# save_group.cgi
+# Create, update or delete a host group
+
+require './itsecur-lib.pl';
+
+sub check_ip_in_groups{
+ my $my_group;
+}
+
+&can_edit_error("groups");
+&ReadParse();
+@groups = &list_groups();
+if (!$in{'new'}) {
+ $group = $groups[$in{'idx'}];
+ }
+&lock_itsecur_files();
+
+if ($in{'delete'}) {
+ # Check if in use
+ &error_setup($text{'group_err2'});
+ @rules = &list_rules();
+ foreach $r (@rules) {
+ &error($text{'group_einuse'})
+ if ($r->{'source'} =~ /\@\Q$group->{'name'}\E/ ||
+ $r->{'dest'} =~ /\@\Q$group->{'name'}\E/);
+ }
+ local @maps;
+ ($iface, @nets) = &get_nat();
+ @maps = grep { ref($_) } @nets;
+ @nets = grep { !ref($_) } @nets;
+
+ local ($net,$local_net);
+ foreach $net (@nets) {
+ $local_net = $net;
+ $local_net =~ s/^\!//;
+ &error($text{'group_in_use_nat'})
+ if ($local_net eq $group->{'name'} );
+ }
+ local ($m);
+ foreach $m (@maps) {
+ &error($text{'group_in_use_nat'})
+ if (@$m->[1] eq $group->{'name'} );
+ }
+
+ local $g;
+ foreach $g (@groups) {
+ next if ($g eq $group);
+ foreach $m (@{$g->{'members'}}) {
+
+ &error($text{'group_in_use_group'}." $g->{name}")
+ if ($m eq "\@$group->{'name'}" );
+ }
+ }
+
+ # Just delete this group
+ splice(@groups, $in{'idx'}, 1);
+ #&automatic_backup();
+ #TODO: Delete from other groups !!
+ }
+else {
+ # Validate inputs
+ &error_setup($text{'group_err'});
+ $in{'name'} =~ /^\S+$/ || &error($text{'group_ename'});
+ if ($in{'new'} || $in{'name'} ne $group->{'name'}) {
+ # Check for clash
+ ($clash) = grep { lc($_->{'name'}) eq lc($in{'name'}) } @groups;
+ $clash && &error($text{'group_eclash'});
+ }
+ for($i=0; defined($in{"member_$i"}); $i++) {
+ next if (!$in{"member_$i"});
+ local $ht = &valid_host($in{"member_$i"});
+ $ht || &error(&text('group_emember', $in{"member_$i"}));
+ if ($ht == 2 && $in{'resolv'}) {
+ local $rs = &to_ipaddress($in{"member_$i"});
+ $in{"member_$i"} = $rs if ($rs);
+ }
+ if ($ht == 4 && $in{"neg_$i"}) {
+ &error(&text('group_eneg', $in{"member_$i"}));
+ }
+ push(@members, $in{"neg_$i"}.$in{"member_$i"});
+ }
+ for($i=0; defined($in{"group_$i"}); $i++) {
+ next if (!$in{"group_$i"});
+ $in{"group_$i"} eq $in{'name'} &&
+ &error($text{'group_eself'});
+ push(@members, "@".$in{"group_$i"});
+ }
+ @members || &error($text{'group_emembers'});
+ $oldname = $group->{'name'};
+ $group->{'name'} = $in{'name'};
+ $group->{'members'} = \@members;
+
+ if ($in{'new'}) {
+ push(@groups, $group);
+ }
+ #@sorted = sort { $a cmp $b } @groups;
+ #@sorted = sort @groups;
+ #@groups = @sorted;
+ if (!$in{'new'} && $oldname ne $group->{'name'}) {
+ # Has been re-named .. update all rules!
+ @rules = &list_rules();
+ foreach $r (@rules) {
+ $r->{'source'} =~ s/\@\Q$oldname\E$/\@$group->{'name'}/;
+ $r->{'dest'} =~ s/\@\Q$oldname\E$/\@$group->{'name'}/;
+ }
+ &save_rules(@rules);
+
+ # And update all other groups
+ foreach $g (@groups) {
+ next if ($g eq $group);
+ foreach $m (@{$g->{'members'}}) {
+ $m = "\@$group->{'name'}"
+ if ($m eq "\@$oldname");
+ }
+ }
+ local @maps;
+ ($iface, @nets) = &get_nat();
+ @maps = grep { ref($_) } @nets;
+ @nets = grep { !ref($_) } @nets;
+ local ($m,$net);
+
+ foreach $net (@nets) {
+ if ($net eq "$oldname") {
+ $net = "$group->{'name'}";
+ } elsif ($net eq "!$oldname") {
+ $net = "!$group->{'name'}";
+ }
+ }
+ foreach $m (@maps) {
+ if (@$m->[1] eq "$oldname") {
+ @$m->[1] = "$group->{'name'}";
+ }
+ }
+ &save_nat($iface, @nets, @maps);
+ }
+ }
+
+&save_groups(@groups);
+$from = $in{'from'} || "groups";
+&unlock_itsecur_files();
+&remote_webmin_log($in{'delete'} ? "delete" : $in{'new'} ? "create" : "update",
+ "group", $group->{'name'}, $group);
+&redirect("list_${from}.cgi");
+
--- /dev/null
+#!/usr/bin/perl
+# save_nat.cgi
+# Update NAT setting
+
+require './itsecur-lib.pl';
+&can_edit_error("nat");
+&ReadParse();
+&lock_itsecur_files();
+
+&error_setup($text{'nat_err'});
+if ($in{'nat'}) {
+ $iface = $in{'iface'} || $in{'iface_other'};
+ $iface =~ /^[a-z0-9:\.]+$/ || &error($text{'nat_eiface'});
+ }
+for($i=0; defined($n = $in{"net_$i"}); $i++) {
+ push(@nets, $n) if ($n);
+ }
+for($i=0; defined($n = $in{"excl_$i"}); $i++) {
+ push(@nets, "!$n") if ($n);
+ }
+local @dests;
+for($i=0; defined($e = $in{"ext_$i"}); $i++) {
+ next if (!$e);
+ #gethostbyname($e) || &error(&text('nat_eext', $i+1));
+ valid_host($e) || &error(&text('nat_eext', $i+1));
+ #is_one_host("\@$e") && &error(&text('nat_eext', $i+1));
+ $n = $in{"int_$i"};
+ #gethostbyname($n) || &error(&text('nat_eint', $i+1));
+ ##valid_host($n) || &error(&text('nat_eint', $i+1));
+ is_one_host("\@$n") && &error(&text('nat_eint', $i+1));
+ $v = $in{"virt_$i"};
+ push(@maps, [ $e, $n, $v ? ( $v ) : ( ) ]);
+ }
+&automatic_backup();
+&save_nat($iface, @nets, @maps);
+&unlock_itsecur_files();
+&remote_webmin_log("update", "nat");
+&redirect("");
+
--- /dev/null
+#!/usr/bin/perl
+# save_nat.cgi
+# Update NAT setting
+
+require './itsecur-lib.pl';
+&can_edit_error("nat");
+&ReadParse();
+&lock_itsecur_files();
+
+&error_setup($text{'nat_err'});
+if ($in{'nat'}) {
+ $iface = $in{'iface'} || $in{'iface_other'};
+ $iface =~ /^[a-z0-9:\.]+$/ || &error($text{'nat_eiface'});
+ }
+for($i=0; defined($n = $in{"net_$i"}); $i++) {
+ push(@nets, $n) if ($n);
+ }
+for($i=0; defined($n = $in{"excl_$i"}); $i++) {
+ push(@nets, "!$n") if ($n);
+ }
+for($i=0; defined($e = $in{"ext_$i"}); $i++) {
+ next if (!$e);
+ gethostbyname($e) || &error(&text('nat_eext', $i+1));
+ $n = $in{"int_$i"};
+ gethostbyname($n) || &error(&text('nat_eint', $i+1));
+ $v = $in{"virt_$i"};
+ push(@maps, [ $e, $n, $v ? ( $v ) : ( ) ]);
+ }
+&automatic_backup();
+&save_nat2($iface, @nets, @maps);
+&unlock_itsecur_files();
+&remote_webmin_log("update", "nat2");
+&redirect("");
+
--- /dev/null
+#!/usr/bin/perl
+# save_pat.cgi
+# Save incoming forwarded ports
+
+require './itsecur-lib.pl';
+&can_edit_error("pat");
+&ReadParse();
+&lock_itsecur_files();
+
+&error_setup($text{'pat_err'});
+for($i=0; defined($s = $in{"service_$i"}); $i++) {
+ next if (!$s);
+ $h = $in{"host_$i"};
+ gethostbyname($h) || &error(&text('pat_ehost', $i+1));
+ $iface = $in{"iface_$i"};
+ $iface eq "" || $iface =~ /^[a-z0-9:\.]+$/ ||
+ &error(&text('pat_eiface', $i+1));
+ push(@forwards, { 'service' => $s,
+ 'host' => $h,
+ 'iface' => $iface });
+ }
+
+&automatic_backup();
+&save_pat(@forwards);
+&unlock_itsecur_files();
+&remote_webmin_log("update", "pat");
+&redirect("");
+
--- /dev/null
+#!/usr/bin/perl
+# Set up remote logging, creating a webmin server if needed
+
+require './itsecur-lib.pl';
+&foreign_require("servers", "servers-lib.pl");
+&can_edit_error("remote");
+&ReadParse();
+
+# Validate inputs
+&error_setup($text{'remote_err'});
+if (!$in{'host_def'}) {
+ gethostbyname($in{'host'}) || &error($text{'remote_ehost'});
+ $in{'user'} || &error($text{'remote_euser'});
+ $server = &save_remote($in{'host'}, $in{'port'},
+ $in{'user'}, $in{'pass'}, 1, 1);
+ }
+else {
+ # Just stop logging
+ &save_remote(undef, undef, undef, undef, 0, 1);
+ }
+&webmin_log("remote");
+&redirect("");
+
+
--- /dev/null
+#!/usr/bin/perl
+# save_rule.cgi
+# Create, update or delete a firewall rule
+
+require './itsecur-lib.pl';
+&can_edit_error("rules");
+&ReadParse();
+@rules = &list_rules();
+@groups = &list_groups();
+if (!$in{'new'}) {
+ $rule = $rules[$in{'idx'}];
+ }
+&lock_itsecur_files();
+
+if ($config{'rusure'} && !$in{'confirm'} && !$in{'new'}) {
+ # Ask for confirmation before making this change
+ &header($text{'rule_title2'}, "",
+ undef, undef, undef, undef, &apply_button());
+ $rule = $rules[$in{'idx'}];
+ print "<hr>\n";
+
+ print "<form action=save_rule.cgi>\n";
+ print "<center>",&text($in{'delete'} ? 'rule_rusured'
+ : 'rule_rusures'),"<p>\n";
+ foreach $i (keys %in) {
+ foreach $v (split(/\0/, $in{$i})) {
+ print "<input type=hidden name=$i value='",
+ &html_escape($v),"'>\n";
+ }
+ }
+ print "<input type=submit name=confirm value='$text{'rule_goahead'}'>\n";
+ print "</center></form>\n";
+
+ print "<hr>\n";
+ &footer("list_rules.cgi", $text{'rules_return'});
+ exit;
+ }
+
+if ($in{'delete'}) {
+ # Just take out rule
+ splice(@rules, $in{'idx'}, 1);
+ }
+else {
+ # Validate and store inputs
+ &error_setup($text{'rule_err'});
+ $rule->{'desc'} = $in{'desc'} || "*";
+ foreach $s ('source', 'dest') {
+ if ($in{"${s}_mode"} == 0) {
+ $rule->{$s} = "*";
+ }
+ elsif ($in{"${s}_mode"} == 1) {
+ &valid_host($in{"${s}_host"}) ||
+ &error($text{"rule_e${s}"});
+ if ($in{"${s}_resolv"}) {
+ local $rs = &to_ipaddress($in{"${s}_host"});
+ $in{"${s}_host"} = $rs if ($rs);
+ }
+ if ($in{"${s}_name"}) {
+ # Add a group for this network/host
+ $in{"${s}_name"} =~ /^\S+$/ ||
+ &error($text{'rule_ename'});
+ $rule->{$s} = "@".$in{"${s}_name"};
+ local @mems = ( $in{"${s}_host"} );
+ push(@groups, { 'name' => $in{"${s}_name"},
+ 'members' => \@mems });
+ }
+ else {
+ $rule->{$s} = $in{"${s}_host"};
+ }
+ }
+ elsif ($in{"${s}_mode"} == 2) {
+ $rule->{$s} = join(" ", map { '@'.$_ }
+ split(/\0/, $in{"${s}_group"}));
+ $rule->{$s} || &error($text{'rule_egroups'});
+ }
+ elsif ($in{"${s}_mode"} == 3) {
+ $rule->{$s} = '%'.$in{"${s}_iface"};
+ }
+ $rule->{$s} = "!".$rule->{$s} if ($in{"${s}_not"});
+ }
+ if ($in{"service_mode"} == 0) {
+ $rule->{'service'} = "*";
+ }
+ else {
+ $rule->{'service'} = join(",", split(/\0/, $in{"service"}));
+ $rule->{'service'} || &error($text{'rule_eservices'});
+ }
+ $rule->{'service'} = "!".$rule->{'service'} if ($in{'snot'});
+ $rule->{'action'} = $in{'action'};
+ $rule->{'log'} = int($in{'log'});
+ $rule->{'time'} = $in{'time_def'} ? "*" : $in{'time'};
+ $rule->{'enabled'} = $in{'enabled'};
+
+ if ($in{'new'}) {
+ # Add to list at chosen position
+ if ($in{'pos'} == -1) {
+ push(@rules, $rule);
+ }
+ else {
+ splice(@rules, $in{'pos'}, 0, $rule);
+ }
+ }
+ else {
+ # Maybe change position
+ foreach $r (grep { $_ ne $rule } @rules) {
+ if ($r->{'index'} == $in{'pos'}) {
+ push(@newrules, $rule);
+ }
+ push(@newrules, $r);
+ }
+ push(@newrules, $rule) if ($in{'pos'} == -1);
+ @rules = @newrules;
+ }
+ }
+
+# Save rules list
+&automatic_backup();
+&save_rules(@rules);
+&save_groups(@groups);
+&unlock_itsecur_files();
+&remote_webmin_log($in{'delete'} ? "delete" : $in{'new'} ? "create" : "update",
+ "rule", $rule->{'index'}+1, $rule);
+&redirect("list_rules.cgi");
+
--- /dev/null
+#!/usr/bin/perl
+# Save the current search
+
+require './itsecur-lib.pl';
+&can_edit_error("report");
+&ReadParse();
+
+# Validate inputs
+$in{'save_name'} =~ /\S/ && $in{'save_name'} !~ /\.\./ ||
+ &error($text{'report_esave'});
+%search = ( 'save_name', $in{'save_name'} );
+foreach $f (@search_fields) {
+ foreach $i (keys %in) {
+ if ($i =~ /^\Q$f\E_/) {
+ $search{$i} = $in{$i};
+ }
+ }
+ }
+&save_search(\%search);
+&redirect("list_report.cgi?save_name=".&urlize($in{'save_name'}));
+
--- /dev/null
+#!/usr/bin/perl
+# Create, update or delete a rules section separator
+
+require './itsecur-lib.pl';
+&can_edit_error("rules");
+&ReadParse();
+@rules = &list_rules();
+if (!$in{'new'}) {
+ $rule = $rules[$in{'idx'}];
+ }
+&lock_itsecur_files();
+
+if ($in{'delete'}) {
+ # Just take out rule
+ splice(@rules, $in{'idx'}, 1);
+ }
+else {
+ # Validate and store inputs
+ &error_setup($text{'sep_err'});
+ $in{'desc'} || &error($text{'sep_edesc'});
+ $rule->{'desc'} = $in{'desc'};
+ $rule->{'sep'} = 1;
+
+ if ($in{'new'}) {
+ # Add to list at chosen position
+ if ($in{'pos'} == -1) {
+ push(@rules, $rule);
+ }
+ else {
+ splice(@rules, $in{'pos'}, 0, $rule);
+ }
+ }
+ else {
+ # Maybe change position
+ foreach $r (grep { $_ ne $rule } @rules) {
+ if ($r->{'index'} == $in{'pos'}) {
+ push(@newrules, $rule);
+ }
+ push(@newrules, $r);
+ }
+ push(@newrules, $rule) if ($in{'pos'} == -1);
+ @rules = @newrules;
+ }
+ }
+
+# Save rules list
+&save_rules(@rules);
+&unlock_itsecur_files();
+&remote_webmin_log($in{'delete'} ? "delete" : $in{'new'} ? "create" : "update",
+ "sep", $rule->{'index'}+1, $rule);
+&redirect("list_rules.cgi");
+
--- /dev/null
+#!/usr/bin/perl
+# save_service.cgi
+# Create, update or delete a service
+
+require './itsecur-lib.pl';
+&can_edit_error("services");
+&ReadParse();
+&lock_itsecur_files();
+@servs = &list_services();
+if (!$in{'new'}) {
+ $serv = $servs[$in{'idx'}];
+ }
+
+if ($in{'delete'}) {
+ # Check if in use by a rule or other service
+ &error_setup($text{'service_err2'});
+ @rules = &list_rules();
+ foreach $r (@rules) {
+ @rservs = split(/,/, $r->{'service'});
+ &error($text{'service_einuse'})
+ if (&indexof($serv->{'name'}, @rservs) >= 0);
+ }
+ foreach $s (@servs) {
+ &error($text{'service_einuse2'})
+ if (&indexof($serv->{'name'}, @{$s->{'others'}}) >= 0);
+ }
+
+ # Just delete this service
+ splice(@servs, $in{'idx'}, 1);
+ &automatic_backup();
+ }
+else {
+ # Validate inputs
+ &error_setup($text{'service_err'});
+ $in{'name'} =~ /\S/ || &error($text{'service_ename'});
+ @others = split(/\0/, $in{'others'});
+ for($i=0; defined($in{"proto_$i"}); $i++) {
+ next if (!$in{"proto_$i"});
+ if ($in{"proto_$i"} eq 'icmp') {
+ $in{"port_$i"} =~ /^\d+$/ ||
+ $in{"port_$i"} eq '*' ||
+ &error(&text('service_eicmp', $i+1));
+ }
+ elsif ($in{"proto_$i"} eq 'ip') {
+ $in{"port_$i"} =~ /^\d+$/ ||
+ &error(&text('service_eip', $i+1));
+ }
+ else {
+ $in{"port_$i"} =~ /^\d+$/ ||
+ $in{"port_$i"} =~ /^\d+\-\d+$/ ||
+ $in{"port_$i"} =~ /^\d+(\s+\d+)*$/ ||
+ &error(&text('service_eport', $i+1));
+ }
+ push(@protos, $in{"proto_$i"});
+ push(@ports, $in{"port_$i"});
+ }
+ @protos || @others || &error($text{'service_enone'});
+ #&unique(@protos) == 1 || &error($text{'service_eprotos'});
+ if ($in{'new'} || lc($in{'name'}) ne lc($serv->{'name'})) {
+ # Check for clash
+ ($clash) = grep { lc($_->{'name'}) eq lc($in{'name'}) } @servs;
+ $clash && &error($text{'service_eclash'});
+ }
+ $oldname = $serv->{'name'};
+ $serv->{'name'} = $in{'name'};
+ $serv->{'protos'} = \@protos;
+ $serv->{'ports'} = \@ports;
+ $serv->{'others'} = \@others;
+
+ if ($in{'new'}) {
+ push(@servs, $serv);
+ }
+
+ &automatic_backup();
+ if (!$in{'new'} && $oldname ne $serv->{'name'}) {
+ # Has been re-named .. update all rules!
+ @rules = &list_rules();
+ foreach $r (@rules) {
+ $r->{'service'} = &replace_service_name(
+ $r->{'service'}, $oldname, $serv->{'name'});
+ }
+ &save_rules(@rules);
+
+ # Also update PAT services
+ @forwards = &get_pat();
+ foreach $f (@forwards) {
+ $f->{'service'} = &replace_service_name(
+ $f->{'service'}, $oldname, $serv->{'name'});
+ }
+ &save_pat(@forwards);
+
+ # Also update other services
+ foreach $s (@servs) {
+ $idx = &indexof($oldname, @{$s->{'others'}});
+ if ($idx >= 0) {
+ $s->{'others'}->[$idx] = $serv->{'name'};
+ }
+ }
+ }
+ }
+
+&save_services(@servs);
+&unlock_itsecur_files();
+&remote_webmin_log($in{'delete'} ? "delete" : $in{'new'} ? "create" : "update",
+ "service", $serv->{'name'}, $serv);
+&redirect("list_services.cgi");
+
+# replace_service_name(comma-list, old, new)
+sub replace_service_name
+{
+local @servs = split(/,/, $_[0]);
+foreach $s (@servs) {
+ $s = $_[2] if ($s eq $_[1]);
+ }
+return join(",", @servs);
+}
+
--- /dev/null
+#!/usr/bin/perl
+# save_spoof.cgi
+# Save spoofing settings
+
+require './itsecur-lib.pl';
+&can_edit_error("spoof");
+&lock_itsecur_files();
+&ReadParse();
+
+&error_setup($text{'spoof_err'});
+if ($in{'spoof'}) {
+ $iface = $in{'iface'} || $in{'iface_other'};
+ $iface =~ /^[a-z0-9:\.]+$/ || &error($text{'nat_eiface'});
+ }
+else {
+ }
+@nets = split(/\s+/, $in{'nets'});
+foreach $n (@nets) {
+ $n =~ /^([0-9\.]+)\/(\d+)$/ &&
+ $2 >= 0 && $2 <= 32 &&
+ &check_ipaddress("$1") ||
+ &error(&text('spoof_enet', $n));
+ }
+!$iface || @nets || &error($text{'spoof_enets'});
+&automatic_backup();
+&save_spoof($iface, @nets);
+&unlock_itsecur_files();
+&remote_webmin_log("update", "spoof");
+&redirect("");
+
--- /dev/null
+#!/usr/bin/perl
+# save_syn.cgi
+# Save syn settings
+
+require './itsecur-lib.pl';
+&can_edit_error("syn");
+&lock_itsecur_files();
+&ReadParse();
+
+&error_setup($text{'syn_err'});
+$flood = $in{'flood'};
+$spoof = $in{'spoof'};
+$fin = $in{'fin'};
+&automatic_backup();
+&save_syn($flood, $spoof, $fin);
+&unlock_itsecur_files();
+&remote_webmin_log("update", "syn");
+&redirect("");
+
--- /dev/null
+#!/usr/bin/perl
+# save_time.cgi
+# Create, update or delete a time range
+
+require './itsecur-lib.pl';
+&can_edit_error("times");
+&lock_itsecur_files();
+&ReadParse();
+@times = &list_times();
+if (!$in{'new'}) {
+ $time = $times[$in{'idx'}];
+ }
+
+if ($in{'delete'}) {
+ # Check if in use
+ &error_setup($text{'time_err2'});
+ @rules = &list_rules();
+ foreach $r (@rules) {
+ &error($text{'time_einuse'})
+ if ($r->{'time'} eq $time->{'name'});
+ }
+
+ # Just delete this time
+ splice(@times, $in{'idx'}, 1);
+ &automatic_backup();
+ }
+else {
+ # Validate inputs
+ &error_setup($text{'time_err'});
+ $in{'name'} =~ /^\S+$/ || &error($text{'time_ename'});
+ if ($in{'new'} || $in{'name'} ne $time->{'name'}) {
+ # Check for clash
+ ($clash) = grep { lc($_->{'name'}) eq lc($in{'name'}) } @times;
+ $clash && &error($text{'time_eclash'});
+ }
+ if (!$in{'hours_def'}) {
+ foreach $t ('from', 'to') {
+ $tm = $in{$t};
+ $tm =~ /^(\d+):(\d+)$/ || &error($text{'time_e'.$t});
+ $1 >= 0 && $1 < 24 || &error($text{'time_ehour'.$t});
+ $2 >= 0 && $2 < 60 || &error($text{'time_emin'.$t});
+ }
+ }
+ if (!$in{'days_def'}) {
+ @days = split(/\0/, $in{'days'});
+ @days || &error($text{'time_edays'});
+ }
+ $oldname = $time->{'name'};
+ $time->{'name'} = $in{'name'};
+ $time->{'hours'} = $in{'hours_def'} ? "*" :
+ $in{'from'}."-".$in{'to'};
+ $time->{'days'} = $in{'days_def'} ? "*" :
+ join(",", @days);
+
+ if ($in{'new'}) {
+ push(@times, $time);
+ }
+
+ &automatic_backup();
+ if (!$in{'new'} && $oldname ne $time->{'name'}) {
+ # Has been re-named .. update all rules!
+ @rules = &list_rules();
+ foreach $r (@rules) {
+ if ($r->{'time'} eq $oldname) {
+ $r->{'time'} = $time->{'name'};
+ }
+ }
+ &save_rules(@rules);
+ }
+ }
+
+&save_times(@times);
+&unlock_itsecur_files();
+&remote_webmin_log($in{'delete'} ? "delete" : $in{'new'} ? "create" : "update",
+ "time", $time->{'name'}, $time);
+&redirect("list_times.cgi");
+
--- /dev/null
+#!/usr/bin/perl
+# save_user.cgi
+# Create, update or delete a Webmin user
+
+require './itsecur-lib.pl';
+&foreign_require("acl", "acl-lib.pl");
+&can_edit_error("users");
+&ReadParse();
+&lock_itsecur_files();
+@users = &acl::list_users();
+if (!$in{'new'}) {
+ ($user) = grep { $_->{'name'} eq $in{'old'} } @users;
+ }
+
+if ($in{'delete'}) {
+ # Delete him
+ &automatic_backup();
+ &acl::delete_user($user->{'name'});
+ }
+else {
+ # Validate and store inputs
+ &error_setup($text{'user_err'});
+ $in{'name'} || &error($text{'user_ename'});
+ $in{'name'} =~ /^[A-z0-9\-\_\.]+$/ ||
+ &error(&acl::text('save_ename', $in{'name'}));
+ $in{'name'} eq 'webmin' && &error($acl::text{'save_enamewebmin'});
+ if (!$in{'old'} || $in{'old'} ne $in{'name'}) {
+ foreach $u (@users, &acl::list_groups()) {
+ if ($u->{'name'} eq $in{'name'}) {
+ &error(&acl::text('save_edup', $in{'name'}));
+ }
+ }
+ }
+ $user->{'name'} = $in{'name'};
+ if (!$in{'same'}) {
+ if (defined(&acl::encrypt_password)) {
+ $user->{'pass'} = &acl::encrypt_password($in{'pass'});
+ }
+ else {
+ $salt = substr(time(), -8);
+ $user->{'pass'} = crypt($in{'pass'}, $salt);
+ }
+ }
+ $locked = ($user->{'pass'} =~ /^\*LK\*/);
+ if ($in{'enabled'} && $locked) {
+ $user->{'pass'} = substr($user->{'pass'}, 4);
+ }
+ elsif (!$in{'enabled'} && !$locked) {
+ $user->{'pass'} = "*LK*".$user->{'pass'};
+ }
+
+ # Validate and save IPs
+ if ($in{'ipmode'}) {
+ @hosts = split(/\s+/, $in{"ips"});
+ if (!@hosts) { &error($acl::text{'save_enone'}); }
+ foreach $h (@hosts) {
+ if ($h =~ /^([0-9\.]+)\/([0-9\.]+)$/) {
+ &check_ipaddress($1) ||
+ &error(&acl::text('save_enet', $1));
+ &check_ipaddress($2) ||
+ &error(&acl::text('save_emask', $2));
+ $i = $h;
+ }
+ elsif ($h =~ /^[0-9\.]+$/) {
+ &check_ipaddress($h) ||
+ &error(&acl::text('save_eip', $h));
+ $i = $h;
+ }
+ elsif ($h =~ /^\*\.(\S+)$/) {
+ $i = $h;
+ }
+ elsif ($h eq 'LOCAL') {
+ $i = 'LOCAL';
+ }
+ elsif (!($i = join('.',unpack("CCCC",inet_aton($h))))) {
+ &error(&acl::text('save_ehost', $h));
+ }
+ push(@ips, $i);
+ }
+ }
+ delete($user->{'allow'});
+ delete($user->{'deny'});
+ if ($in{'ipmode'} == 1) {
+ $user->{'allow'} = join(" ", @ips);
+ }
+ elsif ($in{'ipmode'} == 2) {
+ $user->{'deny'} = join(" ", @ips);
+ }
+
+ &automatic_backup();
+
+ $user->{'modules'} = [ split(/\0/, $in{'mods'}) ];
+ if ($in{'new'}) {
+ # Create the user
+ &acl::create_user($user);
+ }
+ else {
+ # Modify the user
+ &acl::modify_user($in{'old'}, $user);
+ }
+
+ # Update his ACL
+ require "./acl_security.pl";
+ %uaccess = &get_module_acl($in{'name'});
+ &acl_security_save(\%uaccess);
+ if ($in{'new'}) {
+ $uaccess{'noconfig'} = 1;
+ }
+ &save_module_acl(\%uaccess, $in{'name'});
+ }
+&acl::restart_miniserv();
+&unlock_itsecur_files();
+&remote_webmin_log($in{'delete'} ? "delete" : $in{'new'} ? "create" : "update",
+ "user", $user->{'name'}, $user);
+&redirect("list_users.cgi");
+
--- /dev/null
+AOL TCP 5190 #AOL Instant Messanger
+AP-Defender TCP 2626 #Defender Authentication Service
+BackDoor-Setup TCP 5000 #Use by Boinet Lite, Blazer 5, Bubbel Trojans
+Backage TCP 411 #Backage Trojan
+BackDoor-G TCP 1243 #Also used by Subseven, Tiles Trojans
+Citrix-ICA TCP 1494 #ICA Gerneral Service
+Connect-BackDoor TCP 4000 #Also used by SkyDance Trojan
+CrackDown TCP 4444 #Crackdown Trojan
+DaCryptic TCP 1074 #DaCryptic Trojan
+DameWare TCP 6129 #DameWare Mini Remote Control Protocol
+DayTime TCP 13 UDP 13 #DayTime Server Protocol
+DerSphere TCP 1000 #Also used by Insane Network Trojans
+DerSphere-II TCP 2000 #Also used by SennaSpy Trojan Generator
+Direct-Connect TCP 411-412 #Direct Connect P2P Application
+Discard TCP 9 #Discard Server Protocol
+DNS TCP 53 UDP 53 #Domain Name Service
+Echo TCP 7 #Echo Protocol
+eDonkey-4661 TCP 4661 #eDonkey Protocol
+eDonkey-4662 TCP 4662 #eDonkey Protocol
+nTrust-Admin TCP 710 #nTrust CA Administration Service
+nTrust-Key-Mgmt TCP 709 #nTrust Key Management Service
+ERP-1 TCP 12345-12349 #ERP Service
+Exec TCP 512 #Remote Execution
+Finger TCP 79 #UNIX Finger Protocol
+Freak2K TCP 7001 #Also used by Freak88, NetSnooper Gold Trojans
+FTP TCP 21 #File Transfer Protocol
+GateCrasher TCP 6970 #GateCrasher Trojan
+GNUtella-RTR TCP 6347 UDP 6347 #Also used by BearShare, ToadNode, LimeWire
+GNUtella TCP 6346 UDP 6346 #Also used by BearShare, ToadNode, LimeWire
+Gopher TCP 70 #Internet Gopher Protocol
+GoToMyPC TCP 8200 #GotoMy PC
+H323 TCP 1720 #Video Conference Transmission over IP
+HackaTACK-31785 TCP 31785 #HackAttack
+HackaTACK-31787 TCP 31787 #HackAttack
+HackaTACK-31788 TCP 31788 #HackAttack
+HackaTACK-31790 TCP 31790 #HackAttack
+HackaTACK-31792 TCP 31792 #HackAttack
+HotLine-Client TCP 5500-5503 #HotLine Client Connection
+HTTP TCP 80 #Hyper-Text Transfer Protocol
+HTTPS TCP 443 #TLS/SSL
+ICKiller TCP 1027 #ICKiller
+IDENT TCP 113 #Identify RCS Keyword String in Files
+IKE TCP 500 UDP 500 #IPSec Internet Key Exchange
+IMAP TCP 143 #Interactive Mail Protocol
+iMesh TCP 5000 #Also used by many Trojans and UPNP Service
+InCommand TCP 1029 #Also used by ICQ Nuke 98 Trojan
+IPSO-CMP TCP 1111 #IPSO Clustering Management Protocol
+IRC-1 TCP 6660-6670 #Internet Relay Chat
+IRC-2 TCP 7000 #Internet Relay Chat
+Jade TCP 1024 #Also used by Latinus, NetSPY, Rat Trojans
+Kaos TCP 1212 #Kaos Trojan
+KazzaA TCP 1214 #Fast Track P2P Protocol
+Kerberos-v5 TCP 88 UDP 88 #Kerberos Authentication Version 5
+Kerberos TCP 750 UDP 750 #Kerberos Authentication
+Kuang2 TCP 17300 #Kuang2 Trojan
+LDAP TCP 389 #Lightweight Directory Access Protocol
+LDAP-SSL TCP 636 #Lightweight Directory Access Protocol over TLS/SSL
+Rlogin TCP 513 #Rlogin
+iNotes TCP 1352 #Lotus iNotes Web Access Protocol
+lpdw0rm TCP 515 #Used by Ramen Trojans and Printer Service
+Madster TCP 5025 #Formally called Aimster
+####Microsoft-TS TCP 445 #Microsoft CIFS's over TCP
+Mneah TCP 4666 #The Mneah Trojan
+MSN-File Transfer TCP 6891-6900 #MSN File Tranfer
+MSN-Messenger TCP 1863 #MSN Instant Messenger
+MSSQL-Mon TCP 1434 #MSSQL Monitor
+MSSQL TCP 1433 #MSSQL Server
+mysql TCP 3306 #MySQL Server
+MultiDropper TCP 1035 #MultiDropper Trojan
+Napster-Client TCP 6600-6699 #Napster Client also used by WinMX
+Napster-Dir4 TCP 4444 #Napster Directory Connections
+Napster-Dir5 TCP 5555 #Napster Directory Connections
+Napster-Dir6 TCP 6666 #Napster Directory Connections
+Napster-Dir7 TCP 7777 #Napster Directory Connections
+Napster-Dir8 TCP 8888 #Napster Directory Connections
+Napster-Redirector TCP 8875 #Napster Redirector
+NBSession TCP 139 #NetBios Session Service
+NCP TCP 524 #Novell Netware Core Protocol
+NetShow TCP 1755 #Microsoft NetShow-Windows Media Player
+NetSTAT TCP 15 #UNIX NetSTAT Protocol
+NFSD TCP 2049 UDP 2049 #Network File System Deamon
+NNTP TCP 119 #Network News Tranfer Protocol
+NTP TCP 123 UDP 123 #Network Time Protocol
+OAS-NameServer TCP 2649 #Oracle Application Server
+OAS-ORB TCP 2651 #Oracle Application Server
+OpenWindows TCP 2000 #Open Windows
+####Orbix-1570 TCP 1570 #IONA Orbix Deamon
+####Orbix-1571 TCP 1571 #IONA Orbix Deamon
+PcAnywhere-Date TCP 5631 #pcAnywhere
+PcTele-FileSync TCP 2299 #Symantec PcTelecommute File Syncronization
+POP2 TCP 109 #Post Office Protocol Verion 2
+POP3 TCP 110 #Post Office Protocol Verion 3
+667-Trojans TCP 667 #Misc Trojans
+PPTP TCP 1723 #Point 2 Point Tunnelling Protocol
+Quake TCP 26000 UDP 26000 #Quake
+RainWall Command TCP 6374 #RainWall High Avaiablility Deamon
+RAT TCP 1097-1098 #Remote Administration Tool Trojan
+####Real-Audio TCP 7070 #Real Audio
+Remote-Strom TCP 1025 #Used by Fraggle Rock, NetSPY and MD5 BackDoor Trojans
+####RTSP TCP 554 #RealTime Streaming Protocol
+Secure-ID-Prop TCP 5510 #Token based Authentication Service
+ShadyShell TCP 1337 #ShadyShell Trojan
+####RSH TCP 514 #Remote Shell
+SMTP TCP 25 #Simple Mail Tranfer Protocol
+Sockets-DES TCP 1 #Also used by the TCP MUX Service
+SQLNET-1 TCP 1521 #Oracle SQL Net Verison 1 Service
+SQLNET-2-1521 TCP 1521 #Part of Oracle SQLNet Verison 2 Service
+SQLNET-2-1525 TCP 1525 #Part of Oracle SQLNet Verison 2 Service
+SQLNET-2-1526 TCP 1526 #Part of Oracle SQLNet Verison 2 Service
+SSH TCP 22 #Secure Shell
+####SSH2 TCP 22 #Secure Shell Version 2 also blocks version 1
+Safe-T-Net TCP 32557 #Safe-T-Net Configuration
+Squid TCP 3128 #Squid Proxy
+StoneBeat-Control TCP 3002 #StoneBeat Control
+StoneBeat-Deamon TCP 3001 #StoneBeat Deamon HeartBeat
+SubSeven TCP 27374 #Also used by BadBlood, EGO, Lion and WebHead Trojans
+T120 TCP 1503 #H323 Application Sharing Protocol
+TACACS+ TCP 49 #Terminal Access Control Access Control System
+Term-Serv TCP 3389 #Terminal Server
+High-Ports TCP 1024-65535 #TCP High Ports
+Telnet TCP 23 #Telnet Protocol
+TerrorTrojan TCP 3456 #Terror Trojan
+TheFLU TCP 5534 #The FLU Trojan
+Time TCP 37 #Time Server Protocol
+TransScout TCP 2004-2005 #TransScout Trojan
+Trinoo TCP 1524 #Trinoo Trojan
+UltorsTrojan TCP 1234 #Also used by SubSeven Java Client
+UUCP TCP 540 #Unix 2 Unix Copy Program
+WAIS TCP 210 #Wide Area Information Servers
+####Winframe TCP 1494 #Winframe
+X11 TCP 6000-6063 #XWindows System
+Yahoo-Messenger TCP 5050 #Yahoo Messenger
+Yahoo-Voice TCP 5000-5001 #Yahoo Voice
+Yahoo-WebCam TCP 5100 #Yahoo WebCam
+Webmin TCP 10000
+Usermin TCP 20000
+
+
+Archie UDP 1525 #Archie Internet Protocol
+Biff UDP 512 #Give notice of incoming mail messages
+Blubster UDP 41170 #Uses Manolito Protocol P2P
+Bootp UDP 67 #Bootstrap Protocol Server
+Citrix-ICABrowse UDP 1640 #Citrix ICA Browsing
+CU-SeeMe UDP 7648-7652 #Video Conferencing
+DHCP-Reply UDP 68 #DHCP Reply
+DHCP-Request UDP 67 #DHCP Request
+DirectConnect UDP 411-412 #DirectConnect P2p Application
+Discard UDP 9 #Discard Server Protocol
+Echo UDP 7 #Echo
+eDonkey-4665 UDP 4665 #eDonkey
+FreeTel-out UDP 21300 #RealTime Full Duplex Voice Communication
+H323-RAS UDP 1719 #RAS and Associated connection H323
+H323-RASOnly UDP 1719 #Endpoint to Gatekeeper communications
+HackaTack-31789 UDP 31789 #HackaTack Trojan
+HackaTack-31791 UDP 31791 #HackaTack Trojan
+HotLine-Tracker UDP 5499 #HotLine Tracker Connections
+ICQ-Locator UDP 4000 #Mirabilis ICQ Version
+Interphone UDP 22555 #VocalTec Internet Phone
+L2TP UDP 1701 #Layer 2 Tunnelling Protocol
+Microsoft-DS UDP 445 #CIFS over UDP
+MSN-1863 UDP 1863 #MSN
+MSN-1590 UDP 5190 #MSN
+MSN-Voice UDP 6901 #MSN Voice
+MSSQL-MON UDP 1434 #MSSQL Monitor
+MSSQL-Server UDP 1433 #MSSQL Server
+Name UDP 42 #HostName Server
+NBDatagram UDP 138 #NetBIOS Datagram Service
+NBName UDP 137 #NetBIOS Name Service
+RADIUS-2 UDP 1812 #Remote Authentication Dial-In User Service V2
+NoBackO UDP 1201 #NoBackO Trojan
+OnTime UDP 1622 #OnTime
+PcAnywhere UDP 5632 #PcAnywhere
+RADIUS UDP 1645 #Remote Authentication Dial-In User Service
+RainWall-Deamon UDP 6372 #RainWall Deamon
+RailWall-Status UDP 6374 #RainWall Remote Management Status
+RainWall-Stop UDP 6373 #RainWall Monitoring
+RexxRave UDP 1104 #RexxRave Trojan
+RIP UDP 520 #Routing Information Protocol
+SecureID UDP 5500 #Token Based Authentication
+SIP UDP 5060 #Shared Whiteboard and Instant Messenger Apps
+SNMP UDP 161 #Simple Network Management Protocol
+SNMP-Trap UDP 162 #SNMP Trap
+SteamWorks UDP 1558 #Steamworks
+SWTP-SMS UDP 9282 #Software Management Server
+Syslog UDP 514 #UNIX Syslog Protocol
+TACACS UDP 49 #Terminal Access Control Access Control System
+TFTP UDP 69 #Trivial File Transfer Protocol
+TIME UDP 37 #Time Server Protocol
+High-Ports UDP 1024-65535 #High Ports
+Vosaic-Data UDP 20000-20030 #Vosaic Data
+Who UDP 513 #UNIX Who Protocol
+WinMX UDP 6257 #Also uses Napster Ports
+Yahoo V-Chat UDP 5000-5010 #Yahoo Voice Chat
+
+Dest-Unreach ICMP 3 #ICMP Destination Unreachable
+Echo-Reply ICMP 0 #ICMP Echo-Reply
+Echo-Request ICMP 8 #ICMP Echo-Request
+Info-Reply ICMP 16 #ICMP Info Reply
+Info-Request ICMP 15 #ICMP Info Request
+Mask-Reply ICMP 18 #ICMP Mask Reply
+Mask-Request ICMP 17 #ICMP Mask Request
+Param-Prblm ICMP 12 #ICMP Parameter Problem
+Redirect ICMP 5 #ICMP Route Redirect
+Source-Quench ICMP 4 #ICMP Source Quench
+Time-exceeded ICMP 11 #ICMP Time to Live Exceeded
+TimeStamp ICMP 13 #ICMP Time Stamp
+TimeStamp-Reply ICMP 14 #ICMP TimeStamp Reply
+
+AH IP 51 #IPSec Authentication Header Protocol
+BackWeb IP 17 #Push Web Application Directly to Desktops
+EGP IP 8 #Exterior Gateway Protocol
+ESP IP 50 #IPsec Encapsulation Security Paylod Protocol
+WEB_Mapped IP 6 #HTTP and FTP Port Mapping Service
+IGMP IP 2 #Internet Group Management Protocol
+IGRP IP 9 #Cisco Interior Gateway Routing Protocol
+MSSQL_Resolver IP 17 #Block MSSQL Sapphire/Slammer Worms
+OSPF IP 89 #Open Shortest Path First
+RIP-Response IP 17 #RIP Routing Response
+SMTP_Mapped IP 6 #SMTP Port Mapping Service
+SSH_V2 IP 6 #SSH Version 2
+TraceRoute IP 17 #Unix TraceRoute
+VRRP IP 112 #Virtual Router Redundancy Protocol
+GRE IP 47
--- /dev/null
+
+do 'itsecur-lib.pl';
+
+# status_monitor_list()
+# Just one type is supported
+sub status_monitor_list
+{
+return ( [ "rule", $text{'monitor_type'} ] );
+}
+
+# status_monitor_status(type, &monitor, from-ui)
+# Check the logs to see if the rule has been hit recently
+sub status_monitor_status
+{
+local $rv;
+if ($_[2]) {
+ # If this call is from the UI, then just return the current status
+ local %oldstatus;
+ &read_file("$config_directory/status/oldstatus", \%oldstatus);
+ $rv = { 'up' => defined($oldstatus{$_[1]->{'id'}}) ?
+ $oldstatus{$_[1]->{'id'}} : -1 };
+ }
+else {
+ # Actually check the logs
+ local %lasttime;
+ &read_file("$module_config_directory/lasttime", \%lasttime);
+ local $l;
+ local $stime;
+ $rv = { 'up' => 1 };
+ foreach $l (reverse(&parse_all_logs(1))) {
+ if ($l->{'time'} > $lasttime{$_[1]->{'id'}}) {
+ # Consider this line
+ if ($l->{'rule'} == $_[1]->{'rule'}) {
+ # Got a hit!
+ $rv = { 'up' => 0 };
+ }
+ }
+ $stime = $l->{'time'};
+ }
+ $lasttime{$_[1]->{'id'}} = $stime || time();
+ &write_file("$module_config_directory/lasttime", \%lasttime);
+ }
+return $rv;
+}
+
+# status_monitor_dialog(type, &monitor)
+# Return form for selecting a rule
+sub status_monitor_dialog
+{
+local $rv;
+$rv = "<tr> <td><b>$text{'monitor_rule'}</b></td>\n";
+$rv .= "<td colspan=3><select name=rule>\n";
+local $r;
+foreach $r (&list_rules()) {
+ if ($r->{'log'}) {
+ $rv .= sprintf "<option value=%s %s>%s\n",
+ $r->{'num'},
+ $_[1]->{'rule'} == $r->{'num'} ? "selected" : "",
+ &text('monitor_num', $r->{'num'},
+ &group_name($r->{'source'}),
+ &group_name($r->{'dest'}));
+ }
+ }
+$rv .= "</select></td> </tr>\n";
+return $rv;
+}
+
+# status_monitor_parse(type, &monitor, &in)
+# Parse form for selecting a rule
+sub status_monitor_parse
+{
+$_[1]->{'rule'} = $_[2]->{'rule'};
+}
+
+1;
+
--- /dev/null
+#!/usr/bin/perl
+# stop.pl
+# Stop the firewall
+
+$ENV{'WEBMIN_CONFIG'} ||= "/etc/webmin";
+$ENV{'WEBMIN_VAR'} ||= "/var/webmin";
+$no_acl_check++;
+if ($0 =~ /^(.*\/)[^\/]+$/) {
+ chdir($1);
+ }
+require './itsecur-lib.pl';
+$module_name eq 'itsecur-firewall' || die "Command must be run with full path";
+
+print "$text{'stop_doing'}\n";
+$err = &stop_rules();
+if ($err) {
+ print &text('stop_failed', $err),"\n";
+ exit(1);
+ }
+else {
+ print "$text{'stop_done'}\n";
+ &disable_routing();
+ exit(0);
+ }
+
--- /dev/null
+#!/usr/bin/perl
+
+$trust_unknown_referers = 1;
+require './itsecur-lib.pl';
+&can_use_error("logs");
+&ReadParse();
+$| = 1;
+$SIG{'HUP'} = sub { print "got HUP!\n"; };
+$log = $config{'log'} || &get_log_file();
+print "Content-type: text/plain\n\n";
+
+# Get all the firewall log lines
+open(LOG, $log);
+while(<LOG>) {
+ push(@log, $_) if (&is_log_line($_));
+ shift(@log) if (@log > 20);
+ }
+
+# Show the last 20, and keep tailing
+print @log;
+while(1) {
+ sleep(1);
+ $line = <LOG>;
+ print $line if ($line && &is_log_line($line));
+ }
+
--- /dev/null
+#!/usr/bin/perl
+# up.cgi
+# Move a rule up
+
+require './itsecur-lib.pl';
+&can_edit_error("rules");
+&ReadParse();
+&lock_itsecur_files();
+@rules = &list_rules();
+($rules[$in{'idx'}], $rules[$in{'idx'}-1]) =
+ ($rules[$in{'idx'}-1], $rules[$in{'idx'}]);
+&save_rules(@rules);
+&unlock_itsecur_files();
+&remote_webmin_log("move", "rule", $in{'idx'}+1, $rules[$in{'idx'}]);
+&redirect("list_rules.cgi");
+
--- /dev/null
+#!/usr/bin/perl
+# Export all matching logs in WELF format
+
+require './itsecur-lib.pl';
+&can_edit_error("report");
+use POSIX;
+&ReadParse();
+
+@logs = &parse_all_logs();
+@logs = &filter_logs(\@logs, \%in, \@searchvars);
+if ($in{'save_name'}) {
+ push(@searchvars, "save_name=".&urlize($in{'save_name'}));
+ }
+
+# Build map of protos and ports to services
+@servs = &list_services();
+foreach $s (@servs) {
+ for($i=0; $i<@{$s->{'protos'}}; $i++) {
+ $proto = lc($s->{'protos'}->[$i]);
+ $port = $s->{'ports'}->[$i];
+ if ($port =~ /^(\d+)\-(\d+)$/) {
+ foreach $p ($1 .. $2) {
+ $multi_map{$proto,$p} = $s;
+ }
+ }
+ else {
+ $serv_map{$proto,$port} = $s;
+ }
+ }
+ }
+
+# Validate inputs
+&error_setup($text{'welf_err'});
+if ($in{'dest_mode'} == 1) {
+ $orig_dest = $in{'dest'};
+ if (-d $in{'dest'}) {
+ $in{'dest'} .= "/logs.welf";
+ }
+ $in{'dest'} =~ /^(.*)\// || &error($text{'backup_edest'});
+ -d $1 || &error($text{'backup_edestdir'});
+ $file = $in{'dest'};
+ $done = &text('welf_done1', $file);
+ }
+elsif ($in{'dest_mode'} == 2) {
+ gethostbyname($in{'ftphost'}) || &error($text{'backup_eftphost'});
+ $in{'ftpfile'} =~ /^\/\S+/ || &error($text{'backup_eftpfile'});
+ $in{'ftpuser'} =~ /\S/ || &error($text{'backup_eftpuser'});
+ $file = "ftp://$in{'ftpuser'}:$in{'ftppass'}\@$in{'ftphost'}$in{'ftpfile'}";
+ $done = &text('welf_done2', $in{'ftphost'}, $in{'ftpfile'});
+ }
+elsif ($in{'dest_mode'} == 3) {
+ $in{'email'} =~ /^\S+\@\S+$/ || &error($text{'backup_eemail'});
+ $file = "mailto:$in{'email'}";
+ $done = &text('welf_done3', $in{'email'});
+ }
+
+$temp = &tempname();
+open(OUT, ">$temp") || &error($!);
+$host = &get_system_hostname();
+foreach $l (reverse(@logs)) {
+ print OUT "id=firewall ";
+ @tm = localtime($l->{'time'});
+ print OUT "time=\"",strftime("%Y-%m-%d %H:%M:%S", @tm),"\" ";
+ print OUT "fw=$host ";
+ if (&deny_action($l)) {
+ print OUT "pri=4 ";
+ }
+ else {
+ print OUT "pri=5 ";
+ }
+ print OUT "rule=$l->{'rule'} ";
+ if ($l->{'proto'} && $l->{'dst_port'}) {
+ # Find the service name
+ local $serv = $serv_map{lc($l->{'proto'}),$l->{'dst_port'}} ||
+ $multi_map{lc($l->{'proto'}),$l->{'dst_port'}};
+ if ($serv) {
+ print OUT "proto=$serv->{'name'} ";
+ }
+ }
+ print OUT "src=$l->{'src'} ";
+ print OUT "dst=$l->{'dst'}\n";
+ }
+close(OUT);
+
+# Send to destination
+($mode, @dest) = &parse_backup_dest($file);
+if ($mode == 1) {
+ # Move to destination
+ $out = `mv '$temp' '$file' 2>&1`;
+ &error($out) if ($?);
+ }
+elsif ($mode == 2) {
+ # FTP somewhere
+ local $err;
+ &ftp_upload($dest[2], $dest[3], $temp, \$err, undef, $dest[0], $dest[1]);
+ unlink($temp);
+ &error($err) if ($err);
+ }
+elsif ($mode == 3) {
+ # Email somewhere
+ $data = `cat $temp`;
+ unlink($temp);
+ $host = &get_system_hostname();
+ $body = "Firewall logs in WELF format from $host are attached to this email.\n";
+ local $mail = { 'headers' =>
+ [ [ 'From', $config{'from'} || "webmin\@$host" ],
+ [ 'To', $dest[0] ],
+ [ 'Subject', "Firewall logs" ] ],
+ 'attach' =>
+ [ { 'headers' => [ [ 'Content-type', 'text/plain' ] ],
+ 'data' => $body },
+ { 'headers' => [ [ 'Content-type', 'text/plain' ] ],
+ 'data' => $data } ] };
+ $main::errors_must_die = 1;
+ if (&foreign_check("mailboxes")) {
+ &foreign_require("mailboxes", "mailboxes-lib.pl");
+ eval { &mailboxes::send_mail($mail); };
+ }
+ else {
+ &foreign_require("sendmail", "sendmail-lib.pl");
+ &foreign_require("sendmail", "boxes-lib.pl");
+ eval { &sendmail::send_mail($mail); };
+ }
+ return $@ if ($@);
+ }
+
+# Save settings
+$config{'welf_dest'} = $in{'dest_mode'} == 0 ? undef : $file;
+&write_file($module_config_file, \%config);
+
+if ($in{'dest_mode'} == 0) {
+ # Send to browser
+ print "Content-type: text/plain\n\n";
+ open(FILE, $temp);
+ while(<FILE>) {
+ print;
+ }
+ close(FILE);
+ unlink($temp);
+ &remote_webmin_log("backup");
+ }
+else {
+ # Tell the user
+ &header($text{'welf_title'}, "",
+ undef, undef, undef, undef, &apply_button());
+ print "<hr>\n";
+
+ print "<p>$done<p>\n";
+
+ print "<hr>\n";
+ &footer("/$module_name/list_report.cgi?".join("&", @searchvars),
+ $text{'report_return'});
+ }
+