new_api implementations of core PlanetLabConf files; some are deprecated but we need...
Mark Huang [Mon, 6 Nov 2006 22:02:17 +0000 (22:02 +0000)]
29 files changed:
RPM-GPG-KEY-fedora [new file with mode: 0755]
RootResources/pl_conf.py [new file with mode: 0755]
RootResources/pl_netflow.py [new file with mode: 0755]
RootResources/plc_slice_pool.php [new file with mode: 0755]
blacklist.php [new file with mode: 0755]
bwlimit.php [new file with mode: 0755]
get_gpg_key.php [new file with mode: 0755]
get_plc_config.php [new file with mode: 0755]
getupdatesxml.php [new file with mode: 0755]
ipod.conf.php [new file with mode: 0755]
iptables [new file with mode: 0755]
issue.php [new file with mode: 0755]
keys.php [new file with mode: 0755]
logrotate.conf [new file with mode: 0755]
ntp.conf.php [new file with mode: 0755]
ntp/ntp.conf.default [new file with mode: 0755]
ntp/ntp.conf.prob.default [new file with mode: 0755]
ntp/step-tickers.php [new file with mode: 0755]
ntptickers.php [new file with mode: 0755]
pl_nm.conf [new file with mode: 0755]
propd.conf [new file with mode: 0755]
proxies.php [new file with mode: 0755]
sendmail.cf [new file with mode: 0755]
sendmail.mc [new file with mode: 0755]
slocate.cron [new file with mode: 0755]
sshd_config [new file with mode: 0755]
sudoers [new file with mode: 0755]
sysctl.php [new file with mode: 0755]
yum.conf.php [new file with mode: 0755]

diff --git a/RPM-GPG-KEY-fedora b/RPM-GPG-KEY-fedora
new file mode 100755 (executable)
index 0000000..17d4ec7
--- /dev/null
@@ -0,0 +1,27 @@
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: GnuPG v1.0.7 (GNU/Linux)
+
+mQGiBD+dnTsRBACwnlz4AhctOLlVBAsq+RaU82nb5P3bD1YJJpsAce1Ckd2sBUOJ
+D11NUCqH8c7EctOquOZ5zTcWxHiWWbLyKQwUw2SUvnWa5SSbi8kI8q9MTPsPvhwt
+gMrQMLenMO+nsrxrSaG6XcD+ssfJNxC7NQVCQAj3pvvg9rKi3ygsM7CXHwCghgsq
+X6TOr55HE90DbEsoq3b/jjsD/i8aIZ6urUgrpAkQslcakXdJLKgSdwjRUgVZgvYZ
+b7kAx1iPq0t/AhB3NJw3zW4AAKJohGg3xj5K4V8PJEZrSIpoRYlF43Kqlfu2p5gh
+WT89SP4YAlWPeTqf0+dTYUYz3b144k2ZFOdRuXIRxunoYNAUr9oMrxBXbJ/eY+0U
+QX3pBACYzKizyY4JJgd0zFJmNkcdK9nzcm+btYFnYQo33w5GSE686UNr+9yiXt9t
+mPRvNEbj3u+xoAX8B/5k3aZ5NbUhV64/VcKlUdRIxNlFCG7I9KgxeHWAYwi7yqOG
+XM3T/v6o7GLdQEB0ChFqS7kUlqmwLV+C3QhlrFe/Cuk26i+Q6rQiRmVkb3JhIFBy
+b2plY3QgPGZlZG9yYUByZWRoYXQuY29tPohbBBMRAgAbBQI/nZ07BgsJCAcDAgMV
+AgMDFgIBAh4BAheAAAoJELRCadBPKm/S2PAAnRTlhorITphab+oxAHtbxZF9BVyD
+AJ9WOVaZUG53IWWIAXOGv3j/cmr3lohGBBMRAgAGBQI/nZ22AAoJECGRgM3bQqYO
+R5QAoIp1G+omVktq/snxpmz5UeHjlSYjAKCRr/ea/L7S7ZTxB18cf1TYfad1x4hG
+BBARAgAGBQI/ntjgAAoJECnVuiSN9W0FUSUAoJnrone4J0o1HMkRz+6g9KVuO2Fy
+AJ0XyebOzVmI9U5OyOfnNmYV0wnQcrkBDQQ/nZ08EAQAugOfLWJbKwMA9vg2mJU5
+94TZU0HRJkx/fqYhx0YxWWRpzplrEyvcDXuYcWi1Hwh0tD86T4fR5GV6joWiWClz
+D+Hwhhb6gcSdeSGlGLlZAvWYtFSHWiv+3LaI9w8Vtczl99Bh2WiMDNDDGw0RQg6Z
+aftldLSe4j1pffpFGQ8SuisAAwUEAKVxqLT7fC5xQ6oclcZ+PhoDlePQ1BiTS7tu
+GM07bFF4nNvY91LL7S31pooz3XbGSWP8jxzSv1Fw35YhSmWGOBOEXluqMbVQGJJ5
+m8fqJOjC0imbfeWgr/T7zLrJeiljDxvX+6TyawyWQngF6v1Hq6FRV0O0bOp9Npt5
+zqCbDGs/iEYEGBECAAYFAj+dnTwACgkQtEJp0E8qb9L//gCcDVYnDegNCOxDn1se
+dDwxw+0h8OcAn1CZHof15QqxnTwEnvwF2QeOI5dn
+=mJAx
+-----END PGP PUBLIC KEY BLOCK-----
diff --git a/RootResources/pl_conf.py b/RootResources/pl_conf.py
new file mode 100755 (executable)
index 0000000..0a156df
--- /dev/null
@@ -0,0 +1,29 @@
+# RootResources/pl_conf
+
+PL_CONF_VINIT = """#!/bin/sh
+
+# crond needs syslogd running
+/sbin/chkconfig syslog on
+
+# use crond to check for updates
+/sbin/chkconfig crond on
+
+cat <<EOF >/etc/cron.daily/yum-upgrade
+#!/bin/sh
+
+rm -f /var/lib/rpm/__db*
+yum -y upgrade
+EOF
+chmod a+x /etc/cron.daily/yum-upgrade
+
+PACKAGE=sidewinder-PlanetLab-SCS
+rm -f /var/lib/rpm/__db*
+yum -y install $PACKAGE
+"""
+
+try:
+    pl_conf = RootSlice(nm_vserver_flags = "static",
+                        nm_cpu_share = 32,
+                        nm_initscript = PL_CONF_VINIT)
+except:
+    pass
diff --git a/RootResources/pl_netflow.py b/RootResources/pl_netflow.py
new file mode 100755 (executable)
index 0000000..5d5a4dd
--- /dev/null
@@ -0,0 +1,7 @@
+# RootResources/pl_netflow
+
+try:
+    pl_netflow = RootSlice(nm_vserver_flags = "syncstart",
+                           nm_cpu_share = 32)
+except:
+    pass
diff --git a/RootResources/plc_slice_pool.php b/RootResources/plc_slice_pool.php
new file mode 100755 (executable)
index 0000000..a61a656
--- /dev/null
@@ -0,0 +1,22 @@
+<?php
+include('plc_config.php');
+?>
+# RootResources/plc_slice_pool
+
+SA_HOST = "<?php print(PLC_BOOT_HOST); ?>"
+SA_URL = SA_HOST + "/xml/"
+CACERT_PATH = "/mnt/cdrom/bootme/cacert/%s/cacert.pem" % SA_HOST
+
+plc_slice_pool = RootPool(slice = "pl_conf",
+                         plc_sa_prefix = "pl",
+                         plc_sa_server = SA_URL,
+                         plc_sa_cacert = CACERT_PATH,
+                         nm_pool_child_type = "VServerSlice",
+                         nm_cpu_share = RES_INF,
+                         nm_net_avg_rate = RES_INF,
+                         nm_net_min_rate = RES_INF,
+                         nm_net_max_rate = RES_INF,
+                         nm_net_exempt_avg_rate = RES_INF,
+                         nm_net_exempt_min_rate = RES_INF,
+                         nm_net_exempt_max_rate = RES_INF,
+                         nm_disk_quota = RES_INF)
diff --git a/blacklist.php b/blacklist.php
new file mode 100755 (executable)
index 0000000..d04e4c6
--- /dev/null
@@ -0,0 +1,52 @@
+#
+# /etc/planetlab/blacklist
+#
+# post: iptables-restore --noflush < /etc/planetlab/blacklist
+#
+# PlanetLab per-node outbound blacklist
+# 
+# Aaron Klingaman <alk@cs.princeton.edu>
+# Mark Huang <mlhuang@cs.princeton.edu>
+# Copyright (C) 2004 The Trustees of Princeton University
+#
+# $Id: blacklist.php,v 1.5 2005/10/04 18:04:59 alk Exp $
+#
+
+*filter
+-F BLACKLIST
+
+<?php
+
+// Get admin API handle
+require_once 'plc_api.php';
+global $adm;
+
+// Look up the node
+$nodenetworks = $adm->GetNodeNetworks(array($_SERVER['REMOTE_ADDR']));
+if (!empty($nodenetworks)) {
+  $nodes = $adm->GetNodes(array($nodenetworks[0]['node_id']));
+  if (!empty($nodes)) {
+    $node = $nodes[0];
+  }
+}
+
+if (isset($node)) {
+  // XXX Implement generic "networks" table
+  // $networks = $adm->GetNetworks();
+  $networks = array();
+  foreach ($networks as $network) {
+    if ($network['blacklisted']) {
+      $dest = $network['ip'];
+      if ($network['netmask']) {
+       $dest .= "/" . $network['netmask'];
+      }
+      print "-A BLACKLIST -d $dest -j LOGDROP\n";
+    }
+  }
+}
+
+print "\n";
+
+?>
+
+COMMIT
diff --git a/bwlimit.php b/bwlimit.php
new file mode 100755 (executable)
index 0000000..4c6e07b
--- /dev/null
@@ -0,0 +1,34 @@
+<?php
+//
+// Deprecated. Node Manager manages the node bandwidth limit.
+//
+// Mark Huang <mlhuang@cs.princeton.edu>
+// Copyright (C) 2006 The Trustees of Princeton University
+//
+// $Id$
+//
+
+// Get admin API handle
+require_once 'plc_api.php';
+global $adm;
+
+// Look up the node
+$nodenetworks = $adm->GetNodeNetworks(array($_SERVER['REMOTE_ADDR']));
+if (!empty($nodenetworks)) {
+  if ($nodenetworks[0]['bwlimit'] !== NULL) {
+    $rate = $nodenetworks[0]['bwlimit'];
+    if ($rate >= 1000000000 && ($rate % 1000000000) == 0) {
+      printf("%.0fgbit", ($rate / 1000000000.));
+    } elseif ($rate >= 1000000 && ($rate % 1000000) == 0) {
+      printf("%.0fmbit", ($rate / 1000000.));
+    } elseif ($rate >= 1000) {
+      printf("%.0fkbit", ($rate / 1000.));
+    } else {
+      printf("%.0fbit", $rate);
+    }
+  } else {
+    print "-1";
+  }
+}
+
+?>
\ No newline at end of file
diff --git a/get_gpg_key.php b/get_gpg_key.php
new file mode 100755 (executable)
index 0000000..7763e38
--- /dev/null
@@ -0,0 +1,17 @@
+<?php
+//
+// Exports the GPG public key for this PLC
+//
+// Mark Huang <mlhuang@cs.princeton.edu>
+// Copyright (C) 2006 The Trustees of Princeton University
+//
+// $Id: get_gpg_key.php,v 1.1 2006/05/08 18:53:30 mlhuang Exp $
+//
+
+include 'plc_config.php';
+
+echo shell_exec("gpg --homedir=/tmp --export --armor" .
+               " --no-default-keyring" .
+               " --keyring " . PLC_ROOT_GPG_KEY_PUB);
+
+?>
diff --git a/get_plc_config.php b/get_plc_config.php
new file mode 100755 (executable)
index 0000000..b50d91a
--- /dev/null
@@ -0,0 +1,50 @@
+<?php
+//
+// Print a subset of the variables from the PLC configuration store in
+// various formats (Perl, Python, PHP, sh)
+//
+// Mark Huang <mlhuang@cs.princeton.edu>
+// Copyright (C) 2006 The Trustees of Princeton University
+//
+// $Id: get_plc_config.php,v 1.7 2006/05/08 21:45:29 mlhuang Exp $
+//
+
+// Try the new plc_config.php file first
+include 'plc_config.php';
+
+if (isset($_REQUEST['perl'])) {
+  $shebang = '#!/usr/bin/perl';
+  $format = "our $%s=%s;\n";
+  $end = '';
+} elseif (isset($_REQUEST['python'])) {
+  $shebang = '#!/usr/bin/python';
+  $format = "%s=%s\n";
+  $end = '';
+} elseif (isset($_REQUEST['php'])) {
+  $shebang = '<?php';
+  $format = "define('%s', %s);\n";
+  $end = '?>';
+} else {
+  $shebang = '#!/bin/sh';
+  $format = "%s=%s\n";
+  $end = '';
+}
+
+echo $shebang . "\n";
+
+foreach (array('PLC_API_HOST', 'PLC_API_PATH', 'PLC_API_PORT',
+              'PLC_WWW_HOST', 'PLC_BOOT_HOST',
+              'PLC_NAME', 'PLC_SLICE_PREFIX',
+              'PLC_MAIL_SUPPORT_ADDRESS',
+              'PLC_MAIL_SLICE_ADDRESS')
+        as $name) {
+  if (defined($name)) {
+    // Perl, PHP, Python, and sh all support strong single quoting
+    $value = "'" . str_replace("'", "\\'", constant($name)) . "'";
+    printf($format, $name, $value);
+  }
+}
+
+echo $end . "\n";
+
+?>
diff --git a/getupdatesxml.php b/getupdatesxml.php
new file mode 100755 (executable)
index 0000000..9acc834
--- /dev/null
@@ -0,0 +1,138 @@
+<?php
+//
+// Deprecated. Generates an XML file that the old PlanetLabConf script understands.
+//
+// Aaron Klingaman <alk@absarokasoft.com>
+// Mark Huang <mlhuang@cs.princeton.edu>
+//
+// Copyright (C) 2006 The Trustees of Princeton University
+//
+// $Id$
+//
+
+// Get admin API handle
+require_once 'plc_api.php';
+global $adm;
+
+function writeXMLHeader()
+{
+  print( "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n\n" );
+}
+
+define("ENT_UNPARSED", 0); // i.e., CDATA
+define("ENT_PARSED", 1); // i.e., PCDATA (attributes)
+
+function xmlspecialchars_decode($string, $parsed = ENT_UNPARSED)
+{
+  if ($parsed == ENT_PARSED) {
+    // &amp; to &
+    // &apos; to '
+    // &lt; to <
+    // &gt; to >
+    // &quot; to "
+    return str_replace('&amp;', '&',
+                      str_replace(array('&apos;', '&lt;', '&gt;', '&quot;'),
+                                  array("'", '<', '>', '"'),
+                                  $string));
+  } else {
+    // &amp; to &
+    // &apos; to '
+    // &lt; to <
+    // &gt; to >
+    // \" to "
+    // \\ to \
+    return str_replace('&amp;', '&',
+                      str_replace(array('&apos;', '&lt;', '&gt;', '\"', '\\'),
+                                  array("'", '<', '>', '"', "\\"),
+                                  $string));
+  }
+}
+  
+function xmlspecialchars($string, $parsed = ENT_UNPARSED)
+{
+  if ($parsed == ENT_PARSED) {
+    // & to &amp;
+    // ' to &apos;
+    // < to &lt;
+    // > to &gt;
+    // " to &quot;
+    $string = str_replace(array("'", '<', '>', '"'),
+                         array('&apos;', '&lt;', '&gt;', '&quot;'),
+                         str_replace('&', '&amp;', $string));
+  } else {
+    // & to &amp;
+    // ' to &apos;
+    // < to &lt;
+    // > to &gt;
+    // " to \"
+    // \ to \\
+    $string = str_replace(array("'", '<', '>', '"'),
+                         array('&apos;', '&lt;', '&gt;', '\"'),
+                         str_replace(array('&', "\\"),
+                                     array('&amp;', '\\'),
+                                     $string));
+  }
+
+  return utf8_encode($string);
+}
+    
+// Look up the node
+if (!empty($_REQUEST['node_id'])) {
+  $nodes = $adm->GetSlivers(array(intval($_REQUEST['node_id'])));
+} else {
+  $nodenetworks = $adm->GetNodeNetworks(array($_SERVER['REMOTE_ADDR']));
+  if (!empty($nodenetworks)) {
+    $nodes = $adm->GetSlivers(array($nodenetworks[0]['node_id']));
+  }
+}
+
+if (empty($nodes)) {
+  exit();
+}
+$node = $nodes[0];
+$node_id = $node['node_id'];
+
+writeXMLHeader();
+$curtime= time();
+print( "<planetlab_conf version=\"0.1\" time=\"$curtime\">\n" );
+print( "<node id=\"$node_id\">\n" );
+
+foreach( $node['conf_files'] as $conf_file )
+{
+  $source            = xmlspecialchars($conf_file["source"]);
+  $dest              = xmlspecialchars($conf_file["dest"]);
+  $file_permissions  = xmlspecialchars($conf_file["file_permissions"]);
+  $file_owner        = xmlspecialchars($conf_file["file_owner"]);
+  $file_group        = xmlspecialchars($conf_file["file_group"]);
+  $preinstall_cmd    = xmlspecialchars($conf_file["preinstall_cmd"]);
+  $postinstall_cmd   = xmlspecialchars($conf_file["postinstall_cmd"]);
+  $error_cmd         = xmlspecialchars($conf_file["error_cmd"]);
+  $ignore_cmd_errors = $conf_file["ignore_cmd_errors"];
+  $always_update     = $conf_file["always_update"];
+
+  if( $ignore_cmd_errors == 1 )
+    $ignore_cmd_errors= "y";
+  else
+    $ignore_cmd_errors= "n";
+
+  if( $always_update == 1 )
+    $always_update= "y";
+  else
+    $always_update= "n";
+
+  print( "<file always_update=\"$always_update\" ignore_cmd_errors=\"$ignore_cmd_errors\">\n" );
+  print( "<source>$source</source>\n" );
+  print( "<destination>$dest</destination>\n" );
+  print( "<permissions>$file_permissions</permissions>\n" );
+  print( "<owner>$file_owner</owner>\n" );
+  print( "<group>$file_group</group>\n" );
+  print( "<preinstall_cmd>$preinstall_cmd</preinstall_cmd>\n" );
+  print( "<postinstall_cmd>$postinstall_cmd</postinstall_cmd>\n" );
+  print( "<error_cmd>$error_cmd</error_cmd>\n" );
+  print( "</file>\n" );
+}
+
+print( "</node>\n" );
+print( "</planetlab_conf>\n" );
+
+?>
diff --git a/ipod.conf.php b/ipod.conf.php
new file mode 100755 (executable)
index 0000000..695e001
--- /dev/null
@@ -0,0 +1,23 @@
+<?php
+//
+// /etc/ipod.conf for production nodes
+//
+// Mark Huang <mlhuang@cs.princeton.edu>
+// Copyright (C) 2004-2006 The Trustees of Princeton University
+//
+// $Id: ipod.conf.php,v 1.1 2006/04/07 19:29:04 mlhuang Exp $
+//
+
+include('plc_config.php');
+
+// Allow only the API server to send a reboot packet
+$IP_SUBNET = gethostbyname(PLC_API_HOST);
+
+echo <<<EOF
+# IP range that we respond to reboot requests from
+IP_SUBNET=$IP_SUBNET
+IP_MASK=255.255.255.255
+
+EOF;
+
+?>
\ No newline at end of file
diff --git a/iptables b/iptables
new file mode 100755 (executable)
index 0000000..a3ea6b3
--- /dev/null
+++ b/iptables
@@ -0,0 +1,22 @@
+#
+# /etc/sysconfig/iptables
+#
+# post: service iptables restart
+#
+# PlanetLab standard filter chains
+#
+# $Id: iptables,v 1.2 2005/06/03 13:36:09 alk Exp $
+#
+
+*filter
+:INPUT ACCEPT [0:0]
+:FORWARD ACCEPT [0:0]
+:OUTPUT ACCEPT [0:0]
+:BLACKLIST - [0:0]
+:LOGDROP - [0:0]
+
+-A OUTPUT -j BLACKLIST
+-A LOGDROP -j LOG
+-A LOGDROP -j DROP
+
+COMMIT
diff --git a/issue.php b/issue.php
new file mode 100755 (executable)
index 0000000..ed1fc86
--- /dev/null
+++ b/issue.php
@@ -0,0 +1,41 @@
+<?php
+//
+// /etc/issue
+//
+// Mark Huang <mlhuang@cs.princeton.edu>
+// Copyright (C) 2004-2006 The Trustees of Princeton University
+//
+// $Id: issue.php,v 1.1 2006/04/07 18:44:04 mlhuang Exp $
+//
+
+// For PLC_NAME, etc.
+include('plc_config.php');
+
+$PLC_NAME = PLC_NAME;
+$PLC_WWW_HOST = PLC_WWW_HOST;
+$PLC_WWW_PORT = PLC_WWW_PORT;
+$PLC_MAIL_SUPPORT_ADDRESS = PLC_MAIL_SUPPORT_ADDRESS;
+
+if ($PLC_WWW_PORT == 443) {
+  $PLC_WWW_URL = "https://$PLC_WWW_HOST/";
+} elseif ($PLC_WWW_PORT != 80) {
+  $PLC_WWW_URL = "http://$PLC_WWW_HOST:$PLC_WWW_PORT/";
+} else {
+  $PLC_WWW_URL="http://$PLC_WWW_HOST/";
+}
+
+echo <<<EOF
+$PLC_NAME Node: \\n
+Kernel \\r on an \\m
+$PLC_WWW_URL
+
+This machine is a node in the $PLC_NAME distributed network. If you
+require assistance in administering this node, please contact
+${PLC_MAIL_SUPPORT_ADDRESS}.
+
+Console login to this node is restricted to site_admin.
+
+
+EOF;
+
+?>
\ No newline at end of file
diff --git a/keys.php b/keys.php
new file mode 100755 (executable)
index 0000000..38b04e9
--- /dev/null
+++ b/keys.php
@@ -0,0 +1,86 @@
+<?php
+//
+// Deprecated. Node Manager should manage keys.
+//
+// .ssh/authorized_keys generator
+//
+// Basic usage:
+// keys.php?role=admin (all PlanetLab administrators)
+// keys.php?root (PlanetLab root and users allowed root on the querying node)
+// keys.php?site_admin (PIs and tech contacts at the querying node's site)
+//
+// Mark Huang <mlhuang@cs.princeton.edu>
+// Aaron Klingaman <alk@cs.princeton.edu>
+// Copyright (C) 2004 The Trustees of Princeton University
+//
+// $Id: keys.php,v 1.8 2005/10/04 18:11:26 alk Exp $
+//
+
+// Get admin API handle
+require_once 'plc_api.php';
+global $adm;
+
+$persons = array();
+$keys = array();
+
+if (!empty($_REQUEST['role'])) {
+  // XXX Implement API query filters
+  // $persons = $adm->GetPersons(array('roles' => array($_REQUEST['role'])));
+  $all_persons = $adm->GetPersons();
+  foreach ($all_persons as $person) {
+    if (in_array($_REQUEST['role'], $person['roles'])) {
+      $persons[] = $person;
+    }
+  }
+}
+
+if (isset($_REQUEST['site_admin'])) {
+  // Look up the node
+  $nodenetworks = $adm->GetNodeNetworks(array($_SERVER['REMOTE_ADDR']));
+  if (!empty($nodenetworks)) {
+    $nodes = $adm->GetNodes(array($nodenetworks[0]['node_id']));
+    if (!empty($nodes)) {
+      $node = $nodes[0];
+    }
+  }
+  
+  if (isset($node)) {
+    // Look up the site
+    $sites = $adm->GetSites(array($node['site_id']));
+    if ($sites && $sites[0]['person_ids']) {
+      // XXX Implement API query filters
+      // $persons = $adm->GetPersons(array('person_id' => $sites[0]['person_ids'],
+      //                                  'roles' => array('pi')));
+      // $persons += $adm->GetPersons(array('person_id' => $sites[0]['person_ids'],
+      //                                   'roles' => array('tech')));
+      $all_persons = $adm->GetPersons($sites[0]['person_ids']);
+      foreach ($all_persons as $person) {
+       if (in_array('pi', $person['roles']) ||
+           in_array('tech', $person['roles'])) {
+         $persons[] = $person;
+       }
+      }
+    }
+  }
+}
+
+if (isset($_REQUEST['root'])) {
+  $keys[] = array('key' => file_get_contents(PLC_ROOT_SSH_KEY_PUB));
+}
+
+if (!empty($persons)) {
+  $key_ids = array();
+  foreach ($persons as $person) {
+    $key_ids = $key_ids + $person['key_ids'];
+  }
+
+  if (!empty($key_ids)) {
+    $keys = $keys + $adm->GetKeys($key_ids);
+  }
+}
+
+foreach ($keys as $key) {
+  print $key['key'];
+}
+
+?>
diff --git a/logrotate.conf b/logrotate.conf
new file mode 100755 (executable)
index 0000000..23a41c5
--- /dev/null
@@ -0,0 +1,25 @@
+# see "man logrotate" for details
+# rotate log files weekly
+weekly
+
+# keep 4 weeks worth of backlogs
+rotate 4
+
+# create new (empty) log files after rotating old ones
+create
+
+# uncomment this if you want your log files compressed
+#compress
+
+# RPM packages drop log rotation information into this directory
+include /etc/logrotate.d
+
+# no packages own wtmp -- we'll rotate them here
+/var/log/wtmp {
+    monthly
+    create 0664 root utmp
+    rotate 1000
+    compress
+}
+
+# system-specific logs may be also be configured here.
diff --git a/ntp.conf.php b/ntp.conf.php
new file mode 100755 (executable)
index 0000000..4b28145
--- /dev/null
@@ -0,0 +1,98 @@
+<?php
+//
+// /etc/ntp.conf generator
+//
+// Marc Fiuczynski <mef@cs.princeton.edu>
+// Copyright (C) 2006 The Trustees of Princeton University
+// 
+// $Id$
+//
+
+// Get admin API handle
+require_once 'plc_api.php';
+global $adm;
+
+$config_directory = "/var/www/html/PlanetLabConf/ntp/";
+$file_prefix = "ntp.conf.";
+$default_name = "default";
+$file_name = $config_directory . $file_prefix . $default_name;
+
+// Look up the node
+$nodenetworks = $adm->GetNodeNetworks(array($_SERVER['REMOTE_ADDR']));
+if (!empty($nodenetworks)) {
+  $nodes = $adm->GetNodes(array($nodenetworks[0]['node_id']));
+  if (!empty($nodes)) {
+    $node = $nodes[0];
+  }
+}
+
+if (!isset($node)) {
+  readfile($file_name); 
+  exit();
+}
+
+$problem_models = array("Dell Precision 340", "Unknown");
+
+$hostname= trim($node['hostname']);
+$model= trim($node['model']);
+
+/* pull LatLong data */
+$sites = $adm->GetSites(array($node['site_id']));
+if (!empty($sites)) {
+  $site_name= $sites[0]['name'];
+  $mylat= $sites[0]['latitude'];
+  $mylong= $sites[0]['longitude'];
+}
+
+/* typical NTP settings */
+
+print( "# node $hostname site $site_name $mylat $mylong $model\n");
+print( "driftfile /var/lib/ntp/ntp.drift\n" );
+print( "statsdir /var/log/ntpstats/\n" );
+if (is_numeric(array_search($model, $problem_models))) {
+  print( "tinker stepout 0\n" );
+}
+
+/* Look for config file */
+
+$hostname_bits = explode('.', $hostname);
+$chunk_counter = sizeof ($hostname_bits);
+$compare_chunk = $hostname ;
+$found_file = 0;
+
+/* look for host specific overrides */
+$file_name = $config_directory . "host/" . $file_prefix . $compare_chunk ;
+if (is_file($file_name)) {
+  $chunk_counter = 0;
+  $found_file = 1;
+}
+
+/* look for domain specific overrides */
+while ($chunk_counter > 0) {
+  $file_name = $config_directory . $file_prefix . $compare_chunk ;
+  if (is_file($file_name)) {
+    $chunk_counter = 0;
+    $found_file = 1;
+  }
+  else {
+    array_shift($hostname_bits);
+    $compare_chunk = implode('.',$hostname_bits);
+    $chunk_counter--;
+  }
+}
+
+
+if ($found_file and is_readable($file_name)) {
+  readfile($file_name);
+} 
+else {
+  if (is_numeric(array_search($model,$problem_models))) {
+    $file_name = $config_directory . $file_prefix . "prob." . $default_name ;
+  }
+  else {
+    $file_name = $config_directory . $file_prefix . $default_name ;
+  }
+  readfile($file_name); 
+} 
+
+?>
\ No newline at end of file
diff --git a/ntp/ntp.conf.default b/ntp/ntp.conf.default
new file mode 100755 (executable)
index 0000000..a1ff389
--- /dev/null
@@ -0,0 +1,6 @@
+server clock.redhat.com
+server time.apple.com
+server pool.ntp.org
+server mit-main.ron.lcs.mit.edu
+server ucsd.ron.lcs.mit.edu
+server utah.ron.lcs.mit.edu
diff --git a/ntp/ntp.conf.prob.default b/ntp/ntp.conf.prob.default
new file mode 100755 (executable)
index 0000000..a3f3cd9
--- /dev/null
@@ -0,0 +1,6 @@
+server clock.redhat.com minpoll 5 burst
+server time.apple.com minpoll 5 burst
+server pool.ntp.org minpoll 5 burst
+server mit-main.ron.lcs.mit.edu minpoll 5 burst
+server ucsd.ron.lcs.mit.edu minpoll 5 burst
+server utah.ron.lcs.mit.edu  minpoll 5 burst
diff --git a/ntp/step-tickers.php b/ntp/step-tickers.php
new file mode 100755 (executable)
index 0000000..bcdc90b
--- /dev/null
@@ -0,0 +1,78 @@
+<?php
+//
+// /etc/ntp/step-tickers generator
+//
+// Marc Fiuczynski <mef@cs.princeton.edu>
+// Copyright (C) 2006 The Trustees of Princeton University
+// 
+// $Id$
+//
+
+// Get admin API handle
+require_once 'plc_api.php';
+global $adm;
+
+$config_directory= "/var/www/html/PlanetLabConf/ntp/";
+$file_prefix= "ntp.conf.";
+$default_name = "default";
+$file_name = $config_directory . $file_prefix . $default_name;
+
+// Look up the node
+$nodenetworks = $adm->GetNodeNetworks(array($_SERVER['REMOTE_ADDR']));
+if (!empty($nodenetworks)) {
+  $nodes = $adm->GetNodes(array($nodenetworks[0]['node_id']));
+  if (!empty($nodes)) {
+    $node = $nodes[0];
+  }
+}
+
+if (!isset($node)) {
+  readfile($file_name); 
+  exit();
+}
+
+/* Look for config file */
+
+$hostname_bits = explode('.', $hostname);
+$chunk_counter = sizeof ($hostname_bits);
+$compare_chunk = $hostname ;
+$found_file = 0;
+
+/* look for the host specific overrides */
+$file_name = $config_directory . "host/". $file_prefix . $compare_chunk ;
+if (is_file($file_name)) {
+  $chunk_counter = 0;
+  $found_file = 1;
+ }
+
+/* look for the domain specific overrides */
+while ($chunk_counter > 0) {
+  $file_name = $config_directory . $file_prefix . $compare_chunk ;
+  if (is_file($file_name)) {
+    $chunk_counter = 0;
+    $found_file = 1;
+  }
+  else {
+    array_shift($hostname_bits);
+    $compare_chunk = implode('.',$hostname_bits);
+    $chunk_counter--;
+  }
+}
+
+if ($found_file and is_readable($file_name)) {
+  $lines=file($file_name);
+} 
+else {
+  $file_name = $config_directory . $file_prefix . $default_name ;
+  $lines=file($file_name);
+} 
+
+foreach ($lines as $line_num => $line) {
+  $line=rtrim($line);
+  $elements=explode(' ',$line);
+  if ($elements[0] == "server") {
+    print ("$elements[1]\n");
+  }
+}
+
+?>
\ No newline at end of file
diff --git a/ntptickers.php b/ntptickers.php
new file mode 100755 (executable)
index 0000000..263fecb
--- /dev/null
@@ -0,0 +1,53 @@
+<?php
+
+require_once('setup_plconf.php');
+
+/* Look for config file */
+
+$config_directory= "/var/www/html/PlanetLabConf/ntp/";
+$file_prefix= "ntp.conf.";
+$hostname_bits = explode('.', $hostname);
+$chunk_counter = sizeof ($hostname_bits);
+$compare_chunk = $hostname ;
+$found_file = 0;
+$default_name = "default";
+
+/* look for the host specific overrides */
+$file_name = $config_directory . "host/". $file_prefix . $compare_chunk ;
+if (is_file($file_name)) {
+       $chunk_counter = 0;
+       $found_file = 1;
+}
+
+/* look for the domain specific overrides */
+while ($chunk_counter > 0) {
+       $file_name = $config_directory . $file_prefix . $compare_chunk ;
+       if (is_file($file_name)) {
+               $chunk_counter = 0;
+               $found_file = 1;
+       }
+       else {
+               array_shift($hostname_bits);
+               $compare_chunk = implode('.',$hostname_bits);
+               $chunk_counter--;
+       }
+}
+
+if ($found_file and is_readable($file_name)) {
+       $lines=file($file_name);
+} 
+else {
+       $file_name = $config_directory . $file_prefix . $default_name ;
+       $lines=file($file_name);
+} 
+
+foreach ($lines as $line_num => $line) {
+       $line=rtrim($line);
+       $elements=explode(' ',$line);
+       if ($elements[0] == "server") {
+               print ("$elements[1]\n");
+       }
+}
+
+?>
+
diff --git a/pl_nm.conf b/pl_nm.conf
new file mode 100755 (executable)
index 0000000..1dc4fdc
--- /dev/null
@@ -0,0 +1,2 @@
+CPU_SHARES=yes
+VMM_MODULES=VServerVmm
diff --git a/propd.conf b/propd.conf
new file mode 100755 (executable)
index 0000000..dd5a6d0
--- /dev/null
@@ -0,0 +1,100 @@
+#
+# default ACL:
+#
+# anyone can execute the get_file_flags operation (since it is applied
+# within the caller's vserver and the command lsattr gives the same
+# info anyway) or get the version string.  wait is harmless too since
+# the caller needs to know the child ID.  and we let any slice unmount
+# directories in its own filesystem, mostly as a workaround for some
+# Stork problems.
+#
+*: get_file_flags
+*: version
+*: wait
++: unmount
+
+# give Stork permission to mount and unmount client dirs
+arizona_stork: mount_dir
+arizona_stork: set_file_flags pass, "1"
+arizona_stork: set_file_flags_list "1"
+arizona_stork: bind_socket sockname=64?:*
+arizona_stork2: mount_dir
+arizona_stork2: set_file_flags pass, "1"
+arizona_stork2: set_file_flags_list "1"
+arizona_stork2: bind_socket sockname=64?:*
+
+# give CoMon the necessary permissions to run slicestat
+princeton_slicestat: exec "root", pass, "/usr/local/planetlab/bin/pl-ps", none
+princeton_slicestat: exec "root", pass, "/usr/sbin/vtop", "bn1", none
+princeton_slicestat: open_file file=/proc/virtual/*/cacct
+princeton_slicestat: open_file file=/proc/virtual/*/limit
+princeton_comon: open_file file=/var/log/secure
+princeton_comon: exec "root", pass, "/bin/df", "/vservers", none
+
+# give pl_slicedir access to /etc/passwd
+pl_slicedir: open_file pass, "/etc/passwd"
+
+# netflow now runs in a slice so needs various accesses
+pl_netflow: open file=/etc/passwd, flags=r
+pl_netflow: open_file file=/etc/passwd
+pl_netflow: create_socket
+pl_netflow: bind_socket
+
+# nyu_d are building a DNS demux so give them access to port 53
+nyu_d: bind_socket
+nyu_oasis: bind_socket
+
+# QA slices need to be able to create and delete bind-mounts
+pl_qa_0: mount_dir
+pl_qa_1: mount_dir
+
+# irb_snort needs packet sockets for tcpdump
+irb_snort: create_socket
+
+# uw_ankur is using netlink sockets to do the same thing as netflow
+uw_ankur: create_socket
+
+# cornell_codons gets access to port 53 for now
+cornell_codons: create_socket
+
+# give Mic Bowman's conf-monitor service read-only access to root fs
+# and the ability to run df
+idsl_monitor: mount_dir "root:/", pass, "ro"
+idsl_monitor: unmount
+idsl_monitor: exec "root", pass, "/bin/df", "-P", "/", "/vservers", none
+
+# give Shark access to port 111 to run portmap
+# and port 955 to run mount
+nyu_shkr: bind_socket
+nyu_shkr: mount_dir "nfs:**:**"
+nyu_shkr: exec "root", pass, "/bin/umount", "-l", "/vservers/nyu_shkr/**", none
+
+# give tsinghua_lgh access to restricted ports
+tsinghua_lgh: bind_socket
+
+# CoDeeN needs port 53 too
+princeton_codeen: bind_socket sockname=53:*
+
+# give ucin_load access to /var/log/wtmp
+ucin_load: open_file file=/var/log/wtmp*
+
+# give google_highground permission to bind port 81 (and raw sockets)
+google_highground: bind_socket
+
+# pl_conf needs access to port 814
+pl_conf: bind_socket sockname=814:*
+pl_conf: open file=/home/*/.ssh/authorized_keys
+
+# give princeton_visp permission to read all packets sent through the
+# tap0 device
+princeton_visp: open file=/dev/net/tun, flags=rw
+
+# The PLB group needs the BGP port
+princeton_iias: bind_socket sockname=179:*
+princeton_visp: bind_socket sockname=179:*
+mit_rcp: bind_socket sockname=179:*
+
+# PL-VINI group
+mit_rcp: exec "root", pass, "/usr/bin/chrt"
+princeton_iias: exec "root", pass, "/usr/bin/chrt"
+uw_arvind: exec "root", pass, "/usr/bin/chrt"
diff --git a/proxies.php b/proxies.php
new file mode 100755 (executable)
index 0000000..4a1dedd
--- /dev/null
@@ -0,0 +1,66 @@
+#
+# /etc/planetlab/proxies
+#
+# post: service vnet restart
+#
+# Proxy (a.k.a. network telescope a.k.a. honeypot) nodenetwork configuration
+#
+# Aaron Klingaman <alk@cs.princeton.edu>
+# Mark Huang <mlhuang@cs.princeton.edu>
+# Copyright (C) 2004 The Trustees of Princeton University
+#
+# $Id: proxies.php,v 1.8 2005/10/07 17:55:41 mlhuang Exp $
+#
+
+<?php
+// Get admin API handle
+require_once 'plc_api.php';
+global $adm;
+
+// Look up the node
+$nodenetworks = $adm->GetNodeNetworks(array($_SERVER['REMOTE_ADDR']));
+if (!empty($nodenetworks)) {
+  $nodes = $adm->GetNodes(array($nodenetworks[0]['node_id']));
+  if (!empty($nodes)) {
+    $node = $nodes[0];
+  }
+}
+
+if (!isset($node)) {
+  exit();
+}
+
+$nodenetworks = $adm->GetNodeNetworks($node['nodenetwork_ids']);
+
+foreach ($nodenetworks as $nodenetwork) {
+  // XXX PL2896: need nodenetworks.device
+  switch ($nodenetwork['method']) {
+  case 'tap':
+    $dev = "tap0";
+    $types['taps'][$dev][0] = $nodenetwork['ip'] . "/" . $nodenetwork['gateway'];
+    break;
+  case 'proxy':
+    $dev = "proxy0";
+    $types['proxies'][$dev][] = $nodenetwork['ip'];
+    break;
+  }
+}
+
+// taps="tap0 tap1 ..."
+// tap0="1.2.3.4/5.6.7.8"
+// tap1="9.10.11.12/13.14.15.16"
+// ...
+// proxies="proxy0 proxy1 ..."
+// proxy0="1.2.3.4 5.6.7.8 ..."
+// proxy1="9.10.11.12 13.14.15.16 ..."
+// ...
+if (isset($types)) {
+  foreach ($types as $type => $devs) {
+    print("$type=\"" . implode(" ", array_keys($devs)) . "\"\n");
+    foreach ($devs as $dev => $ips) {
+      print("$dev=\"" . implode(" ", $ips) . "\"\n");
+    }
+  }
+}
+
+?>
diff --git a/sendmail.cf b/sendmail.cf
new file mode 100755 (executable)
index 0000000..b217edf
--- /dev/null
@@ -0,0 +1,1819 @@
+#
+# Copyright (c) 1998-2003 Sendmail, Inc. and its suppliers.
+#      All rights reserved.
+# Copyright (c) 1983, 1995 Eric P. Allman.  All rights reserved.
+# Copyright (c) 1988, 1993
+#      The Regents of the University of California.  All rights reserved.
+#
+# By using this file, you agree to the terms and conditions set
+# forth in the LICENSE file which can be found at the top level of
+# the sendmail distribution.
+#
+#
+
+######################################################################
+######################################################################
+#####
+#####          SENDMAIL CONFIGURATION FILE
+#####
+##### built by root@alice.cs.princeton.edu on Wed Nov 3 22:29:56 UTC 2004
+##### in /etc/mail
+##### using /usr/share/sendmail-cf/ as configuration include directory
+#####
+######################################################################
+#####
+#####  DO NOT EDIT THIS FILE!  Only edit the source .mc file.
+#####
+######################################################################
+######################################################################
+
+#####  $Id: alpha-sendmail.cf,v 1.3 2005/06/03 13:59:40 alk Exp $  #####
+#####  $Id: alpha-sendmail.cf,v 1.3 2005/06/03 13:59:40 alk Exp $  #####
+#####  setup for Red Hat Linux  #####
+#####  $Id: alpha-sendmail.cf,v 1.3 2005/06/03 13:59:40 alk Exp $  #####
+
+
+
+#####  $Id: alpha-sendmail.cf,v 1.3 2005/06/03 13:59:40 alk Exp $  #####
+
+
+
+
+
+
+
+
+
+#####  $Id: alpha-sendmail.cf,v 1.3 2005/06/03 13:59:40 alk Exp $  #####
+
+#####  $Id: alpha-sendmail.cf,v 1.3 2005/06/03 13:59:40 alk Exp $  #####
+
+#####  $Id: alpha-sendmail.cf,v 1.3 2005/06/03 13:59:40 alk Exp $  #####
+
+#####  $Id: alpha-sendmail.cf,v 1.3 2005/06/03 13:59:40 alk Exp $  #####
+
+#####  $Id: alpha-sendmail.cf,v 1.3 2005/06/03 13:59:40 alk Exp $  #####
+
+#####  $Id: alpha-sendmail.cf,v 1.3 2005/06/03 13:59:40 alk Exp $  #####
+
+#####  $Id: alpha-sendmail.cf,v 1.3 2005/06/03 13:59:40 alk Exp $  #####
+
+
+#####  $Id: alpha-sendmail.cf,v 1.3 2005/06/03 13:59:40 alk Exp $  #####
+
+
+#####  $Id: alpha-sendmail.cf,v 1.3 2005/06/03 13:59:40 alk Exp $  #####
+
+#####  $Id: alpha-sendmail.cf,v 1.3 2005/06/03 13:59:40 alk Exp $  #####
+
+#####  $Id: alpha-sendmail.cf,v 1.3 2005/06/03 13:59:40 alk Exp $  #####
+
+#####  $Id: alpha-sendmail.cf,v 1.3 2005/06/03 13:59:40 alk Exp $  #####
+
+#####  $Id: alpha-sendmail.cf,v 1.3 2005/06/03 13:59:40 alk Exp $  #####
+
+#####  $Id: alpha-sendmail.cf,v 1.3 2005/06/03 13:59:40 alk Exp $  #####
+
+
+#####  $Id: alpha-sendmail.cf,v 1.3 2005/06/03 13:59:40 alk Exp $  #####
+
+# level 10 config file format
+V10/Berkeley
+
+# override file safeties - setting this option compromises system security,
+# addressing the actual file configuration problem is preferred
+# need to set this before any file actions are encountered in the cf file
+#O DontBlameSendmail=safe
+
+# default LDAP map specification
+# need to set this now before any LDAP maps are defined
+#O LDAPDefaultSpec=-h localhost
+
+##################
+#   local info   #
+##################
+
+# my LDAP cluster
+# need to set this before any LDAP lookups are done (including classes)
+#D{sendmailMTACluster}$m
+
+Cwlocalhost
+# file containing names of hosts for which we receive email
+Fw/etc/mail/local-host-names
+
+# my official domain name
+# ... define this only if sendmail cannot automatically determine your domain
+#Dj$w.Foo.COM
+
+# host/domain names ending with a token in class P are canonical
+CP.
+
+# "Smart" relay host (may be null)
+DS
+
+
+# operators that cannot be in local usernames (i.e., network indicators)
+CO @ % !
+
+# a class with just dot (for identifying canonical names)
+C..
+
+# a class with just a left bracket (for identifying domain literals)
+C[[
+
+# access_db acceptance class
+C{Accept}OK RELAY
+
+
+C{ResOk}OKR
+
+
+# Hosts for which relaying is permitted ($=R)
+FR-o /etc/mail/relay-domains
+
+# arithmetic map
+Karith arith
+# macro storage map
+Kmacro macro
+# possible values for TLS_connection in access map
+C{tls}VERIFY ENCR
+
+
+
+
+
+# dequoting map
+Kdequote dequote
+
+# class E: names that should be exposed as from this host, even if we masquerade
+# class L: names that should be delivered locally, even if we have a relay
+# class M: domains that should be converted to $M
+# class N: domains that should not be converted to $M
+#CL root
+C{w}localhost.localdomain
+C{M}localhost
+C{M}localhost.localdomain
+
+# who I masquerade as (null for no masquerading) (see also $=M)
+DMplanet-lab.org
+
+# my name for error messages
+DnMAILER-DAEMON
+
+
+# Mailer table (overriding domains)
+Kmailertable hash -o /etc/mail/mailertable.db
+
+# Virtual user table (maps incoming users)
+Kvirtuser hash -o /etc/mail/virtusertable.db
+
+CPREDIRECT
+
+# Access list database (for spam stomping)
+Kaccess hash -T<TMPF> -o /etc/mail/access.db
+
+# Configuration version number
+DZ8.12.11
+
+
+###############
+#   Options   #
+###############
+
+# strip message body to 7 bits on input?
+O SevenBitInput=False
+
+# 8-bit data handling
+#O EightBitMode=pass8
+
+# wait for alias file rebuild (default units: minutes)
+O AliasWait=10
+
+# location of alias file
+O AliasFile=/etc/aliases
+
+# minimum number of free blocks on filesystem
+O MinFreeBlocks=100
+
+# maximum message size
+#O MaxMessageSize=1000000
+
+# substitution for space (blank) characters
+O BlankSub=.
+
+# avoid connecting to "expensive" mailers on initial submission?
+O HoldExpensive=False
+
+# checkpoint queue runs after every N successful deliveries
+#O CheckpointInterval=10
+
+# default delivery mode
+O DeliveryMode=background
+
+# error message header/file
+#O ErrorHeader=/etc/mail/error-header
+
+# error mode
+#O ErrorMode=print
+
+# save Unix-style "From_" lines at top of header?
+#O SaveFromLine=False
+
+# queue file mode (qf files)
+#O QueueFileMode=0600
+
+# temporary file mode
+O TempFileMode=0600
+
+# match recipients against GECOS field?
+#O MatchGECOS=False
+
+# maximum hop count
+#O MaxHopCount=25
+
+# location of help file
+O HelpFile=/etc/mail/helpfile
+
+# ignore dots as terminators in incoming messages?
+#O IgnoreDots=False
+
+# name resolver options
+#O ResolverOptions=+AAONLY
+
+# deliver MIME-encapsulated error messages?
+O SendMimeErrors=True
+
+# Forward file search path
+O ForwardPath=$z/.forward.$w:$z/.forward
+
+# open connection cache size
+O ConnectionCacheSize=2
+
+# open connection cache timeout
+O ConnectionCacheTimeout=5m
+
+# persistent host status directory
+#O HostStatusDirectory=.hoststat
+
+# single thread deliveries (requires HostStatusDirectory)?
+#O SingleThreadDelivery=False
+
+# use Errors-To: header?
+O UseErrorsTo=False
+
+# log level
+O LogLevel=9
+
+# send to me too, even in an alias expansion?
+#O MeToo=True
+
+# verify RHS in newaliases?
+O CheckAliases=False
+
+# default messages to old style headers if no special punctuation?
+O OldStyleHeaders=True
+
+# SMTP daemon options
+
+O DaemonPortOptions=Port=smtp,Addr=127.0.0.1, Name=MTA
+
+# SMTP client options
+#O ClientPortOptions=Family=inet, Address=0.0.0.0
+
+# Modifiers to define {daemon_flags} for direct submissions
+#O DirectSubmissionModifiers
+
+# Use as mail submission program? See sendmail/SECURITY
+#O UseMSP
+
+# privacy flags
+O PrivacyOptions=authwarnings,novrfy,noexpn,restrictqrun
+
+# who (if anyone) should get extra copies of error messages
+#O PostmasterCopy=Postmaster
+
+# slope of queue-only function
+#O QueueFactor=600000
+
+# limit on number of concurrent queue runners
+#O MaxQueueChildren
+
+# maximum number of queue-runners per queue-grouping with multiple queues
+#O MaxRunnersPerQueue=1
+
+# priority of queue runners (nice(3))
+#O NiceQueueRun
+
+# shall we sort the queue by hostname first?
+#O QueueSortOrder=priority
+
+# minimum time in queue before retry
+#O MinQueueAge=30m
+
+# how many jobs can you process in the queue?
+#O MaxQueueRunSize=10000
+
+# perform initial split of envelope without checking MX records
+#O FastSplit=1
+
+# queue directory
+O QueueDirectory=/var/spool/mqueue
+
+# key for shared memory; 0 to turn off
+#O SharedMemoryKey=0
+
+
+
+# timeouts (many of these)
+#O Timeout.initial=5m
+O Timeout.connect=1m
+#O Timeout.aconnect=0s
+#O Timeout.iconnect=5m
+#O Timeout.helo=5m
+#O Timeout.mail=10m
+#O Timeout.rcpt=1h
+#O Timeout.datainit=5m
+#O Timeout.datablock=1h
+#O Timeout.datafinal=1h
+#O Timeout.rset=5m
+#O Timeout.quit=2m
+#O Timeout.misc=2m
+#O Timeout.command=1h
+O Timeout.ident=0
+#O Timeout.fileopen=60s
+#O Timeout.control=2m
+O Timeout.queuereturn=5d
+#O Timeout.queuereturn.normal=5d
+#O Timeout.queuereturn.urgent=2d
+#O Timeout.queuereturn.non-urgent=7d
+
+O Timeout.queuewarn=4h
+#O Timeout.queuewarn.normal=4h
+#O Timeout.queuewarn.urgent=1h
+#O Timeout.queuewarn.non-urgent=12h
+
+#O Timeout.hoststatus=30m
+#O Timeout.resolver.retrans=5s
+#O Timeout.resolver.retrans.first=5s
+#O Timeout.resolver.retrans.normal=5s
+#O Timeout.resolver.retry=4
+#O Timeout.resolver.retry.first=4
+#O Timeout.resolver.retry.normal=4
+#O Timeout.lhlo=2m
+#O Timeout.auth=10m
+#O Timeout.starttls=1h
+
+# time for DeliverBy; extension disabled if less than 0
+#O DeliverByMin=0
+
+# should we not prune routes in route-addr syntax addresses?
+#O DontPruneRoutes=False
+
+# queue up everything before forking?
+O SuperSafe=True
+
+# status file
+O StatusFile=/var/log/mail/statistics
+
+# time zone handling:
+#  if undefined, use system default
+#  if defined but null, use TZ envariable passed in
+#  if defined and non-null, use that info
+#O TimeZoneSpec=
+
+# default UID (can be username or userid:groupid)
+O DefaultUser=8:12
+
+# list of locations of user database file (null means no lookup)
+O UserDatabaseSpec=/etc/mail/userdb.db
+
+# fallback MX host
+#O FallbackMXhost=fall.back.host.net
+
+# if we are the best MX host for a site, try it directly instead of config err
+O TryNullMXList=true
+
+# load average at which we just queue messages
+O QueueLA=60000
+
+# load average at which we refuse connections
+O RefuseLA=60000
+
+# load average at which we delay connections; 0 means no limit
+#O DelayLA=0
+
+# maximum number of children we allow at one time
+#O MaxDaemonChildren=0
+
+# maximum number of new connections per second
+#O ConnectionRateThrottle=0
+
+# work recipient factor
+#O RecipientFactor=30000
+
+# deliver each queued job in a separate process?
+#O ForkEachJob=False
+
+# work class factor
+#O ClassFactor=1800
+
+# work time factor
+#O RetryFactor=90000
+
+# default character set
+#O DefaultCharSet=iso-8859-1
+
+# service switch file (name hardwired on Solaris, Ultrix, OSF/1, others)
+#O ServiceSwitchFile=/etc/mail/service.switch
+
+# hosts file (normally /etc/hosts)
+#O HostsFile=/etc/hosts
+
+# dialup line delay on connection failure
+#O DialDelay=10s
+
+# action to take if there are no recipients in the message
+#O NoRecipientAction=add-to-undisclosed
+
+# chrooted environment for writing to files
+#O SafeFileEnvironment=/arch
+
+# are colons OK in addresses?
+#O ColonOkInAddr=True
+
+# shall I avoid expanding CNAMEs (violates protocols)?
+#O DontExpandCnames=False
+
+# SMTP initial login message (old $e macro)
+O SmtpGreetingMessage=$j Sendmail $v/$Z; $b
+
+# UNIX initial From header format (old $l macro)
+O UnixFromLine=From $g $d
+
+# From: lines that have embedded newlines are unwrapped onto one line
+#O SingleLineFromHeader=False
+
+# Allow HELO SMTP command that does not include a host name
+#O AllowBogusHELO=False
+
+# Characters to be quoted in a full name phrase (@,;:\()[] are automatic)
+#O MustQuoteChars=.
+
+# delimiter (operator) characters (old $o macro)
+O OperatorChars=.:%@!^/[]+
+
+# shall I avoid calling initgroups(3) because of high NIS costs?
+#O DontInitGroups=False
+
+# are group-writable :include: and .forward files (un)trustworthy?
+# True (the default) means they are not trustworthy.
+#O UnsafeGroupWrites=True
+
+
+# where do errors that occur when sending errors get sent?
+#O DoubleBounceAddress=postmaster
+
+# where to save bounces if all else fails
+#O DeadLetterDrop=/var/tmp/dead.letter
+
+# what user id do we assume for the majority of the processing?
+#O RunAsUser=sendmail
+
+# maximum number of recipients per SMTP envelope
+#O MaxRecipientsPerMessage=100
+
+# limit the rate recipients per SMTP envelope are accepted
+# once the threshold number of recipients have been rejected
+#O BadRcptThrottle=20
+
+# shall we get local names from our installed interfaces?
+O DontProbeInterfaces=true
+
+# Return-Receipt-To: header implies DSN request
+#O RrtImpliesDsn=False
+
+# override connection address (for testing)
+#O ConnectOnlyTo=0.0.0.0
+
+# Trusted user for file ownership and starting the daemon
+#O TrustedUser=root
+
+# Control socket for daemon management
+#O ControlSocketName=/var/spool/mqueue/.control
+
+# Maximum MIME header length to protect MUAs
+#O MaxMimeHeaderLength=2048/1024
+
+# Maximum length of the sum of all headers
+#O MaxHeadersLength=32768
+
+# Maximum depth of alias recursion
+#O MaxAliasRecursion=10
+
+# location of pid file
+#O PidFile=/var/run/sendmail.pid
+
+# Prefix string for the process title shown on 'ps' listings
+#O ProcessTitlePrefix=prefix
+
+# Data file (df) memory-buffer file maximum size
+#O DataFileBufferSize=4096
+
+# Transcript file (xf) memory-buffer file maximum size
+#O XscriptFileBufferSize=4096
+
+# lookup type to find information about local mailboxes
+#O MailboxDatabase=pw
+
+# list of authentication mechanisms
+#O AuthMechanisms=EXTERNAL GSSAPI KERBEROS_V4 DIGEST-MD5 CRAM-MD5
+
+# default authentication information for outgoing connections
+#O DefaultAuthInfo=/etc/mail/default-auth-info
+
+# SMTP AUTH flags
+O AuthOptions=A
+
+# SMTP AUTH maximum encryption strength
+#O AuthMaxBits
+
+# SMTP STARTTLS server options
+#O TLSSrvOptions
+
+# Input mail filters
+#O InputMailFilters
+
+
+# CA directory
+O CACertPath=/etc/mail/certs
+# CA file
+O CACertFile=/etc/mail/certs/cacert.pem
+# Server Cert
+O ServerCertFile=/etc/mail/certs/cert.pem
+# Server private key
+O ServerKeyFile=/etc/mail/certs/key.pem
+# Client Cert
+O ClientCertFile=/etc/mail/certs/cert.pem
+# Client private key
+O ClientKeyFile=/etc/mail/certs/key.pem
+# DHParameters (only required if DSA/DH is used)
+#O DHParameters
+# Random data source (required for systems without /dev/urandom under OpenSSL)
+#O RandFile
+
+############################
+# QUEUE GROUP DEFINITIONS  #
+############################
+
+
+###########################
+#   Message precedences   #
+###########################
+
+Pfirst-class=0
+Pspecial-delivery=100
+Plist=-30
+Pbulk=-60
+Pjunk=-100
+
+#####################
+#   Trusted users   #
+#####################
+
+# this is equivalent to setting class "t"
+Ft/etc/mail/trusted-users
+Troot
+Tdaemon
+Tuucp
+
+#########################
+#   Format of headers   #
+#########################
+
+H?P?Return-Path: <$g>
+HReceived: $?sfrom $s $.$?_($?s$|from $.$_)
+       $.$?{auth_type}(authenticated$?{auth_ssf} bits=${auth_ssf}$.)
+       $.by $j ($v/$Z)$?r with $r$. id $i$?{tls_version}
+       (version=${tls_version} cipher=${cipher} bits=${cipher_bits} verify=${verify})$.$?u
+       for $u; $|;
+       $.$b
+H?D?Resent-Date: $a
+H?D?Date: $a
+H?F?Resent-From: $?x$x <$g>$|$g$.
+H?F?From: $?x$x <$g>$|$g$.
+H?x?Full-Name: $x
+# HPosted-Date: $a
+# H?l?Received-Date: $b
+H?M?Resent-Message-Id: <$t.$i@$j>
+H?M?Message-Id: <$t.$i@$j>
+
+#\f
+######################################################################
+######################################################################
+#####
+#####                  REWRITING RULES
+#####
+######################################################################
+######################################################################
+
+############################################
+###  Ruleset 3 -- Name Canonicalization  ###
+############################################
+Scanonify=3
+
+# handle null input (translate to <@> special case)
+R$@                    $@ <@>
+
+# strip group: syntax (not inside angle brackets!) and trailing semicolon
+R$*                    $: $1 <@>                       mark addresses
+R$* < $* > $* <@>      $: $1 < $2 > $3                 unmark <addr>
+R@ $* <@>              $: @ $1                         unmark @host:...
+R$* [ IPv6 : $+ ] <@>  $: $1 [ IPv6 : $2 ]             unmark IPv6 addr
+R$* :: $* <@>          $: $1 :: $2                     unmark node::addr
+R:include: $* <@>      $: :include: $1                 unmark :include:...
+R$* : $* [ $* ]                $: $1 : $2 [ $3 ] <@>           remark if leading colon
+R$* : $* <@>           $: $2                           strip colon if marked
+R$* <@>                        $: $1                           unmark
+R$* ;                     $1                           strip trailing semi
+R$* < $+ :; > $*       $@ $2 :; <@>                    catch <list:;>
+R$* < $* ; >              $1 < $2 >                    bogus bracketed semi
+
+# null input now results from list:; syntax
+R$@                    $@ :; <@>
+
+# strip angle brackets -- note RFC733 heuristic to get innermost item
+R$*                    $: < $1 >                       housekeeping <>
+R$+ < $* >                < $2 >                       strip excess on left
+R< $* > $+                < $1 >                       strip excess on right
+R<>                    $@ < @ >                        MAIL FROM:<> case
+R< $+ >                        $: $1                           remove housekeeping <>
+
+# strip route address <@a,@b,@c:user@d> -> <user@d>
+R@ $+ , $+             $2
+R@ [ $* ] : $+         $2
+R@ $+ : $+             $2
+
+# find focus for list syntax
+R $+ : $* ; @ $+       $@ $>Canonify2 $1 : $2 ; < @ $3 >       list syntax
+R $+ : $* ;            $@ $1 : $2;                     list syntax
+
+# find focus for @ syntax addresses
+R$+ @ $+               $: $1 < @ $2 >                  focus on domain
+R$+ < $+ @ $+ >                $1 $2 < @ $3 >                  move gaze right
+R$+ < @ $+ >           $@ $>Canonify2 $1 < @ $2 >      already canonical
+
+
+# convert old-style addresses to a domain-based address
+R$- ! $+               $@ $>Canonify2 $2 < @ $1 .UUCP >        resolve uucp names
+R$+ . $- ! $+          $@ $>Canonify2 $3 < @ $1 . $2 >         domain uucps
+R$+ ! $+               $@ $>Canonify2 $2 < @ $1 .UUCP >        uucp subdomains
+
+# if we have % signs, take the rightmost one
+R$* % $*               $1 @ $2                         First make them all @s.
+R$* @ $* @ $*          $1 % $2 @ $3                    Undo all but the last.
+R$* @ $*               $@ $>Canonify2 $1 < @ $2 >      Insert < > and finish
+
+# else we must be a local name
+R$*                    $@ $>Canonify2 $1
+
+
+################################################
+###  Ruleset 96 -- bottom half of ruleset 3  ###
+################################################
+
+SCanonify2=96
+
+# handle special cases for local names
+R$* < @ localhost > $*         $: $1 < @ $j . > $2             no domain at all
+R$* < @ localhost . $m > $*    $: $1 < @ $j . > $2             local domain
+R$* < @ localhost . UUCP > $*  $: $1 < @ $j . > $2             .UUCP domain
+
+# check for IPv4/IPv6 domain literal
+R$* < @ [ $+ ] > $*            $: $1 < @@ [ $2 ] > $3          mark [addr]
+R$* < @@ $=w > $*              $: $1 < @ $j . > $3             self-literal
+R$* < @@ $+ > $*               $@ $1 < @ $2 > $3               canon IP addr
+
+
+
+
+
+# if really UUCP, handle it immediately
+
+# try UUCP traffic as a local address
+R$* < @ $+ . UUCP > $*         $: $1 < @ $[ $2 $] . UUCP . > $3
+R$* < @ $+ . . UUCP . > $*     $@ $1 < @ $2 . > $3
+
+# hostnames ending in class P are always canonical
+R$* < @ $* $=P > $*            $: $1 < @ $2 $3 . > $4
+R$* < @ $* $~P > $*            $: $&{daemon_flags} $| $1 < @ $2 $3 > $4
+R$* CC $* $| $* < @ $+.$+ > $* $: $3 < @ $4.$5 . > $6
+R$* CC $* $| $*                        $: $3
+# pass to name server to make hostname canonical
+R$* $| $* < @ $* > $*          $: $2 < @ $[ $3 $] > $4
+R$* $| $*                      $: $2
+
+# local host aliases and pseudo-domains are always canonical
+R$* < @ $=w > $*               $: $1 < @ $2 . > $3
+R$* < @ $* $=M > $*            $: $1 < @ $2 $3 . > $4
+R$* < @ $={VirtHost} > $*      $: $1 < @ $2 . > $3
+R$* < @ $* . . > $*            $1 < @ $2 . > $3
+
+
+##################################################
+###  Ruleset 4 -- Final Output Post-rewriting  ###
+##################################################
+Sfinal=4
+
+R$+ :; <@>             $@ $1 :                         handle <list:;>
+R$* <@>                        $@                              handle <> and list:;
+
+# strip trailing dot off possibly canonical name
+R$* < @ $+ . > $*      $1 < @ $2 > $3
+
+# eliminate internal code
+R$* < @ *LOCAL* > $*   $1 < @ $j > $2
+
+# externalize local domain info
+R$* < $+ > $*          $1 $2 $3                        defocus
+R@ $+ : @ $+ : $+      @ $1 , @ $2 : $3                <route-addr> canonical
+R@ $*                  $@ @ $1                         ... and exit
+
+# UUCP must always be presented in old form
+R$+ @ $- . UUCP                $2!$1                           u@h.UUCP => h!u
+
+# delete duplicate local names
+R$+ % $=w @ $=w                $1 @ $2                         u%host@host => u@host
+
+
+
+##############################################################
+###   Ruleset 97 -- recanonicalize and call ruleset zero   ###
+###               (used for recursive calls)              ###
+##############################################################
+
+SRecurse=97
+R$*                    $: $>canonify $1
+R$*                    $@ $>parse $1
+
+
+######################################
+###   Ruleset 0 -- Parse Address   ###
+######################################
+
+Sparse=0
+
+R$*                    $: $>Parse0 $1          initial parsing
+R<@>                   $#local $: <@>          special case error msgs
+R$*                    $: $>ParseLocal $1      handle local hacks
+R$*                    $: $>Parse1 $1          final parsing
+
+#
+#  Parse0 -- do initial syntax checking and eliminate local addresses.
+#      This should either return with the (possibly modified) input
+#      or return with a #error mailer.  It should not return with a
+#      #mailer other than the #error mailer.
+#
+
+SParse0
+R<@>                   $@ <@>                  special case error msgs
+R$* : $* ; <@>         $#error $@ 5.1.3 $: "553 List:; syntax illegal for recipient addresses"
+R@ <@ $* >             < @ $1 >                catch "@@host" bogosity
+R<@ $+>                        $#error $@ 5.1.3 $: "553 User address required"
+R$+ <@>                        $#error $@ 5.1.3 $: "553 Hostname required"
+R$*                    $: <> $1
+R<> $* < @ [ $* ] : $+ > $*    $1 < @ [ $2 ] : $3 > $4
+R<> $* < @ [ $* ] , $+ > $*    $1 < @ [ $2 ] , $3 > $4
+R<> $* < @ [ $* ] $+ > $*      $#error $@ 5.1.2 $: "553 Invalid address"
+R<> $* < @ [ $+ ] > $*         $1 < @ [ $2 ] > $3
+R<> $* <$* : $* > $*   $#error $@ 5.1.3 $: "553 Colon illegal in host name part"
+R<> $*                 $1
+R$* < @ . $* > $*      $#error $@ 5.1.2 $: "553 Invalid host name"
+R$* < @ $* .. $* > $*  $#error $@ 5.1.2 $: "553 Invalid host name"
+R$* < @ $* @ > $*      $#error $@ 5.1.2 $: "553 Invalid route address"
+R$* @ $* < @ $* > $*   $#error $@ 5.1.3 $: "553 Invalid route address"
+R$* , $~O $*           $#error $@ 5.1.3 $: "553 Invalid route address"
+
+
+# now delete the local info -- note $=O to find characters that cause forwarding
+R$* < @ > $*           $@ $>Parse0 $>canonify $1       user@ => user
+R< @ $=w . > : $*      $@ $>Parse0 $>canonify $2       @here:... -> ...
+R$- < @ $=w . >                $: $(dequote $1 $) < @ $2 . >   dequote "foo"@here
+R< @ $+ >              $#error $@ 5.1.3 $: "553 User address required"
+R$* $=O $* < @ $=w . > $@ $>Parse0 $>canonify $1 $2 $3 ...@here -> ...
+R$-                    $: $(dequote $1 $) < @ *LOCAL* >        dequote "foo"
+R< @ *LOCAL* >         $#error $@ 5.1.3 $: "553 User address required"
+R$* $=O $* < @ *LOCAL* >
+                       $@ $>Parse0 $>canonify $1 $2 $3 ...@*LOCAL* -> ...
+R$* < @ *LOCAL* >      $: $1
+
+#
+#  Parse1 -- the bottom half of ruleset 0.
+#
+
+SParse1
+
+# handle numeric address spec
+R$* < @ [ $+ ] > $*    $: $>ParseLocal $1 < @ [ $2 ] > $3      numeric internet spec
+R$* < @ [ $+ ] > $*    $: $1 < @ [ $2 ] : $S > $3      Add smart host to path
+R$* < @ [ $+ ] : > $*          $#esmtp $@ [$2] $: $1 < @ [$2] > $3     no smarthost: send
+R$* < @ [ $+ ] : $- : $*> $*   $#$3 $@ $4 $: $1 < @ [$2] > $5  smarthost with mailer
+R$* < @ [ $+ ] : $+ > $*       $#esmtp $@ $3 $: $1 < @ [$2] > $4       smarthost without mailer
+
+# handle virtual users
+R$+                    $: <!> $1               Mark for lookup
+R<!> $+ < @ $={VirtHost} . >   $: < $(virtuser $1 @ $2 $@ $1 $: @ $) > $1 < @ $2 . >
+R<!> $+ < @ $=w . >    $: < $(virtuser $1 @ $2 $@ $1 $: @ $) > $1 < @ $2 . >
+R<@> $+ + $+ < @ $* . >
+                       $: < $(virtuser $1 + + @ $3 $@ $1 $@ $2 $@ +$2 $: @ $) > $1 + $2 < @ $3 . >
+R<@> $+ + $* < @ $* . >
+                       $: < $(virtuser $1 + * @ $3 $@ $1 $@ $2 $@ +$2 $: @ $) > $1 + $2 < @ $3 . >
+R<@> $+ + $* < @ $* . >
+                       $: < $(virtuser $1 @ $3 $@ $1 $@ $2 $@ +$2 $: @ $) > $1 + $2 < @ $3 . >
+R<@> $+ + $+ < @ $+ . >        $: < $(virtuser + + @ $3 $@ $1 $@ $2 $@ +$2 $: @ $) > $1 + $2 < @ $3 . >
+R<@> $+ + $* < @ $+ . >        $: < $(virtuser + * @ $3 $@ $1 $@ $2 $@ +$2 $: @ $) > $1 + $2 < @ $3 . >
+R<@> $+ + $* < @ $+ . >        $: < $(virtuser @ $3 $@ $1 $@ $2 $@ +$2 $: ! $) > $1 + $2 < @ $3 . >
+R<@> $+ < @ $+ . >     $: < $(virtuser @ $2 $@ $1 $: @ $) > $1 < @ $2 . >
+R<@> $+                        $: $1
+R<!> $+                        $: $1
+R< error : $-.$-.$- : $+ > $*  $#error $@ $1.$2.$3 $: $4
+R< error : $- $+ > $*  $#error $@ $(dequote $1 $) $: $2
+R< $+ > $+ < @ $+ >    $: $>Recurse $1
+
+# short circuit local delivery so forwarded email works
+
+
+R$=L < @ $=w . >       $#local $: @ $1                 special local names
+R$+ < @ $=w . >                $#local $: $1                   regular local name
+
+# not local -- try mailer table lookup
+R$* <@ $+ > $*         $: < $2 > $1 < @ $2 > $3        extract host name
+R< $+ . > $*           $: < $1 > $2                    strip trailing dot
+R< $+ > $*             $: < $(mailertable $1 $) > $2   lookup
+R< $~[ : $* > $*       $>MailerToTriple < $1 : $2 > $3         check -- resolved?
+R< $+ > $*             $: $>Mailertable <$1> $2                try domain
+
+# resolve remotely connected UUCP links (if any)
+
+# resolve fake top level domains by forwarding to other hosts
+
+
+
+# pass names that still have a host to a smarthost (if defined)
+R$* < @ $* > $*                $: $>MailerToTriple < $S > $1 < @ $2 > $3       glue on smarthost name
+
+# deal with other remote names
+R$* < @$* > $*         $#esmtp $@ $2 $: $1 < @ $2 > $3 user@host.domain
+
+# handle locally delivered names
+R$=L                   $#local $: @ $1         special local names
+R$+                    $#local $: $1                   regular local names
+
+###########################################################################
+###   Ruleset 5 -- special rewriting after aliases have been expanded   ###
+###########################################################################
+
+SLocal_localaddr
+Slocaladdr=5
+R$+                    $: $1 $| $>"Local_localaddr" $1
+R$+ $| $#ok            $@ $1                   no change
+R$+ $| $#$*            $#$2
+R$+ $| $*              $: $1
+
+
+
+
+# deal with plussed users so aliases work nicely
+R$+ + *                        $#local $@ $&h $: $1
+R$+ + $*               $#local $@ + $2 $: $1 + *
+
+# prepend an empty "forward host" on the front
+R$+                    $: <> $1
+
+
+
+R< > $+                        $: < > < $1 <> $&h >            nope, restore +detail
+
+R< > < $+ <> + $* >    $: < > < $1 + $2 >              check whether +detail
+R< > < $+ <> $* >      $: < > < $1 >                   else discard
+R< > < $+ + $* > $*       < > < $1 > + $2 $3           find the user part
+R< > < $+ > + $*       $#local $@ $2 $: @ $1           strip the extra +
+R< > < $+ >            $@ $1                           no +detail
+R$+                    $: $1 <> $&h                    add +detail back in
+
+R$+ <> + $*            $: $1 + $2                      check whether +detail
+R$+ <> $*              $: $1                           else discard
+R< local : $* > $*     $: $>MailerToTriple < local : $1 > $2   no host extension
+R< error : $* > $*     $: $>MailerToTriple < error : $1 > $2   no host extension
+
+R< $~[ : $+ > $+       $: $>MailerToTriple < $1 : $2 > $3 < @ $2 >
+
+R< $+ > $+             $@ $>MailerToTriple < $1 > $2 < @ $1 >
+
+
+###################################################################
+###  Ruleset 90 -- try domain part of mailertable entry        ###
+###################################################################
+
+SMailertable=90
+R$* <$- . $+ > $*      $: $1$2 < $(mailertable .$3 $@ $1$2 $@ $2 $) > $4
+R$* <$~[ : $* > $*     $>MailerToTriple < $2 : $3 > $4         check -- resolved?
+R$* < . $+ > $*        $@ $>Mailertable $1 . <$2> $3           no -- strip & try again
+R$* < $* > $*          $: < $(mailertable . $@ $1$2 $) > $3    try "."
+R< $~[ : $* > $*       $>MailerToTriple < $1 : $2 > $3         "." found?
+R< $* > $*             $@ $2                           no mailertable match
+
+###################################################################
+###  Ruleset 95 -- canonify mailer:[user@]host syntax to triple        ###
+###################################################################
+
+SMailerToTriple=95
+R< > $*                                $@ $1                   strip off null relay
+R< error : $-.$-.$- : $+ > $*  $#error $@ $1.$2.$3 $: $4
+R< error : $- : $+ > $*                $#error $@ $(dequote $1 $) $: $2
+R< error : $+ > $*             $#error $: $1
+R< local : $* > $*             $>CanonLocal < $1 > $2
+R< $~[ : $+ @ $+ > $*<$*>$*    $# $1 $@ $3 $: $2<@$3>  use literal user
+R< $~[ : $+ > $*               $# $1 $@ $2 $: $3       try qualified mailer
+R< $=w > $*                    $@ $2                   delete local host
+R< $+ > $*                     $#relay $@ $1 $: $2     use unqualified mailer
+
+###################################################################
+###  Ruleset CanonLocal -- canonify local: syntax              ###
+###################################################################
+
+SCanonLocal
+# strip local host from routed addresses
+R< $* > < @ $+ > : $+          $@ $>Recurse $3
+R< $* > $+ $=O $+ < @ $+ >     $@ $>Recurse $2 $3 $4
+
+# strip trailing dot from any host name that may appear
+R< $* > $* < @ $* . >          $: < $1 > $2 < @ $3 >
+
+# handle local: syntax -- use old user, either with or without host
+R< > $* < @ $* > $*            $#local $@ $1@$2 $: $1
+R< > $+                                $#local $@ $1    $: $1
+
+# handle local:user@host syntax -- ignore host part
+R< $+ @ $+ > $* < @ $* >       $: < $1 > $3 < @ $4 >
+
+# handle local:user syntax
+R< $+ > $* <@ $* > $*          $#local $@ $2@$3 $: $1
+R< $+ > $*                     $#local $@ $2    $: $1
+
+###################################################################
+###  Ruleset 93 -- convert header names to masqueraded form    ###
+###################################################################
+
+SMasqHdr=93
+
+
+# do not masquerade anything in class N
+R$* < @ $* $=N . >     $@ $1 < @ $2 $3 . >
+
+# special case the users that should be exposed
+R$=E < @ *LOCAL* >     $@ $1 < @ $j . >                leave exposed
+R$=E < @ $* $=M . >    $@ $1 < @ $2 $3 . >
+R$=E < @ $=w . >       $@ $1 < @ $2 . >
+
+# handle domain-specific masquerading
+R$* < @ $* $=M . > $*  $: $1 < @ $2 $3 . @ $M > $4     convert masqueraded doms
+R$* < @ $=w . > $*     $: $1 < @ $2 . @ $M > $3
+R$* < @ *LOCAL* > $*   $: $1 < @ $j . @ $M > $2
+R$* < @ $+ @ > $*      $: $1 < @ $2 > $3               $M is null
+R$* < @ $+ @ $+ > $*   $: $1 < @ $3 . > $4             $M is not null
+
+###################################################################
+###  Ruleset 94 -- convert envelope names to masqueraded form  ###
+###################################################################
+
+SMasqEnv=94
+R$+                    $@ $>MasqHdr $1
+
+###################################################################
+###  Ruleset 98 -- local part of ruleset zero (can be null)    ###
+###################################################################
+
+SParseLocal=98
+
+# addresses sent to foo@host.REDIRECT will give a 551 error code
+R$* < @ $+ .REDIRECT. >                $: $1 < @ $2 . REDIRECT . > < ${opMode} >
+R$* < @ $+ .REDIRECT. > <i>    $: $1 < @ $2 . REDIRECT. >
+R$* < @ $+ .REDIRECT. > < $- > $#error $@ 5.1.1 $: "551 User has moved; please try " <$1@$2>
+
+
+
+
+######################################################################
+###  D: LookUpDomain -- search for domain in access database
+###
+###    Parameters:
+###            <$1> -- key (domain name)
+###            <$2> -- default (what to return if not found in db)
+###            <$3> -- mark (must be <(!|+) single-token>)
+###                    ! does lookup only with tag
+###                    + does lookup with and without tag
+###            <$4> -- passthru (additional data passed unchanged through)
+######################################################################
+
+SD
+R<$*> <$+> <$- $-> <$*>                $: < $(access $4:$1 $: ? $) > <$1> <$2> <$3 $4> <$5>
+R<?> <$+> <$+> <+ $-> <$*>     $: < $(access $1 $: ? $) > <$1> <$2> <+ $3> <$4>
+R<?> <[$+.$-]> <$+> <$- $-> <$*>       $@ $>D <[$1]> <$3> <$4 $5> <$6>
+R<?> <[$+::$-]> <$+> <$- $-> <$*>      $: $>D <[$1]> <$3> <$4 $5> <$6>
+R<?> <[$+:$-]> <$+> <$- $-> <$*>       $: $>D <[$1]> <$3> <$4 $5> <$6>
+R<?> <$+.$+> <$+> <$- $-> <$*> $@ $>D <$2> <$3> <$4 $5> <$6>
+R<?> <$+> <$+> <$- $-> <$*>    $@ <$2> <$5>
+R<$* <TMPF>> <$+> <$+> <$- $-> <$*>    $@ <<TMPF>> <$6>
+R<$*> <$+> <$+> <$- $-> <$*>   $@ <$1> <$6>
+
+######################################################################
+###  A: LookUpAddress -- search for host address in access database
+###
+###    Parameters:
+###            <$1> -- key (dot quadded host address)
+###            <$2> -- default (what to return if not found in db)
+###            <$3> -- mark (must be <(!|+) single-token>)
+###                    ! does lookup only with tag
+###                    + does lookup with and without tag
+###            <$4> -- passthru (additional data passed through)
+######################################################################
+
+SA
+R<$+> <$+> <$- $-> <$*>                $: < $(access $4:$1 $: ? $) > <$1> <$2> <$3 $4> <$5>
+R<?> <$+> <$+> <+ $-> <$*>     $: < $(access $1 $: ? $) > <$1> <$2> <+ $3> <$4>
+R<?> <$+::$-> <$+> <$- $-> <$*>                $@ $>A <$1> <$3> <$4 $5> <$6>
+R<?> <$+:$-> <$+> <$- $-> <$*>         $@ $>A <$1> <$3> <$4 $5> <$6>
+R<?> <$+.$-> <$+> <$- $-> <$*>         $@ $>A <$1> <$3> <$4 $5> <$6>
+R<?> <$+> <$+> <$- $-> <$*>    $@ <$2> <$5>
+R<$* <TMPF>> <$+> <$+> <$- $-> <$*>    $@ <<TMPF>> <$6>
+R<$*> <$+> <$+> <$- $-> <$*>   $@ <$1> <$6>
+
+######################################################################
+###  CanonAddr --      Convert an address into a standard form for
+###                    relay checking.  Route address syntax is
+###                    crudely converted into a %-hack address.
+###
+###    Parameters:
+###            $1 -- full recipient address
+###
+###    Returns:
+###            parsed address, not in source route form
+######################################################################
+
+SCanonAddr
+R$*                    $: $>Parse0 $>canonify $1       make domain canonical
+
+
+######################################################################
+###  ParseRecipient -- Strip off hosts in $=R as well as possibly
+###                    $* $=m or the access database.
+###                    Check user portion for host separators.
+###
+###    Parameters:
+###            $1 -- full recipient address
+###
+###    Returns:
+###            parsed, non-local-relaying address
+######################################################################
+
+SParseRecipient
+R$*                            $: <?> $>CanonAddr $1
+R<?> $* < @ $* . >             <?> $1 < @ $2 >                 strip trailing dots
+R<?> $- < @ $* >               $: <?> $(dequote $1 $) < @ $2 > dequote local part
+
+# if no $=O character, no host in the user portion, we are done
+R<?> $* $=O $* < @ $* >                $: <NO> $1 $2 $3 < @ $4>
+R<?> $*                                $@ $1
+
+
+R<NO> $* < @ $* $=R >          $: <RELAY> $1 < @ $2 $3 >
+R<NO> $* < @ $+ >              $: $>D <$2> <NO> <+ To> <$1 < @ $2 >>
+R<$+> <$+>                     $: <$1> $2
+
+
+
+R<RELAY> $* < @ $* >           $@ $>ParseRecipient $1
+R<$+> $*                       $@ $2
+
+
+######################################################################
+###  check_relay -- check hostname/address on SMTP startup
+######################################################################
+
+SLocal_check_relay
+Scheck_relay
+R$*                    $: $1 $| $>"Local_check_relay" $1
+R$* $| $* $| $#$*      $#$3
+R$* $| $* $| $*                $@ $>"Basic_check_relay" $1 $| $2
+
+SBasic_check_relay
+# check for deferred delivery mode
+R$*                    $: < $&{deliveryMode} > $1
+R< d > $*              $@ deferred
+R< $* > $*             $: $2
+
+R$+ $| $+              $: $>D < $1 > <?> <+ Connect> < $2 >
+R   $| $+              $: $>A < $1 > <?> <+ Connect> <>        empty client_name
+R<?> <$+>              $: $>A < $1 > <?> <+ Connect> <>        no: another lookup
+R<?> <$*>              $: OK                           found nothing
+R<$={Accept}> <$*>     $@ $1                           return value of lookup
+R<REJECT> <$*>         $#error $@ 5.7.1 $: "550 Access denied"
+R<DISCARD> <$*>                $#discard $: discard
+R<ERROR:$-.$-.$-:$+> <$*>      $#error $@ $1.$2.$3 $: $4
+R<ERROR:$+> <$*>               $#error $: $1
+R<$* <TMPF>> <$*>              $#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."
+R<$+> <$*>             $#error $: $1
+
+
+
+######################################################################
+###  check_mail -- check SMTP `MAIL FROM:' command argument
+######################################################################
+
+SLocal_check_mail
+Scheck_mail
+R$*                    $: $1 $| $>"Local_check_mail" $1
+R$* $| $#$*            $#$2
+R$* $| $*              $@ $>"Basic_check_mail" $1
+
+SBasic_check_mail
+# check for deferred delivery mode
+R$*                    $: < $&{deliveryMode} > $1
+R< d > $*              $@ deferred
+R< $* > $*             $: $2
+
+# authenticated?
+R$*                    $: $1 $| $>"tls_client" $&{verify} $| MAIL
+R$* $| $#$+            $#$2
+R$* $| $*              $: $1
+
+R<>                    $@ <OK>                 we MUST accept <> (RFC 1123)
+R$+                    $: <?> $1
+R<?><$+>               $: <@> <$1>
+R<?>$+                 $: <@> <$1>
+R$*                    $: $&{daemon_flags} $| $1
+R$* f $* $| <@> < $* @ $- >    $: < ? $&{client_name} > < $3 @ $4 >
+R$* u $* $| <@> < $* > $: <?> < $3 >
+R$* $| $*              $: $2
+# handle case of @localhost on address
+R<@> < $* @ localhost >        $: < ? $&{client_name} > < $1 @ localhost >
+R<@> < $* @ [127.0.0.1] >
+                       $: < ? $&{client_name} > < $1 @ [127.0.0.1] >
+R<@> < $* @ localhost.$m >
+                       $: < ? $&{client_name} > < $1 @ localhost.$m >
+R<@> < $* @ localhost.UUCP >
+                       $: < ? $&{client_name} > < $1 @ localhost.UUCP >
+R<@> $*                        $: $1                   no localhost as domain
+R<? $=w> $*            $: $2                   local client: ok
+R<? $+> <$+>           $#error $@ 5.5.4 $: "553 Real domain name required for sender address"
+R<?> $*                        $: $1
+R$*                    $: <?> $>CanonAddr $1           canonify sender address and mark it
+R<?> $* < @ $+ . >     <?> $1 < @ $2 >                 strip trailing dots
+# handle non-DNS hostnames (*.bitnet, *.decnet, *.uucp, etc)
+R<?> $* < @ $* $=P >   $: <OKR> $1 < @ $2 $3 >
+R<?> $* < @ $j >       $: <OKR> $1 < @ $j >
+R<?> $* < @ $+ >       $: <OKR> $1 < @ $2 >            ... unresolvable OK
+
+# check sender address: user@address, user@, address
+R<$+> $+ < @ $* >      $: @<$1> <$2 < @ $3 >> $| <F:$2@$3> <U:$2@> <D:$3>
+R<$+> $+               $: @<$1> <$2> $| <U:$2@>
+R@ <$+> <$*> $| <$+>   $: <@> <$1> <$2> $| $>SearchList <+ From> $| <$3> <>
+R<@> <$+> <$*> $| <$*> $: <$3> <$1> <$2>               reverse result
+# retransform for further use
+R<?> <$+> <$*>         $: <$1> $2      no match
+R<$+> <$+> <$*>                $: <$1> $3      relevant result, keep it
+
+# handle case of no @domain on address
+R<?> $*                        $: $&{daemon_flags} $| <?> $1
+R$* u $* $| <?> $*     $: <OKR> $3
+R$* $| $*              $: $2
+R<?> $*                        $: < ? $&{client_addr} > $1
+R<?> $*                        $@ <OKR>                        ...local unqualed ok
+R<? $+> $*             $#error $@ 5.5.4 $: "553 Domain name required for sender address " $&f
+                                                       ...remote is not
+# check results
+R<?> $*                        $: @ $1         mark address: nothing known about it
+R<$={ResOk}> $*                $@ <OKR>        domain ok: stop
+R<TEMP> $*             $#error $@ 4.1.8 $: "451 Domain of sender address " $&f " does not resolve"
+R<PERM> $*             $#error $@ 5.1.8 $: "553 Domain of sender address " $&f " does not exist"
+R<$={Accept}> $*       $# $1           accept from access map
+R<DISCARD> $*          $#discard $: discard
+R<REJECT> $*           $#error $@ 5.7.1 $: "550 Access denied"
+R<ERROR:$-.$-.$-:$+> $*                $#error $@ $1.$2.$3 $: $4
+R<ERROR:$+> $*         $#error $: $1
+R<<TMPF>> $*           $#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."
+R<$+> $*               $#error $: $1           error from access db
+
+######################################################################
+###  check_rcpt -- check SMTP `RCPT TO:' command argument
+######################################################################
+
+SLocal_check_rcpt
+Scheck_rcpt
+R$*                    $: $1 $| $>"Local_check_rcpt" $1
+R$* $| $#$*            $#$2
+R$* $| $*              $@ $>"Basic_check_rcpt" $1
+
+SBasic_check_rcpt
+# empty address?
+R<>                    $#error $@ nouser $: "553 User address required"
+R$@                    $#error $@ nouser $: "553 User address required"
+# check for deferred delivery mode
+R$*                    $: < $&{deliveryMode} > $1
+R< d > $*              $@ deferred
+R< $* > $*             $: $2
+
+
+######################################################################
+R$*                    $: $1 $| @ $>"Rcpt_ok" $1
+R$* $| @ $#TEMP $+     $: $1 $| T $2
+R$* $| @ $#$*          $#$2
+R$* $| @ RELAY         $@ RELAY
+R$* $| @ $*            $: O $| $>"Relay_ok" $1
+R$* $| T $+            $: T $2 $| $>"Relay_ok" $1
+R$* $| $#TEMP $+       $#error $2
+R$* $| $#$*            $#$2
+R$* $| RELAY           $@ RELAY
+R T $+ $| $*           $#error $1
+# anything else is bogus
+R$*                    $#error $@ 5.7.1 $: "550 Relaying denied"
+
+
+######################################################################
+### Rcpt_ok: is the recipient ok?
+######################################################################
+SRcpt_ok
+R$*                    $: $>ParseRecipient $1          strip relayable hosts
+
+
+
+# blacklist local users or any host from receiving mail
+R$*                    $: <?> $1
+R<?> $+ < @ $=w >      $: <> <$1 < @ $2 >> $| <F:$1@$2> <U:$1@> <D:$2>
+R<?> $+ < @ $* >       $: <> <$1 < @ $2 >> $| <F:$1@$2> <D:$2>
+R<?> $+                        $: <> <$1> $| <U:$1@>
+R<> <$*> $| <$+>       $: <@> <$1> $| $>SearchList <+ To> $| <$2> <>
+R<@> <$*> $| <$*>      $: <$2> <$1>            reverse result
+R<?> <$*>              $: @ $1         mark address as no match
+R<$={Accept}> <$*>     $: @ $2         mark address as no match
+
+R<REJECT> $*           $#error $@ 5.2.1 $: "550 Mailbox disabled for this recipient"
+R<DISCARD> $*          $#discard $: discard
+R<ERROR:$-.$-.$-:$+> $*                $#error $@ $1.$2.$3 $: $4
+R<ERROR:$+> $*         $#error $: $1
+R<<TMPF>> $*           $#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."
+R<$+> $*               $#error $: $1           error from access db
+R@ $*                  $1              remove mark
+
+# authenticated via TLS?
+R$*                    $: $1 $| $>RelayTLS     client authenticated?
+R$* $| $# $+           $# $2                   error/ok?
+R$* $| $*              $: $1                   no
+
+R$*                    $: $1 $| $>"Local_Relay_Auth" $&{auth_type}
+R$* $| $# $*           $# $2
+R$* $| NO              $: $1
+R$* $| $*              $: $1 $| $&{auth_type}
+R$* $|                 $: $1
+R$* $| $={TrustAuthMech}       $# RELAY
+R$* $| $*              $: $1
+# anything terminating locally is ok
+R$+ < @ $=w >          $@ RELAY
+R$+ < @ $* $=R >       $@ RELAY
+R$+ < @ $+ >           $: $>D <$2> <?> <+ To> <$1 < @ $2 >>
+R<RELAY> $*            $@ RELAY
+R<$* <TMPF>> $*                $#TEMP $@ 4.3.0 $: "451 Temporary system failure. Please try again later."
+R<$*> <$*>             $: $2
+
+
+
+# check for local user (i.e. unqualified address)
+R$*                    $: <?> $1
+R<?> $* < @ $+ >       $: <REMOTE> $1 < @ $2 >
+# local user is ok
+R<?> $+                        $@ RELAY
+R<$+> $*               $: $2
+
+######################################################################
+### Relay_ok: is the relay/sender ok?
+######################################################################
+SRelay_ok
+# anything originating locally is ok
+# check IP address
+R$*                    $: $&{client_addr}
+R$@                    $@ RELAY                originated locally
+R0                     $@ RELAY                originated locally
+R127.0.0.1             $@ RELAY                originated locally
+RIPv6:::1              $@ RELAY                originated locally
+R$=R $*                        $@ RELAY                relayable IP address
+R$*                    $: $>A <$1> <?> <+ Connect> <$1>
+R<RELAY> $*            $@ RELAY                relayable IP address
+
+R<<TMPF>> $*           $#TEMP $@ 4.3.0 $: "451 Temporary system failure. Please try again later."
+R<$*> <$*>             $: $2
+R$*                    $: [ $1 ]               put brackets around it...
+R$=w                   $@ RELAY                ... and see if it is local
+
+
+# check client name: first: did it resolve?
+R$*                    $: < $&{client_resolve} >
+R<TEMP>                        $#TEMP $@ 4.7.1 $: "450 Relaying temporarily denied. Cannot resolve PTR record for " $&{client_addr}
+R<FORGED>              $#error $@ 5.7.1 $: "550 Relaying denied. IP name possibly forged " $&{client_name}
+R<FAIL>                        $#error $@ 5.7.1 $: "550 Relaying denied. IP name lookup failed " $&{client_name}
+R$*                    $: <@> $&{client_name}
+# pass to name server to make hostname canonical
+R<@> $* $=P            $:<?>  $1 $2
+R<@> $+                        $:<?>  $[ $1 $]
+R$* .                  $1                      strip trailing dots
+R<?> $=w               $@ RELAY
+R<?> $* $=R                    $@ RELAY
+R<?> $*                        $: $>D <$1> <?> <+ Connect> <$1>
+R<RELAY> $*            $@ RELAY
+R<$* <TMPF>> $*                $#TEMP $@ 4.3.0 $: "451 Temporary system failure. Please try again later."
+R<$*> <$*>             $: $2
+
+
+######################################################################
+###  F: LookUpFull -- search for an entry in access database
+###
+###    lookup of full key (which should be an address) and
+###    variations if +detail exists: +* and without +detail
+###
+###    Parameters:
+###            <$1> -- key
+###            <$2> -- default (what to return if not found in db)
+###            <$3> -- mark (must be <(!|+) single-token>)
+###                    ! does lookup only with tag
+###                    + does lookup with and without tag
+###            <$4> -- passthru (additional data passed unchanged through)
+######################################################################
+
+SF
+R<$+> <$*> <$- $-> <$*>                $: <$(access $4:$1 $: ? $)> <$1> <$2> <$3 $4> <$5>
+R<?> <$+> <$*> <+ $-> <$*>     $: <$(access $1 $: ? $)> <$1> <$2> <+ $3> <$4>
+R<?> <$+ + $* @ $+> <$*> <$- $-> <$*>
+                       $: <$(access $6:$1+*@$3 $: ? $)> <$1+$2@$3> <$4> <$5 $6> <$7>
+R<?> <$+ + $* @ $+> <$*> <+ $-> <$*>
+                       $: <$(access $1+*@$3 $: ? $)> <$1+$2@$3> <$4> <+ $5> <$6>
+R<?> <$+ + $* @ $+> <$*> <$- $-> <$*>
+                       $: <$(access $6:$1@$3 $: ? $)> <$1+$2@$3> <$4> <$5 $6> <$7>
+R<?> <$+ + $* @ $+> <$*> <+ $-> <$*>
+                       $: <$(access $1@$3 $: ? $)> <$1+$2@$3> <$4> <+ $5> <$6>
+R<?> <$+> <$*> <$- $-> <$*>    $@ <$2> <$5>
+R<$+ <TMPF>> <$*> <$- $-> <$*> $@ <<TMPF>> <$5>
+R<$+> <$*> <$- $-> <$*>                $@ <$1> <$5>
+
+######################################################################
+###  E: LookUpExact -- search for an entry in access database
+###
+###    Parameters:
+###            <$1> -- key
+###            <$2> -- default (what to return if not found in db)
+###            <$3> -- mark (must be <(!|+) single-token>)
+###                    ! does lookup only with tag
+###                    + does lookup with and without tag
+###            <$4> -- passthru (additional data passed unchanged through)
+######################################################################
+
+SE
+R<$*> <$*> <$- $-> <$*>                $: <$(access $4:$1 $: ? $)> <$1> <$2> <$3 $4> <$5>
+R<?> <$+> <$*> <+ $-> <$*>     $: <$(access $1 $: ? $)> <$1> <$2> <+ $3> <$4>
+R<?> <$+> <$*> <$- $-> <$*>    $@ <$2> <$5>
+R<$+ <TMPF>> <$*> <$- $-> <$*> $@ <<TMPF>> <$5>
+R<$+> <$*> <$- $-> <$*>                $@ <$1> <$5>
+
+######################################################################
+###  U: LookUpUser -- search for an entry in access database
+###
+###    lookup of key (which should be a local part) and
+###    variations if +detail exists: +* and without +detail
+###
+###    Parameters:
+###            <$1> -- key (user@)
+###            <$2> -- default (what to return if not found in db)
+###            <$3> -- mark (must be <(!|+) single-token>)
+###                    ! does lookup only with tag
+###                    + does lookup with and without tag
+###            <$4> -- passthru (additional data passed unchanged through)
+######################################################################
+
+SU
+R<$+> <$*> <$- $-> <$*>                $: <$(access $4:$1 $: ? $)> <$1> <$2> <$3 $4> <$5>
+R<?> <$+> <$*> <+ $-> <$*>     $: <$(access $1 $: ? $)> <$1> <$2> <+ $3> <$4>
+R<?> <$+ + $* @> <$*> <$- $-> <$*>
+                       $: <$(access $5:$1+*@ $: ? $)> <$1+$2@> <$3> <$4 $5> <$6>
+R<?> <$+ + $* @> <$*> <+ $-> <$*>
+                       $: <$(access $1+*@ $: ? $)> <$1+$2@> <$3> <+ $4> <$5>
+R<?> <$+ + $* @> <$*> <$- $-> <$*>
+                       $: <$(access $5:$1@ $: ? $)> <$1+$2@> <$3> <$4 $5> <$6>
+R<?> <$+ + $* @> <$*> <+ $-> <$*>
+                       $: <$(access $1@ $: ? $)> <$1+$2@> <$3> <+ $4> <$5>
+R<?> <$+> <$*> <$- $-> <$*>    $@ <$2> <$5>
+R<$+ <TMPF>> <$*> <$- $-> <$*> $@ <<TMPF>> <$5>
+R<$+> <$*> <$- $-> <$*>                $@ <$1> <$5>
+
+######################################################################
+###  SearchList: search a list of items in the access map
+###    Parameters:
+###            <exact tag> $| <mark:address> <mark:address> ... <>
+###    where "exact" is either "+" or "!":
+###    <+ TAG> lookup with and w/o tag
+###    <! TAG> lookup with tag
+###    possible values for "mark" are:
+###            D: recursive host lookup (LookUpDomain)
+###            E: exact lookup, no modifications
+###            F: full lookup, try user+ext@domain and user@domain
+###            U: user lookup, try user+ext and user (input must have trailing @)
+###    return: <RHS of lookup> or <?> (not found)
+######################################################################
+
+# class with valid marks for SearchList
+C{src}E F D U 
+SSearchList
+# just call the ruleset with the name of the tag... nice trick...
+R<$+> $| <$={src}:$*> <$*>     $: <$1> $| <$4> $| $>$2 <$3> <?> <$1> <>
+R<$+> $| <> $| <?> <>          $@ <?>
+R<$+> $| <$+> $| <?> <>                $@ $>SearchList <$1> $| <$2>
+R<$+> $| <$*> $| <$+> <>       $@ <$3>
+R<$+> $| <$+>                  $@ <$2>
+
+
+######################################################################
+###  trust_auth: is user trusted to authenticate as someone else?
+###
+###    Parameters:
+###            $1: AUTH= parameter from MAIL command
+######################################################################
+
+SLocal_trust_auth
+Strust_auth
+R$*                    $: $&{auth_type} $| $1
+# required by RFC 2554 section 4.
+R$@ $| $*              $#error $@ 5.7.1 $: "550 not authenticated"
+R$* $| $&{auth_authen}         $@ identical
+R$* $| <$&{auth_authen}>       $@ identical
+R$* $| $*              $: $1 $| $>"Local_trust_auth" $2
+R$* $| $#$*            $#$2
+R$*                    $#error $@ 5.7.1 $: "550 " $&{auth_authen} " not allowed to act as " $&{auth_author}
+
+######################################################################
+###  Relay_Auth: allow relaying based on authentication?
+###
+###    Parameters:
+###            $1: ${auth_type}
+######################################################################
+SLocal_Relay_Auth
+
+######################################################################
+###  srv_features: which features to offer to a client?
+###    (done in server)
+######################################################################
+Ssrv_features
+R$*            $: $>D <$&{client_name}> <?> <! "Srv_Features"> <>
+R<?>$*         $: $>A <$&{client_addr}> <?> <! "Srv_Features"> <>
+R<?>$*         $: <$(access "Srv_Features": $: ? $)>
+R<?>$*         $@ OK
+R<$* <TMPF>>$* $#temp
+R<$+>$*                $# $1
+
+######################################################################
+###  try_tls: try to use STARTTLS?
+###    (done in client)
+######################################################################
+Stry_tls
+R$*            $: $>D <$&{server_name}> <?> <! "Try_TLS"> <>
+R<?>$*         $: $>A <$&{server_addr}> <?> <! "Try_TLS"> <>
+R<?>$*         $: <$(access "Try_TLS": $: ? $)>
+R<?>$*         $@ OK
+R<$* <TMPF>>$* $#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."
+R<NO>$*                $#error $@ 5.7.1 $: "550 do not try TLS with " $&{server_name} " ["$&{server_addr}"]"
+######################################################################
+###  tls_rcpt: is connection with server "good" enough?
+###    (done in client, per recipient)
+###
+###    Parameters:
+###            $1: recipient
+######################################################################
+Stls_rcpt
+R$*                    $: $(macro {TLS_Name} $@ $&{server_name} $) $1
+R$+                    $: <?> $>CanonAddr $1
+R<?> $+ < @ $+ . >     <?> $1 <@ $2 >
+R<?> $+ < @ $+ >       $: $1 <@ $2 > $| <F:$1@$2> <U:$1@> <D:$2> <E:>
+R<?> $+                        $: $1 $| <U:$1@> <E:>
+R$* $| $+      $: $1 $| $>SearchList <! "TLS_Rcpt"> $| $2 <>
+R$* $| <?>     $@ OK
+R$* $| <$* <TMPF>>     $#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."
+R$* $| <$+>    $@ $>"TLS_connection" $&{verify} $| <$2>
+
+######################################################################
+###  tls_client: is connection with client "good" enough?
+###    (done in server)
+###
+###    Parameters:
+###            ${verify} $| (MAIL|STARTTLS)
+######################################################################
+Stls_client
+R$*            $: $(macro {TLS_Name} $@ $&{server_name} $) $1
+R$* $| $*      $: $1 $| $>D <$&{client_name}> <?> <! "TLS_Clt"> <>
+R$* $| <?>$*   $: $1 $| $>A <$&{client_addr}> <?> <! "TLS_Clt"> <>
+R$* $| <?>$*   $: $1 $| <$(access "TLS_Clt": $: ? $)>
+R$* $| <$* <TMPF>>     $#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."
+R$*            $@ $>"TLS_connection" $1
+
+######################################################################
+###  tls_server: is connection with server "good" enough?
+###    (done in client)
+###
+###    Parameter:
+###            ${verify}
+######################################################################
+Stls_server
+R$*            $: $(macro {TLS_Name} $@ $&{server_name} $) $1
+R$*            $: $1 $| $>D <$&{server_name}> <?> <! "TLS_Srv"> <>
+R$* $| <?>$*   $: $1 $| $>A <$&{server_addr}> <?> <! "TLS_Srv"> <>
+R$* $| <?>$*   $: $1 $| <$(access "TLS_Srv": $: ? $)>
+R$* $| <$* <TMPF>>     $#error $@ 4.3.0 $: "451 Temporary system failure. Please try again later."
+R$*            $@ $>"TLS_connection" $1
+
+######################################################################
+###  TLS_connection: is TLS connection "good" enough?
+###
+###    Parameters:
+###            ${verify} $| <Requirement> [<>]
+###            Requirement: RHS from access map, may be ? for none.
+######################################################################
+STLS_connection
+R$* $| <$*>$*                  $: $1 $| <$2>
+# create the appropriate error codes
+R$* $| <PERM + $={tls} $*>     $: $1 $| <503:5.7.0> <$2 $3>
+R$* $| <TEMP + $={tls} $*>     $: $1 $| <403:4.7.0> <$2 $3>
+R$* $| <$={tls} $*>            $: $1 $| <403:4.7.0> <$2 $3>
+# deal with TLS handshake failures: abort
+RSOFTWARE $| <$-:$+> $*        $#error $@ $2 $: $1 " TLS handshake failed."
+RSOFTWARE $| $*                $#error $@ 4.7.0 $: "403 TLS handshake failed."
+R$* $| <$*> <VERIFY>           $: <$2> <VERIFY> <> $1
+R$* $| <$*> <VERIFY + $+>      $: <$2> <VERIFY> <$3> $1
+R$* $| <$*> <$={tls}:$->$*     $: <$2> <$3:$4> <> $1
+R$* $| <$*> <$={tls}:$- + $+>$*        $: <$2> <$3:$4> <$5> $1
+R$* $| $*                      $@ OK
+# authentication required: give appropriate error
+# other side did authenticate (via STARTTLS)
+R<$*><VERIFY> <> OK            $@ OK
+R<$*><VERIFY> <$+> OK          $: <$1> <REQ:0> <$2>
+R<$*><VERIFY:$-> <$*> OK       $: <$1> <REQ:$2> <$3>
+R<$*><ENCR:$-> <$*> $*         $: <$1> <REQ:$2> <$3>
+R<$-:$+><VERIFY $*> <$*>       $#error $@ $2 $: $1 " authentication required"
+R<$-:$+><VERIFY $*> <$*> FAIL  $#error $@ $2 $: $1 " authentication failed"
+R<$-:$+><VERIFY $*> <$*> NO    $#error $@ $2 $: $1 " not authenticated"
+R<$-:$+><VERIFY $*> <$*> NOT   $#error $@ $2 $: $1 " no authentication requested"
+R<$-:$+><VERIFY $*> <$*> NONE  $#error $@ $2 $: $1 " other side does not support STARTTLS"
+R<$-:$+><VERIFY $*> <$*> $+    $#error $@ $2 $: $1 " authentication failure " $4
+R<$*><REQ:$-> <$*>             $: <$1> <REQ:$2> <$3> $>max $&{cipher_bits} : $&{auth_ssf}
+R<$*><REQ:$-> <$*> $-          $: <$1> <$2:$4> <$3> $(arith l $@ $4 $@ $2 $)
+R<$-:$+><$-:$-> <$*> TRUE      $#error $@ $2 $: $1 " encryption too weak " $4 " less than " $3
+R<$-:$+><$-:$-> <$*> $*                $: <$1:$2 ++ $5>
+R<$-:$+ ++ >                   $@ OK
+R<$-:$+ ++ $+ >                        $: <$1:$2> <$3>
+R<$-:$+> < $+ ++ $+ >          <$1:$2> <$3> <$4>
+R<$-:$+> $+                    $@ $>"TLS_req" $3 $| <$1:$2>
+
+######################################################################
+###  TLS_req: check additional TLS requirements
+###
+###    Parameters: [<list> <of> <req>] $| <$-:$+>
+###            $-: SMTP reply code
+###            $+: Enhanced Status Code
+######################################################################
+STLS_req
+R $| $+                $@ OK
+R<CN> $* $| <$+>               $: <CN:$&{TLS_Name}> $1 $| <$2>
+R<CN:$&{cn_subject}> $* $| <$+>                $@ $>"TLS_req" $1 $| <$2>
+R<CN:$+> $* $| <$-:$+> $#error $@ $4 $: $3 " CN " $&{cn_subject} " does not match " $1
+R<CS:$&{cert_subject}> $* $| <$+>      $@ $>"TLS_req" $1 $| <$2>
+R<CS:$+> $* $| <$-:$+> $#error $@ $4 $: $3 " Cert Subject " $&{cert_subject} " does not match " $1
+R<CI:$&{cert_issuer}> $* $| <$+>       $@ $>"TLS_req" $1 $| <$2>
+R<CI:$+> $* $| <$-:$+> $#error $@ $4 $: $3 " Cert Issuer " $&{cert_issuer} " does not match " $1
+ROK                    $@ OK
+
+######################################################################
+###  max: return the maximum of two values separated by :
+###
+###    Parameters: [$-]:[$-]
+######################################################################
+Smax
+R:             $: 0
+R:$-           $: $1
+R$-:           $: $1
+R$-:$-         $: $(arith l $@ $1 $@ $2 $) : $1 : $2
+RTRUE:$-:$-    $: $2
+R$-:$-:$-      $: $2
+
+
+######################################################################
+###  RelayTLS: allow relaying based on TLS authentication
+###
+###    Parameters:
+###            none
+######################################################################
+SRelayTLS
+# authenticated?
+R$*                    $: <?> $&{verify}
+R<?> OK                        $: OK           authenticated: continue
+R<?> $*                        $@ NO           not authenticated
+R$*                    $: $&{cert_issuer}
+R$+                    $: $(access CERTISSUER:$1 $)
+RRELAY                 $# RELAY
+RSUBJECT               $: <@> $&{cert_subject}
+R<@> $+                        $: <@> $(access CERTSUBJECT:$1 $)
+R<@> RELAY             $# RELAY
+R$*                    $: NO
+
+######################################################################
+###  authinfo: lookup authinfo in the access map
+###
+###    Parameters:
+###            $1: {server_name}
+###            $2: {server_addr}
+######################################################################
+Sauthinfo
+R$*            $: $1 $| $>D <$&{server_name}> <?> <! AuthInfo> <>
+R$* $| <?>$*   $: $1 $| $>A <$&{server_addr}> <?> <! AuthInfo> <>
+R$* $| <?>$*   $: $1 $| <$(access AuthInfo: $: ? $)> <>
+R$* $| <?>$*   $@ no                           no authinfo available
+R$* $| <$*> <> $# $2
+
+#\f
+######################################################################
+######################################################################
+#####
+#####                  MAIL FILTER DEFINITIONS
+#####
+######################################################################
+######################################################################
+
+#\f
+######################################################################
+######################################################################
+#####
+#####                  MAILER DEFINITIONS
+#####
+######################################################################
+######################################################################
+
+#####################################
+###   SMTP Mailer specification   ###
+#####################################
+
+#####  $Id: alpha-sendmail.cf,v 1.3 2005/06/03 13:59:40 alk Exp $  #####
+
+#
+#  common sender and masquerading recipient rewriting
+#
+SMasqSMTP
+R$* < @ $* > $*                $@ $1 < @ $2 > $3               already fully qualified
+R$+                    $@ $1 < @ *LOCAL* >             add local qualification
+
+#
+#  convert pseudo-domain addresses to real domain addresses
+#
+SPseudoToReal
+
+# pass <route-addr>s through
+R< @ $+ > $*           $@ < @ $1 > $2                  resolve <route-addr>
+
+# output fake domains as user%fake@relay
+
+# do UUCP heuristics; note that these are shared with UUCP mailers
+R$+ < @ $+ .UUCP. >    $: < $2 ! > $1                  convert to UUCP form
+R$+ < @ $* > $*                $@ $1 < @ $2 > $3               not UUCP form
+
+# leave these in .UUCP form to avoid further tampering
+R< $&h ! > $- ! $+     $@ $2 < @ $1 .UUCP. >
+R< $&h ! > $-.$+ ! $+  $@ $3 < @ $1.$2 >
+R< $&h ! > $+          $@ $1 < @ $&h .UUCP. >
+R< $+ ! > $+           $: $1 ! $2 < @ $Y >             use UUCP_RELAY
+R$+ < @ $~[ $* : $+ >  $@ $1 < @ $4 >                  strip mailer: part
+R$+ < @ >              $: $1 < @ *LOCAL* >             if no UUCP_RELAY
+
+
+#
+#  envelope sender rewriting
+#
+SEnvFromSMTP
+R$+                    $: $>PseudoToReal $1            sender/recipient common
+R$* :; <@>             $@                              list:; special case
+R$*                    $: $>MasqSMTP $1                qualify unqual'ed names
+R$+                    $: $>MasqEnv $1                 do masquerading
+
+
+#
+#  envelope recipient rewriting --
+#  also header recipient if not masquerading recipients
+#
+SEnvToSMTP
+R$+                    $: $>PseudoToReal $1            sender/recipient common
+R$+                    $: $>MasqSMTP $1                qualify unqual'ed names
+R$* < @ *LOCAL* > $*   $: $1 < @ $j . > $2
+
+#
+#  header sender and masquerading header recipient rewriting
+#
+SHdrFromSMTP
+R$+                    $: $>PseudoToReal $1            sender/recipient common
+R:; <@>                        $@                              list:; special case
+
+# do special header rewriting
+R$* <@> $*             $@ $1 <@> $2                    pass null host through
+R< @ $* > $*           $@ < @ $1 > $2                  pass route-addr through
+R$*                    $: $>MasqSMTP $1                qualify unqual'ed names
+R$+                    $: $>MasqHdr $1                 do masquerading
+
+
+#
+#  relay mailer header masquerading recipient rewriting
+#
+SMasqRelay
+R$+                    $: $>MasqSMTP $1
+R$+                    $: $>MasqHdr $1
+
+Msmtp,         P=[IPC], F=mDFMuX, S=EnvFromSMTP/HdrFromSMTP, R=EnvToSMTP, E=\r\n, L=990,
+               T=DNS/RFC822/SMTP,
+               A=TCP $h
+Mesmtp,                P=[IPC], F=mDFMuXa, S=EnvFromSMTP/HdrFromSMTP, R=EnvToSMTP, E=\r\n, L=990,
+               T=DNS/RFC822/SMTP,
+               A=TCP $h
+Msmtp8,                P=[IPC], F=mDFMuX8, S=EnvFromSMTP/HdrFromSMTP, R=EnvToSMTP, E=\r\n, L=990,
+               T=DNS/RFC822/SMTP,
+               A=TCP $h
+Mdsmtp,                P=[IPC], F=mDFMuXa%, S=EnvFromSMTP/HdrFromSMTP, R=EnvToSMTP, E=\r\n, L=990,
+               T=DNS/RFC822/SMTP,
+               A=TCP $h
+Mrelay,                P=[IPC], F=mDFMuXa8, S=EnvFromSMTP/HdrFromSMTP, R=MasqSMTP, E=\r\n, L=2040,
+               T=DNS/RFC822/SMTP,
+               A=TCP $h
+
+
+######################*****##############
+###   PROCMAIL Mailer specification   ###
+##################*****##################
+
+#####  $Id: alpha-sendmail.cf,v 1.3 2005/06/03 13:59:40 alk Exp $  #####
+
+Mprocmail,     P=/usr/bin/procmail, F=DFMSPhnu9, S=EnvFromSMTP/HdrFromSMTP, R=EnvToSMTP/HdrFromSMTP,
+               T=DNS/RFC822/X-Unix,
+               A=procmail -Y -m $h $f $u
+
+
+##################################################
+###   Local and Program Mailer specification   ###
+##################################################
+
+#####  $Id: alpha-sendmail.cf,v 1.3 2005/06/03 13:59:40 alk Exp $  #####
+
+#
+#  Envelope sender rewriting
+#
+SEnvFromL
+R<@>                   $n                      errors to mailer-daemon
+R@ <@ $*>              $n                      temporarily bypass Sun bogosity
+R$+                    $: $>AddDomain $1       add local domain if needed
+R$*                    $: $>MasqEnv $1         do masquerading
+
+#
+#  Envelope recipient rewriting
+#
+SEnvToL
+R$+ < @ $* >           $: $1                   strip host part
+
+#
+#  Header sender rewriting
+#
+SHdrFromL
+R<@>                   $n                      errors to mailer-daemon
+R@ <@ $*>              $n                      temporarily bypass Sun bogosity
+R$+                    $: $>AddDomain $1       add local domain if needed
+R$*                    $: $>MasqHdr $1         do masquerading
+
+#
+#  Header recipient rewriting
+#
+SHdrToL
+R$+                    $: $>AddDomain $1       add local domain if needed
+R$* < @ *LOCAL* > $*   $: $1 < @ $j . > $2
+
+#
+#  Common code to add local domain name (only if always-add-domain)
+#
+SAddDomain
+R$* < @ $* > $*        $@ $1 < @ $2 > $3       already fully qualified
+
+R$+                    $@ $1 < @ *LOCAL* >     add local qualification
+
+Mlocal,                P=/usr/bin/procmail, F=lsDFMAw5:/|@qSPfhn9, S=EnvFromL/HdrFromL, R=EnvToL/HdrToL,
+               T=DNS/RFC822/X-Unix,
+               A=procmail -t -Y -a $h -d $u
+Mprog,         P=/usr/sbin/smrsh, F=lsDFMoqeu9, S=EnvFromL/HdrFromL, R=EnvToL/HdrToL, D=$z:/,
+               T=X-Unix/X-Unix/X-Unix,
+               A=smrsh -c $u
+
diff --git a/sendmail.mc b/sendmail.mc
new file mode 100755 (executable)
index 0000000..ded90e7
--- /dev/null
@@ -0,0 +1,153 @@
+divert(-1)dnl
+dnl #
+dnl # This is the sendmail macro config file for m4. If you make changes to
+dnl # /etc/mail/sendmail.mc, you will need to regenerate the
+dnl # /etc/mail/sendmail.cf file by confirming that the sendmail-cf package is
+dnl # installed and then performing a
+dnl #
+dnl #     make -C /etc/mail
+dnl #
+include(`/usr/share/sendmail-cf/m4/cf.m4')dnl
+VERSIONID(`setup for Red Hat Linux')dnl
+OSTYPE(`linux')dnl
+dnl #
+dnl # default logging level is 9, you might want to set it higher to
+dnl # debug the configuration
+dnl #
+dnl define(`confLOG_LEVEL', `9')dnl
+dnl #
+dnl # Uncomment and edit the following line if your outgoing mail needs to
+dnl # be sent out through an external mail server:
+dnl #
+dnl define(`SMART_HOST',`smtp.your.provider')
+dnl #
+define(`confDEF_USER_ID',``8:12'')dnl
+dnl define(`confAUTO_REBUILD')dnl
+define(`confTO_CONNECT', `1m')dnl
+define(`confTRY_NULL_MX_LIST',true)dnl
+define(`confDONT_PROBE_INTERFACES',true)dnl
+define(`PROCMAIL_MAILER_PATH',`/usr/bin/procmail')dnl
+define(`ALIAS_FILE', `/etc/aliases')dnl
+define(`STATUS_FILE', `/var/log/mail/statistics')dnl
+define(`UUCP_MAILER_MAX', `2000000')dnl
+define(`confUSERDB_SPEC', `/etc/mail/userdb.db')dnl
+define(`confPRIVACY_FLAGS', `authwarnings,novrfy,noexpn,restrictqrun')dnl
+define(`confAUTH_OPTIONS', `A')dnl
+dnl #
+dnl # The following allows relaying if the user authenticates, and disallows
+dnl # plaintext authentication (PLAIN/LOGIN) on non-TLS links
+dnl #
+dnl define(`confAUTH_OPTIONS', `A p')dnl
+dnl # 
+dnl # PLAIN is the preferred plaintext authentication method and used by
+dnl # Mozilla Mail and Evolution, though Outlook Express and other MUAs do
+dnl # use LOGIN. Other mechanisms should be used if the connection is not
+dnl # guaranteed secure.
+dnl # Please remember that saslauthd needs to be running for AUTH. 
+dnl #
+dnl TRUST_AUTH_MECH(`EXTERNAL DIGEST-MD5 CRAM-MD5 LOGIN PLAIN')dnl
+dnl define(`confAUTH_MECHANISMS', `EXTERNAL GSSAPI DIGEST-MD5 CRAM-MD5 LOGIN PLAIN')dnl
+dnl #
+dnl # Rudimentary information on creating certificates for sendmail TLS:
+dnl #     make -C /usr/share/ssl/certs usage
+dnl # or use the included makecert.sh script 
+dnl #
+define(`CERT_DIR',`/etc/mail/certs')
+define(`confCACERT_PATH',`CERT_DIR')
+define(`confCACERT',`CERT_DIR/cacert.pem')
+define(`confSERVER_CERT',`CERT_DIR/cert.pem')
+define(`confSERVER_KEY',`CERT_DIR/key.pem')
+define(`confCLIENT_CERT',`CERT_DIR/cert.pem')
+define(`confCLIENT_KEY',`CERT_DIR/key.pem')
+dnl #
+dnl # This allows sendmail to use a keyfile that is shared with OpenLDAP's
+dnl # slapd, which requires the file to be readble by group ldap
+dnl #
+dnl define(`confDONT_BLAME_SENDMAIL',`groupreadablekeyfile')dnl
+dnl #
+dnl define(`confTO_QUEUEWARN', `4h')dnl
+dnl define(`confTO_QUEUERETURN', `5d')dnl
+define(`confQUEUE_LA', `60000')dnl
+define(`confREFUSE_LA', `60000')dnl
+define(`confTO_IDENT', `0')dnl
+dnl FEATURE(delay_checks)dnl
+FEATURE(`no_default_msa',`dnl')dnl
+FEATURE(`smrsh',`/usr/sbin/smrsh')dnl
+FEATURE(`mailertable',`hash -o /etc/mail/mailertable.db')dnl
+FEATURE(`virtusertable',`hash -o /etc/mail/virtusertable.db')dnl
+FEATURE(redirect)dnl
+FEATURE(always_add_domain)dnl
+FEATURE(use_cw_file)dnl
+FEATURE(use_ct_file)dnl
+dnl #
+dnl # The -t option will retry delivery if e.g. the user runs over his quota.
+dnl #
+FEATURE(local_procmail,`',`procmail -t -Y -a $h -d $u')dnl
+FEATURE(`access_db',`hash -T<TMPF> -o /etc/mail/access.db')dnl
+FEATURE(`blacklist_recipients')dnl
+dnl EXPOSED_USER(`root')dnl
+dnl #
+dnl # The following causes sendmail to only listen on the IPv4 loopback address
+dnl # 127.0.0.1 and not on any other network devices. Remove the loopback
+dnl # address restriction to accept email from the internet or intranet.
+dnl #
+DAEMON_OPTIONS(`Port=smtp,Addr=127.0.0.1, Name=MTA')dnl
+dnl #
+dnl # The following causes sendmail to additionally listen to port 587 for
+dnl # mail from MUAs that authenticate. Roaming users who can't reach their
+dnl # preferred sendmail daemon due to port 25 being blocked or redirected find
+dnl # this useful.
+dnl #
+dnl DAEMON_OPTIONS(`Port=submission, Name=MSA, M=Ea')dnl
+dnl #
+dnl # The following causes sendmail to additionally listen to port 465, but
+dnl # starting immediately in TLS mode upon connecting. Port 25 or 587 followed
+dnl # by STARTTLS is preferred, but roaming clients using Outlook Express can't
+dnl # do STARTTLS on ports other than 25. Mozilla Mail can ONLY use STARTTLS
+dnl # and doesn't support the deprecated smtps; Evolution <1.1.1 uses smtps
+dnl # when SSL is enabled-- STARTTLS support is available in version 1.1.1.
+dnl #
+dnl # For this to work your OpenSSL certificates must be configured.
+dnl #
+dnl DAEMON_OPTIONS(`Port=smtps, Name=TLSMTA, M=s')dnl
+dnl #
+dnl # The following causes sendmail to additionally listen on the IPv6 loopback
+dnl # device. Remove the loopback address restriction listen to the network.
+dnl #
+dnl DAEMON_OPTIONS(`port=smtp,Addr=::1, Name=MTA-v6, Family=inet6')dnl
+dnl #
+dnl # enable both ipv6 and ipv4 in sendmail:
+dnl #
+dnl DAEMON_OPTIONS(`Name=MTA-v4, Family=inet, Name=MTA-v6, Family=inet6')
+dnl #
+dnl # We strongly recommend not accepting unresolvable domains if you want to
+dnl # protect yourself from spam. However, the laptop and users on computers
+dnl # that do not have 24x7 DNS do need this.
+dnl #
+FEATURE(`accept_unresolvable_domains')dnl
+dnl #
+dnl FEATURE(`relay_based_on_MX')dnl
+dnl # 
+dnl # Also accept email sent to "localhost.localdomain" as local email.
+dnl # 
+LOCAL_DOMAIN(`localhost.localdomain')dnl
+dnl #
+dnl # The following example makes mail from this host and any additional
+dnl # specified domains appear to be sent from mydomain.com
+dnl #
+MASQUERADE_AS(`planet-lab.org')dnl
+dnl #
+dnl # masquerade not just the headers, but the envelope as well
+dnl #
+FEATURE(masquerade_envelope)dnl
+dnl #
+dnl # masquerade not just @mydomainalias.com, but @*.mydomainalias.com as well
+dnl #
+FEATURE(masquerade_entire_domain)dnl
+dnl #
+MASQUERADE_DOMAIN(localhost)dnl
+MASQUERADE_DOMAIN(localhost.localdomain)dnl
+dnl MASQUERADE_DOMAIN(mydomainalias.com)dnl
+dnl MASQUERADE_DOMAIN(mydomain.lan)dnl
+MAILER(smtp)dnl
+MAILER(procmail)dnl
diff --git a/slocate.cron b/slocate.cron
new file mode 100755 (executable)
index 0000000..e9d3f63
--- /dev/null
@@ -0,0 +1,3 @@
+#!/bin/sh
+renice +19 -p $$ >/dev/null 2>&1
+/usr/bin/updatedb -f "nfs,smbfs,ncpfs,proc,devpts" -e "/tmp,/var/tmp,/usr/tmp,/afs,/net,/vservers"
diff --git a/sshd_config b/sshd_config
new file mode 100755 (executable)
index 0000000..a65946a
--- /dev/null
@@ -0,0 +1,83 @@
+#Port 22
+Protocol 2
+#ListenAddress 0.0.0.0
+#ListenAddress ::
+
+# HostKey for protocol version 1
+#HostKey /etc/ssh/ssh_host_key
+# HostKeys for protocol version 2
+#HostKey /etc/ssh/ssh_host_rsa_key
+#HostKey /etc/ssh/ssh_host_dsa_key
+
+# Lifetime and size of ephemeral version 1 server key
+#KeyRegenerationInterval 3600
+#ServerKeyBits 768
+
+# Logging
+#obsoletes QuietMode and FascistLogging
+#SyslogFacility AUTH
+SyslogFacility AUTHPRIV
+#LogLevel INFO
+
+# Authentication:
+
+#LoginGraceTime 120
+PermitRootLogin without-password
+#StrictModes yes
+
+RSAAuthentication yes
+#PubkeyAuthentication yes
+#AuthorizedKeysFile    .ssh/authorized_keys
+
+# rhosts authentication should not be used
+#RhostsAuthentication no
+# Don't read the user's ~/.rhosts and ~/.shosts files
+#IgnoreRhosts yes
+# For this to work you will also need host keys in /etc/ssh/ssh_known_hosts
+#RhostsRSAAuthentication no
+# similar for protocol version 2
+#HostbasedAuthentication no
+# Change to yes if you don't trust ~/.ssh/known_hosts for
+# RhostsRSAAuthentication and HostbasedAuthentication
+#IgnoreUserKnownHosts no
+
+# To disable tunneled clear text passwords, change to no here!
+PasswordAuthentication no
+#PermitEmptyPasswords no
+
+# Change to no to disable s/key passwords
+#ChallengeResponseAuthentication yes
+
+# Kerberos options
+#KerberosAuthentication no
+#KerberosOrLocalPasswd yes
+#KerberosTicketCleanup yes
+
+#AFSTokenPassing no
+
+# Kerberos TGT Passing only works with the AFS kaserver
+#KerberosTgtPassing no
+
+# Set this to 'yes' to enable PAM keyboard-interactive authentication 
+# Warning: enabling this may bypass the setting of 'PasswordAuthentication'
+#PAMAuthenticationViaKbdInt no
+
+#X11Forwarding no
+X11Forwarding yes
+#X11DisplayOffset 10
+#X11UseLocalhost yes
+#PrintMotd yes
+#PrintLastLog yes
+#KeepAlive yes
+#UseLogin no
+#UsePrivilegeSeparation yes
+#PermitUserEnvironment no
+#Compression yes
+
+MaxStartups 10:30:60
+# no default banner path
+#Banner /some/path
+#VerifyReverseMapping no
+
+# override default of no subsystems
+Subsystem      sftp    /usr/libexec/openssh/sftp-server
diff --git a/sudoers b/sudoers
new file mode 100755 (executable)
index 0000000..eb51a40
--- /dev/null
+++ b/sudoers
@@ -0,0 +1,52 @@
+# -----------------------------------------------------------------
+# We're assuming that ssh authentication has already been used, this
+# is more risky than I'm comfortable with, but it saves the problem 
+# of managing a separate password file.
+# -----------------------------------------------------------------
+Defaults       !authenticate
+
+# -----------------------------------------------------------------
+# No surpise... root has universal access
+# -----------------------------------------------------------------
+root           ALL = (ALL) ALL
+
+# -----------------------------------------------------------------
+# ADMIN_CMDS are those available to PlanetLab administrators
+# -----------------------------------------------------------------
+Cmnd_Alias     ADMIN_CMDS =    /usr/local/planetlab/bin/pl-ps, \
+                               /usr/local/planetlab/bin/pl-catlogs, \
+                               /usr/local/planetlab/bin/pl-limitbw, \
+                               /usr/local/planetlab/bin/pl-kill, \
+                                /usr/local/planetlab/bin/pl-sanetop, \
+                                /usr/sbin/tcpdump, \
+                               /usr/local/planetlab/bin/tcpdumpkill, \
+                               /sbin/shutdown, \
+                               /usr/local/planetlab/bin/tc, \
+                                /etc/init.d/vserver-init, \
+                                /usr/local/planetlab/bin/NodeUpdate.py, \
+                                /usr/local/planetlab/bin/PlanetLabConf.py, \
+                                /usr/local/planetlab/bin/PlanetLabKeys.py, \
+                                /etc/init.d/ntpd, \
+                                /usr/sbin/ntpdate
+
+
+# -----------------------------------------------------------------
+# SITE_CMDS are those available to local site administrators
+# -----------------------------------------------------------------
+Cmnd_Alias     SITE_CMDS =     /usr/local/planetlab/bin/pl-ps, \
+                               /usr/local/planetlab/bin/pl-catlogs, \
+                               /usr/local/planetlab/bin/pl-limitbw, \
+                                /usr/sbin/tcpdump, \
+                               /sbin/shutdown, \
+                               /usr/bin/passwd -d site_admin, \
+                               /usr/bin/passwd site_admin
+
+# -----------------------------------------------------------------
+# PLADMINS -- accounts with admin privileges on all nodes
+# -----------------------------------------------------------------
+pl_admin       ALL = ADMIN_CMDS
+
+# -----------------------------------------------------------------
+# Site Admins -- accounts with admin privileges on the local nodes
+# -----------------------------------------------------------------
+site_admin     ALL = SITE_CMDS
diff --git a/sysctl.php b/sysctl.php
new file mode 100755 (executable)
index 0000000..e0120ed
--- /dev/null
@@ -0,0 +1,62 @@
+<?php
+//
+// /etc/sysctl.conf generator
+//
+// Mark Huang <mlhuang@cs.princeton.edu>
+// Copyright (C) 2006 The Trustees of Princeton University
+//
+// $Id$
+//
+
+// Get admin API handle
+require_once 'plc_api.php';
+global $adm;
+
+$ip_forward = 0;
+
+// Look up the node
+$nodenetworks = $adm->GetNodeNetworks(array($_SERVER['REMOTE_ADDR']));
+if (!empty($nodenetworks)) {
+  $nodes = $adm->GetNodes(array($nodenetworks[0]['node_id']));
+  if (!empty($nodes)) {
+    $node = $nodes[0];
+    $nodenetworks = $adm->GetNodeNetworks($node['nodenetwork_ids']);
+    foreach ($nodenetworks as $nodenetwork) {
+      // Nodes with proxy socket interfaces need to be able to forward
+      // between the fake proxy0 interface and the real interface.
+      if ($nodenetwork['method'] == 'proxy') {
+       $ip_forward = 1;
+       break;
+      }
+    }
+  }
+}
+
+?>
+
+# Kernel sysctl configuration file for Red Hat Linux
+#
+# For binary values, 0 is disabled, 1 is enabled.  See sysctl(8) and
+# sysctl.conf(5) for more details.
+
+# Controls IP packet forwarding
+net.ipv4.ip_forward = <?php echo $ip_forward; ?>
+
+# Controls source route verification
+net.ipv4.conf.default.rp_filter = 1
+
+# Controls the System Request debugging functionality of the kernel
+kernel.sysrq = 0
+
+# Controls whether core dumps will append the PID to the core filename.
+# Useful for debugging multi-threaded applications.
+kernel.core_uses_pid = 1
+
+# TCP window scaling and broken routers
+net.ipv4.tcp_moderate_rcvbuf=0
+net.ipv4.tcp_default_win_scale=0
+net.ipv4.tcp_window_scaling=0
+
+# Mark only out of window RST segments as INVALID. This setting, among
+# other things, allows data to be sent with SYN packets.
+net.ipv4.netfilter.ip_conntrack_tcp_be_liberal=1
diff --git a/yum.conf.php b/yum.conf.php
new file mode 100755 (executable)
index 0000000..8cc2b90
--- /dev/null
@@ -0,0 +1,73 @@
+<?php
+//
+// /etc/yum.conf for production nodes
+//
+// Mark Huang <mlhuang@cs.princeton.edu>
+// Copyright (C) 2004-2006 The Trustees of Princeton University
+//
+// $Id: yum.conf.php,v 1.3 2006/05/18 23:09:43 mlhuang Exp $
+//
+
+// For PLC_NAME and PLC_BOOT_HOST
+include('plc_config.php');
+
+$PLC_NAME = PLC_NAME;
+$BOOT_BASE = PLC_BOOT_HOST;
+
+$repos = array(array('FedoraCore2Base', 'Fedora Core 2 Base', 'stock-fc2'),
+              array('FedoraCore2Updates', 'Fedora Core 2 Updates', 'updates-fc2'),
+              array('ThirdParty', 'Third Party RPMS', '3rdparty'));
+
+if (isset($_REQUEST['alpha'])) {
+  $repos[] = array('PlanetLabAlpha', 'PlanetLab Alpha RPMS', 'planetlab-alpha');
+  $repos[] = array('FedoraCore2Testing', 'Fedora Core 2 Testing', 'testing-fc2');
+} elseif (isset($_REQUEST['beta'])) {
+  $repos[] = array('PlanetLabBeta', 'PlanetLab Beta RPMS', 'planetlab-beta');
+} elseif (isset($_REQUEST['rollout'])) {
+  $repos[] = array('PlanetLab', 'PlanetLab RPMS', 'planetlab-rollout');
+} else {
+  $repos[] = array('PlanetLab', 'PlanetLab RPMS', 'planetlab');
+}
+
+if (isset($_REQUEST['gpgcheck'])) {
+  $gpgcheck = $_REQUEST['gpgcheck'];
+} else {
+  $gpgcheck = 0;
+}
+
+echo <<<EOF
+[main]
+### for yum-2.4 in fc4 (this will be ignored by yum-2.0)
+### everything in here, do not scan /etc/yum.repos.d/
+reposdir=/dev/null
+cachedir=/var/cache/yum
+debuglevel=2
+logfile=/var/log/yum.log
+pkgpolicy=newest
+gpgcheck=$gpgcheck
+
+
+EOF;
+
+// Figure out which repositories we actually have on this
+// machine. MyPLC installations, for instance, generally only have
+// PlanetLab RPMS installed.
+foreach ($repos as $repo) {
+  $id = $repo[0];
+  $name = $repo[1] . " -- " . "$PLC_NAME Central";
+  $dir = "/install-rpms/" . $repo[2];
+  $baseurl = "http://$BOOT_BASE" . $dir . "/";
+
+  if (is_dir(realpath($_SERVER['DOCUMENT_ROOT'] . $dir))) {
+    echo <<<EOF
+[$id]
+name=$name
+baseurl=$baseurl
+gpgcheck=$gpgcheck
+
+
+EOF;
+  }
+}
+
+?>
\ No newline at end of file