<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Yet another web log &#187; Administration</title>
	<atom:link href="http://blog.philippheckel.com/category/administration/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.philippheckel.com</link>
	<description>Life, Linux and other things</description>
	<lastBuildDate>Thu, 17 Mar 2011 10:04:42 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>Altering old SVN revisions: removing confidental data from a Subversion repository</title>
		<link>http://blog.philippheckel.com/2011/02/01/altering-old-svn-revisions-removing-confidental-data-from-subversion-repository/</link>
		<comments>http://blog.philippheckel.com/2011/02/01/altering-old-svn-revisions-removing-confidental-data-from-subversion-repository/#comments</comments>
		<pubDate>Tue, 01 Feb 2011 11:26:44 +0000</pubDate>
		<dc:creator>Philipp C. Heckel</dc:creator>
				<category><![CDATA[Administration]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Security]]></category>
		<category><![CDATA[Subversion]]></category>
		<category><![CDATA[SVN]]></category>

		<guid isPermaLink="false">http://blog.philippheckel.com/?p=588</guid>
		<description><![CDATA[Version control systems like CVS or Subversion are designed for keeping track of the changes of a project and for having the possibility to revert to old revisions if something goes wrong. In contrast to regular relational databases, these systems are made only for adding new content to a repository, and not for removing data [...]]]></description>
			<content:encoded><![CDATA[<p>Version control systems like <a href="http://www.nongnu.org/cvs/">CVS</a> or <a href="http://subversion.apache.org/">Subversion</a> are designed for keeping track of the changes of a project and for having the possibility to revert to old revisions if something goes wrong. In contrast to regular relational databases, these systems are made only for adding new content to a repository, and not for removing data from it. In fact, deleting old content is <a href=" http://subversion.apache.org/faq.html#removal">not a built-in functionality</a> in SVN, and mostly requires removing entire revisions from the repository or even <a href="http://svnbook.red-bean.com/en/1.1/ch05s03.html#svn-ch-5-sect-3.1.3">creating a new one</a>. </p>
<p>But what happens if you <strong>accidentally commit a password</strong> or other sensitive information to a repository? This post explains <strong>how to remove this confidential data</strong> permanently from the repository by simply overwriting it in old revisions, i.e. without having to remove revisions or create a new repository.</p>
<p><span id="more-588"></span></p>
<hr />
<b>Contents</b></p>
<div class="toc">
<ol>
<li><a href="http://blog.philippheckel.com/2011/02/01/altering-old-svn-revisions-removing-confidental-data-from-subversion-repository/#Introduction">1. Introduction</a></p>
<ol>
<li><a href="http://blog.philippheckel.com/2011/02/01/altering-old-svn-revisions-removing-confidental-data-from-subversion-repository/#Disclaimer">1.1. Disclaimer</a></li>
<li><a href="http://blog.philippheckel.com/2011/02/01/altering-old-svn-revisions-removing-confidental-data-from-subversion-repository/#Requirements">1.2. Requirements</a></li>
<li><a href="http://blog.philippheckel.com/2011/02/01/altering-old-svn-revisions-removing-confidental-data-from-subversion-repository/#Example-Scenario">1.3. Example Scenario</a></li>
</ol>
</li>
<li><a href="http://blog.philippheckel.com/2011/02/01/altering-old-svn-revisions-removing-confidental-data-from-subversion-repository/#Local-machine-Identify-the-affected-revisions-in-the-working-copy">2. Local machine: Identify the affected revisions in the working copy</a>
<ol>
<li><a href="http://blog.philippheckel.com/2011/02/01/altering-old-svn-revisions-removing-confidental-data-from-subversion-repository/#Fix-and-commit-the-affected-file">2.1. Fix and commit the affected file</a></li>
<li><a href="http://blog.philippheckel.com/2011/02/01/altering-old-svn-revisions-removing-confidental-data-from-subversion-repository/#Identify-the-affected-file-versions-locally">2.2. Identify the affected file versions locally</a></li>
<li><a href="http://blog.philippheckel.com/2011/02/01/altering-old-svn-revisions-removing-confidental-data-from-subversion-repository/#Get-MD5-checksums-of-the-affected-versions">2.3. Get MD5 checksums of the affected versions</a></li>
</ol>
</li>
<li><a href="http://blog.philippheckel.com/2011/02/01/altering-old-svn-revisions-removing-confidental-data-from-subversion-repository/#SVN-repository-Correct-the-affected-files">3. SVN repository: Correct the affected files</a>
<ol>
<li><a href="http://blog.philippheckel.com/2011/02/01/altering-old-svn-revisions-removing-confidental-data-from-subversion-repository/#Make-a-repository-backup">3.1. Make a repository backup</a></li>
<li><a href="http://blog.philippheckel.com/2011/02/01/altering-old-svn-revisions-removing-confidental-data-from-subversion-repository/#Verify-affected-versions">3.2. Verify affected versions</a></li>
<li><a href="http://blog.philippheckel.com/2011/02/01/altering-old-svn-revisions-removing-confidental-data-from-subversion-repository/#Replace-the-password-and-checksums">3.3. Replace the password and checksums</a></li>
</ol>
</li>
<li><a href="http://blog.philippheckel.com/2011/02/01/altering-old-svn-revisions-removing-confidental-data-from-subversion-repository/#Test-locally">4. Test locally</a></li>
<li><a href="http://blog.philippheckel.com/2011/02/01/altering-old-svn-revisions-removing-confidental-data-from-subversion-repository/#Bash-history-cleanup">5. Bash history cleanup</a></li>
</ol>
</div>
<hr />
<h3 id="Introduction" >1. Introduction</h3>
<h4 id="Disclaimer" >1.1. Disclaimer</h4>
<p>The following actions might lead to data loss. I am not responsible for anything that goes wrong because of my description. </p>
<h4 id="Requirements" >1.2. Requirements</h4>
<p>It is absolutely necessary to have <strong>root access to the SVN respository</strong>. That is not only through the svnadmin command, but full command line access to the files, particularly to the &#8220;repos&#8221; directory.</p>
<p>If you do not have root access to the repository, you cannot remove any data from the repository! In that case, contact your SVN administrator.</p>
<h4 id="Example-Scenario" >1.3. Example Scenario</h4>
<p>For this example, let&#8217;s assume you accidentally committed the file <strong>config.cfg</strong> with a plain text password <em style="color: red">123secret</em> a while ago (in <strong>revision 12</strong>). The repository is currently at <strong>revision 25</strong> and you just realized that the password was in there all the time:</p>

<div class="wp_syntax"><div class="code"><pre class="config" style="font-family:monospace;"># Config file &quot;config.cfg&quot;
username = someone
password = 123secret
...</pre></div></div>

<h3 id="Local-machine-Identify-the-affected-revisions-in-the-working-copy" >2. Local machine: Identify the affected revisions in the working copy</h3>
<h4 id="Fix-and-commit-the-affected-file" >2.1. Fix and commit the affected file</h4>
<p>The following commands are performed on <strong>your local machine</strong> within the working copy of the project, i.e. on the client machine.</p>
<p>Before we start tinkering and forging the SVN history and its repository, first fix the affected file and commit a new revision to the repository. In most cases, people are not going to look in old revisions of a config file, so the faster you commit a new version, the less likely it is that someone sees it!</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">$ <span style="color: #7a0874; font-weight: bold;">cd</span> ~<span style="color: #000000; font-weight: bold;">/</span>Dev<span style="color: #000000; font-weight: bold;">/</span>yourproject
$ <span style="color: #c20cb9; font-weight: bold;">vi</span> config.cfg
<span style="color: #666666; font-style: italic;"># Change password to something else</span>
$ <span style="color: #c20cb9; font-weight: bold;">svn</span> commit <span style="color: #660033;">-m</span> <span style="color: #ff0000;">&quot;config update&quot;</span>
...
Transmitting <span style="color: #c20cb9; font-weight: bold;">file</span> data .
Committed revision <span style="color: #000000;">26</span>.</pre></div></div>

<h4 id="Identify-the-affected-file-versions-locally" >2.2. Identify the affected file versions locally</h4>
<p>In most cases you will probably realize right away that you just committed something confidential to the SVN repository. In this case, you only have to fix one single version of that file and is pretty clear which revision is affected.</p>
<p>In other cases, however, the affected file might be in the repository for many revisions before you realize it. If this is the case, there might be multiple revisions of the file in the repository and each of these versions needs to be fixed. To identify the possibly affected versions of the file, you can peak into the logs:</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">$ <span style="color: #c20cb9; font-weight: bold;">svn</span> log config.cfg
<span style="color: #660033;">------------------------------------------------------------------------</span>
r22 <span style="color: #000000; font-weight: bold;">|</span> someone <span style="color: #000000; font-weight: bold;">|</span> <span style="color: #000000;">2011</span>-01-<span style="color: #000000;">25</span> 01:<span style="color: #000000;">36</span>:<span style="color: #000000;">12</span> +0100 <span style="color: #7a0874; font-weight: bold;">&#40;</span>Tue, <span style="color: #000000;">25</span> Jan <span style="color: #000000;">2011</span><span style="color: #7a0874; font-weight: bold;">&#41;</span> <span style="color: #000000; font-weight: bold;">|</span> <span style="color: #000000;">1</span> line
&nbsp;
update xy config
<span style="color: #660033;">------------------------------------------------------------------------</span>
r12 <span style="color: #000000; font-weight: bold;">|</span> someone <span style="color: #000000; font-weight: bold;">|</span> <span style="color: #000000;">2011</span>-01-05 00:<span style="color: #000000;">45</span>:<span style="color: #000000;">19</span> +0100 <span style="color: #7a0874; font-weight: bold;">&#40;</span>Wed, 05 Jan <span style="color: #000000;">2011</span><span style="color: #7a0874; font-weight: bold;">&#41;</span> <span style="color: #000000; font-weight: bold;">|</span> <span style="color: #000000;">1</span> line
&nbsp;
added connection details to config
<span style="color: #660033;">------------------------------------------------------------------------</span>
...</pre></div></div>

<p>In this case, the file has been altered in the two <strong>revisions 12 and 22</strong>. Both <strong>might</strong> include the password and are stored in the repository, i.e. both potentially need to be corrected.</p>
<h4 id="Get-MD5-checksums-of-the-affected-versions" >2.3. Get MD5 checksums of the affected versions</h4>
<p>SVN ensures the integrity of its repository by saving MD5 checksums of all the files and its versions. Since it is now clear which revisions might be affected, you need to get the <em>current</em> checksums of these file versions and calculate checksums for the new <em>corrected</em> (&#8220;forged&#8221;) versions. In short, you need to do the following <strong>for each affected version</strong>:</p>
<ul>
<li>Retrieve the version and calculate its MD5 checksum</li>
<li>Make a copy of file, replace the confidential information with &#8220;x&#8221;s and calculate the MD5 checksum of the new file.</li>
<li>Remember or copy all the checksums and versions into a file.</li>
</ul>
<p>In this example, we&#8217;ll have to get the checksums for revisions 12 and 22 of the <em>config.cfg</em>-file. The code below only shows what to do for revision 22; revision 12 is analogue:</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #666666; font-style: italic;"># Get current checksum of revision 22</span>
$ <span style="color: #c20cb9; font-weight: bold;">svn</span> <span style="color: #660033;">--revision</span> <span style="color: #000000;">22</span> config.cfg
...
At revision <span style="color: #000000;">22</span>.
$ md5sum config.cfg
0e28c6c8342649c290400567130f657b  config.cfg
&nbsp;
<span style="color: #666666; font-style: italic;"># Correct the file and get new checksum</span>
$ <span style="color: #c20cb9; font-weight: bold;">cp</span> config.cfg <span style="color: #000000; font-weight: bold;">/</span>tmp<span style="color: #000000; font-weight: bold;">/</span>config.cfg-<span style="color: #000000;">22</span>
$ <span style="color: #c20cb9; font-weight: bold;">vi</span> <span style="color: #000000; font-weight: bold;">/</span>tmp<span style="color: #000000; font-weight: bold;">/</span>config.cfg-<span style="color: #000000;">22</span>
<span style="color: #666666; font-style: italic;"># Overwrite the password with &quot;xxxxxxxxx&quot; (same length as the old password!!)</span>
$ md5sum <span style="color: #000000; font-weight: bold;">/</span>tmp<span style="color: #000000; font-weight: bold;">/</span>config.cfg-<span style="color: #000000;">22</span>
459a78e2eae02b28f810f9fdebdc5b52  <span style="color: #000000; font-weight: bold;">/</span>tmp<span style="color: #000000; font-weight: bold;">/</span>config.cfg-<span style="color: #000000;">22</span>
&nbsp;
<span style="color: #666666; font-style: italic;"># Repeat this for revision 12</span></pre></div></div>

<h3 id="SVN-repository-Correct-the-affected-files" >3. SVN repository: Correct the affected files</h3>
<div style="border: 1px solid red; background: #fcc; padding: 5px; margin-top: 8px"><strong>Warning</strong>: This step can damage your repository, so make sure you backup as described in 3.1. before you change anything.</div>
<p>In this step, we finally start altering the repository. All the actions are performed on <strong>the server machine</strong> as <strong>root</strong> user inside the actual SVN repository directory, so be sure not to confuse it with you local machine.</p>
<h4 id="Make-a-repository-backup" >3.1. Make a repository backup</h4>
<p>Creating some sort of backup is crucial, since we are about to change the binary revision files of the Subversion repository. The easiest way to do this is to backup the whole repository folder of your project, e.g. /path/to/svn/repos/yourproject. However, if its total size is too big you can also choose to only backup the files identified in 3.2.</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #666666; font-style: italic;"># Make backup of project; Note the &quot;-a&quot; parameter to keep the permissions.</span>
$ <span style="color: #c20cb9; font-weight: bold;">mkdir</span> <span style="color: #000000; font-weight: bold;">/</span>backups
$ <span style="color: #c20cb9; font-weight: bold;">cp</span> <span style="color: #660033;">-a</span> <span style="color: #000000; font-weight: bold;">/</span>path<span style="color: #000000; font-weight: bold;">/</span>to<span style="color: #000000; font-weight: bold;">/</span>svn<span style="color: #000000; font-weight: bold;">/</span>repos<span style="color: #000000; font-weight: bold;">/</span>yourproject <span style="color: #000000; font-weight: bold;">/</span>backups</pre></div></div>

<h4 id="Verify-affected-versions" >3.2. Verify affected versions</h4>
<p>After the backup, we need to verify that we really need to change all the versions we identified earlier. To do that, navigate to the &#8220;revs&#8221; folder inside the repository and grep for the password:</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">$ <span style="color: #7a0874; font-weight: bold;">cd</span> <span style="color: #000000; font-weight: bold;">/</span>path<span style="color: #000000; font-weight: bold;">/</span>to<span style="color: #000000; font-weight: bold;">/</span>svn<span style="color: #000000; font-weight: bold;">/</span>repos<span style="color: #000000; font-weight: bold;">/</span>yourproject<span style="color: #000000; font-weight: bold;">/</span>db<span style="color: #000000; font-weight: bold;">/</span>revs<span style="color: #000000; font-weight: bold;">/</span><span style="color: #000000;">0</span>
$ <span style="color: #c20cb9; font-weight: bold;">grep</span> 123secret <span style="color: #000000; font-weight: bold;">*</span>
Binary <span style="color: #c20cb9; font-weight: bold;">file</span> <span style="color: #000000;">12</span> matches
Binary <span style="color: #c20cb9; font-weight: bold;">file</span> <span style="color: #000000;">22</span> matches</pre></div></div>

<p>The matching files are the revisions that contain the password, and hence also the files that need to be &#8220;corrected&#8221;. Note that sometimes not all the versions identified through the &#8220;svn log&#8221; command appear in this list. That is because when the file is simply moved and not changed or other parts of it were altered, its contents will not be stored in the SVN revision file.</p>
<h4 id="Replace-the-password-and-checksums" >3.3. Replace the password and checksums</h4>
<p>Since the SVN revision files are binary, we need a hex editor to edit them. Hence install hexedit, and then simply replace the password and checksums like identified before:</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">$ <span style="color: #c20cb9; font-weight: bold;">apt-get</span> <span style="color: #c20cb9; font-weight: bold;">install</span> hexedit
&nbsp;
$ hexedit <span style="color: #000000;">22</span>
<span style="color: #666666; font-style: italic;"># Hex editor opens the file for revision 22</span>
<span style="color: #666666; font-style: italic;"># Replace passwords and checksums</span>
&nbsp;
<span style="color: #666666; font-style: italic;"># Repeat this for revision 12</span></pre></div></div>

<p>Hexedit is not the easiest editor to use. So here is a step-by-step of what you need to do:</p>
<ul>
<li>Hit TAB, then CTRL-S to search</li>
<li>Enter the password <em style="color: red">123secret</em> and hit return</li>
<li>Overwrite the password with <em style="color: red">xxxxxxxxx</em> (same length!)</li>
<li>Hit CTRL-S, then &#8220;Y&#8221; to save</li>
<li>Repeat 1-4 for each occurance of the password.</li>
<li>Do the same for the old checksum &#8220;0e28c6c8342649c290400567130f657b&#8221;, and replace it with the new one &#8220;f85abfd8b63fa7ab68abc9364f2d339e&#8221;</li>
<li>Hit CTRL-X to quit</li>
<li>Repeat this for all affected revisions</li>
</ul>
<p>That&#8217;s the complete magic. If checked out, the revisions 12 and 22 (and of course also their succeeding versions) will show <em style="color: red">xxxxxxxxx</em> instead of the initially committed password.</p>
<h3 id="Test-locally" ">4. Test locally</h3>
<p>Now test locally if you can switch between revisions and every works without error messages:</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">$ <span style="color: #c20cb9; font-weight: bold;">svn</span> <span style="color: #660033;">--revision</span> <span style="color: #000000;">12</span> update
...
At revision <span style="color: #000000;">12</span>.
$ <span style="color: #c20cb9; font-weight: bold;">grep</span> password config.cfg
password = xxxxxxxxx</pre></div></div>

<p>If you did everything as the tutorial says, you shouldn&#8217;t get any errors. If you forgot to replace checksums or you changed something that you weren&#8217;t supposed to change in the SVN revision file, you might get an error like below. However, if that happens, you can always go back to your backup and try it again&#8230;</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">$ <span style="color: #c20cb9; font-weight: bold;">svn</span> <span style="color: #660033;">--revision</span> <span style="color: #000000;">12</span> update
<span style="color: #c20cb9; font-weight: bold;">svn</span>: Checksum mismatch <span style="color: #000000; font-weight: bold;">while</span> reading representation:
   expected:  f85abfd8b63fa7ab68abc9364f2d339e
     actual:  de6f581d115197baebc43c3975b9e396</pre></div></div>

<h3 id="Bash-history-cleanup" >5. Bash history cleanup</h3>
<p>In step 3.2. we typed the plain text password in the bash. As you might know, this leaves traces in the ~/.bash_history file. Delete them by opening the files and then by simply removing the according lines. Make sure that you <strong>do not use the search</strong> function of VIM, since that has a history on its own. If you do, delete the history of VIM in ~/.viminfo.</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">$ <span style="color: #c20cb9; font-weight: bold;">vi</span> ~<span style="color: #000000; font-weight: bold;">/</span>.bash_history
<span style="color: #666666; font-style: italic;"># Remove everything that contains the password</span>
<span style="color: #666666; font-style: italic;"># Do NOT use the search function, but search manually!</span></pre></div></div>

]]></content:encoded>
			<wfw:commentRss>http://blog.philippheckel.com/2011/02/01/altering-old-svn-revisions-removing-confidental-data-from-subversion-repository/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>WP-UN: WordPress version update notification with cron</title>
		<link>http://blog.philippheckel.com/2010/01/29/wp-un-wordpress-version-update-notification-with-cron/</link>
		<comments>http://blog.philippheckel.com/2010/01/29/wp-un-wordpress-version-update-notification-with-cron/#comments</comments>
		<pubDate>Fri, 29 Jan 2010 13:32:30 +0000</pubDate>
		<dc:creator>Philipp C. Heckel</dc:creator>
				<category><![CDATA[Administration]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[Security]]></category>
		<category><![CDATA[Cron]]></category>
		<category><![CDATA[Mail]]></category>
		<category><![CDATA[Postfix]]></category>
		<category><![CDATA[Scripts]]></category>
		<category><![CDATA[WordPress]]></category>

		<guid isPermaLink="false">http://blog.philippheckel.com/?p=164</guid>
		<description><![CDATA[WordPress is a very popular open-source blog software and is used widely throughout the Internet. However, with great success comes great attack potential: like any other wide spread open-source software, WordPress is target for frequent hacking attacks and spam-bots. All the more important is it to always update the distribution to the latest release. As [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://wordpress.org/">WordPress</a> is a very popular open-source blog software and is used widely throughout the Internet. However, with great success comes great attack potential: like any other wide spread open-source software, WordPress is target for frequent hacking attacks and spam-bots. All the more important is it to always update the distribution to the latest release.</p>
<p>As Debian/Ubuntu user, I am spoiled when it comes to update management: <em>apt-get</em> updates most of my software, and <em>apticron</em> notifies me when updates are available. For WordPress however, the packaged versions of Debian/Ubuntu are really old and less adjustable which unfortunately makes a manual installation inevitable. While there are several automated WordPress update mechanisms out there, I couldn&#8217;t find a simple notify-on-update tool.</p>
<p>This post introduces the <em>WordPress Update Notifier</em> (WP-UN), a simple script that frequently compares the installed WordPress version with the latest available one. If a new version is available, it sends an e-mail to a given address.</p>
<p><span id="more-164"></span></p>
<h3 id="toc-update">Update</h3>
<p><strong>February &#8217;11</strong>: I updated the script so that it now uses the WordPress API. If you want, you can still download the <a href="http://blog.philippheckel.com/uploads/2010/01/wp-un-0.1">old version of WP-UN</a>, but since wordpress.org changed their download mechanisms, it does not work any more. </p>
<h3 id="toc-requirements">Requirements</h3>
<p>WP-UN is compatible with <strong>WordPress 2.5-3.x</strong>. It needs a  <strong>local mail server</strong> such as <a href="http://www.sendmail.org/">Sendmail</a> or <a href="http://www.postfix.org/">Postfix</a> to deliver the notification e-mail. </p>
<h3 id="toc-download-installation">Download &amp; Installation</h3>
<p>Download the script, save it to your preferred location and make it executable:</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">$ <span style="color: #c20cb9; font-weight: bold;">wget</span> <span style="color: #660033;">-O</span> <span style="color: #000000; font-weight: bold;">/</span>usr<span style="color: #000000; font-weight: bold;">/</span>local<span style="color: #000000; font-weight: bold;">/</span>bin<span style="color: #000000; font-weight: bold;">/</span>wp-un \
          http:<span style="color: #000000; font-weight: bold;">//</span>blog.philippheckel.com<span style="color: #000000; font-weight: bold;">/</span>uploads<span style="color: #000000; font-weight: bold;">/</span><span style="color: #000000;">2010</span><span style="color: #000000; font-weight: bold;">/</span>01<span style="color: #000000; font-weight: bold;">/</span>wp-un
$ <span style="color: #c20cb9; font-weight: bold;">chmod</span> +x <span style="color: #000000; font-weight: bold;">/</span>usr<span style="color: #000000; font-weight: bold;">/</span>local<span style="color: #000000; font-weight: bold;">/</span>bin<span style="color: #000000; font-weight: bold;">/</span>wp-un</pre></div></div>

<p>That&#8217;s it for the installation. The script can now be called by simply running <em>wp-un</em>.</p>
<p><strong>Download</strong>: <a href="http://blog.philippheckel.com/uploads/2010/01/wp-un">WP-UN 0.2, February 2011</a><br />
<strong>Old version</strong>: <a href="http://blog.philippheckel.com/uploads/2010/01/wp-un-0.1">WP-UN 0.1, January 2010</a> (broken!)</p>
<h3 id="toc-usage">Usage</h3>
<p>Now you can call the script with the following arguments:</p>
<ul>
<li><strong>&#8211;test</strong>: to test if the notification works, use the <em>&#8211;test</em> parameter (optional).</li>
<li><strong>INSTALL-DIR</strong>: the path to your local WordPress installation, for example /var/www/myblog.</li>
<li><strong>NOTIFY-EMAIL</strong>: the e-mail address of the person to notify if a new WordPress version is available.</li>
</ul>
<p>By default, the script is completely silent so that adding a cronjob doesn&#8217;t require output redirections. If, however, the <em>&#8211;test</em> option is given, it is more verbose and sends the notification e-mail in any case.</p>
<p>If a new WordPress version is available, the output looks something like this:</p>

<div class="wp_syntax"><div class="code"><pre class="text" style="font-family:monospace;">$ wp-un --test /var/www/myblog admin@example.com
Checking installed version... WordPress 2.5.1
Checking latest version... WordPress 2.9.1
Update required; Sending notification to admin@example.com... done.</pre></div></div>

<p>If WordPress is up-to-date, WP-UN would normally not send any notification. If, however, the <em>&#8211;test</em> option is enabled, it sends the e-mail no matter what. In this case, the output will look like this:</p>

<div class="wp_syntax"><div class="code"><pre class="text" style="font-family:monospace;">$ wp-un --test /var/www/myblog admin@example.com
Checking installed version... WordPress 2.9.1
Checking latest version... WordPress 2.9.1
Update not necessary; WordPress is up-to-date.
TEST-flag enabled: sending notfication to admin@example.com... done.</pre></div></div>

<p>The notification you receive will look like this:</p>

<div class="wp_syntax"><div class="code"><pre class="text" style="font-family:monospace;"> The WordPress installation on host example.com needs an update:
&nbsp;
   Installed Version: WordPress 2.5.1
                  at: /var/www/myblog
&nbsp;
      Latest Version: WordPress 2.9.1
            Download: http://www.wordpress.org/latest.tar.gz</pre></div></div>

<h3 id="toc-as-cronjob">As cronjob</h3>
<p>If you want to be notified as soon as a new version comes out, installing a cronjob is a good idea. Simply run <em>crontab -e</em> and add the following line to the file:</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #000000;">0</span> <span style="color: #000000;">6</span> <span style="color: #000000; font-weight: bold;">*</span> <span style="color: #000000; font-weight: bold;">*</span> <span style="color: #000000; font-weight: bold;">*</span> <span style="color: #000000; font-weight: bold;">/</span>usr<span style="color: #000000; font-weight: bold;">/</span>local<span style="color: #000000; font-weight: bold;">/</span>bin<span style="color: #000000; font-weight: bold;">/</span>wp-un <span style="color: #000000; font-weight: bold;">/</span>var<span style="color: #000000; font-weight: bold;">/</span>www<span style="color: #000000; font-weight: bold;">/</span>myblog admin<span style="color: #000000; font-weight: bold;">@</span>example.com</pre></div></div>

<p>WP-UN will now run every morning at 6am and notify you if a new WordPress version is out there!</p>
<h3 id="toc-conclusion">Conclusion</h3>
<p>WP-UN is just one of many solutions and it&#8217;s only the work of one afternoon. However, it doesn&#8217;t need any additional software and keeps it simple. It serves its purpose and keeps my WordPress installation always up-to-date. If you have any suggestions or questions, feel free to comment below.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.philippheckel.com/2010/01/29/wp-un-wordpress-version-update-notification-with-cron/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>How to: Postfix as mail relay with greylisting support</title>
		<link>http://blog.philippheckel.com/2010/01/28/how-to-postfix-as-mail-relay-with-greylisting-support/</link>
		<comments>http://blog.philippheckel.com/2010/01/28/how-to-postfix-as-mail-relay-with-greylisting-support/#comments</comments>
		<pubDate>Thu, 28 Jan 2010 20:35:11 +0000</pubDate>
		<dc:creator>Philipp C. Heckel</dc:creator>
				<category><![CDATA[Administration]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[Debian]]></category>
		<category><![CDATA[Greylisting]]></category>
		<category><![CDATA[Mail]]></category>
		<category><![CDATA[Postfix]]></category>
		<category><![CDATA[SQLgrey]]></category>

		<guid isPermaLink="false">http://blog.philippheckel.com/?p=30</guid>
		<description><![CDATA[Greylisting is a very efficient technique for fighting spam and can reduce the spam messages in your mailbox by more than 90%. It uses the fact that most spammers only try delivering their spam-mails once, whereas real mail transfer agents (such as the ones regular e-mail service providers are using) try delivering each message up [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.greylisting.org/">Greylisting</a> is a very efficient technique for fighting spam and can reduce the spam messages in your mailbox by more than 90%. It uses the fact that most spammers only try delivering their spam-mails once, whereas real mail transfer agents (such as the ones regular e-mail service providers are using) try delivering each message up to 4-5 days before they give up. </p>
<p>I have always wondered why most ESPs don&#8217;t offer greylisting for their mailboxes, but only rely on less effective and resource-hungry post-retrieval filter methods. Unfortunately, my e-mail provider is one of them so that I get at least a couple of spam mails a day &#8230;</p>
<p>Luckily, it is very easy to set up your own mail relay with greylisting support, i.e. a mail server that simply forwards the mail to your real provider once it passes the greylist-filter. </p>
<p>This little tutorial describes how to set up <a href="http://www.postfix.org">Postfix</a> and <a href="http://sqlgrey.sourceforge.net/">SQLgrey</a> as mail relay.</p>
<p><span id="more-30"></span></p>
<h3 id="toc-1-what-you-need">1. What you need</h3>
<ul>
<li>A dedicated or virtual private server with SSH root access.</li>
<li>Access to the DNS entries of your domain for adjusting the MX record; in this post called <em>example.com</em></li>
</ul>
<h3 id="toc-2-how-it-works">2. How it works</h3>
<p>If you have outsourced all e-mail services to a service provider like I have, the MX record of your domain usually points to your provider&#8217;s mail server. That is, your mails go directly to the mail server of your provider, e.g. <strong>Google&#8217;s mail server → your provider&#8217;s mail server</strong>. That is, your DNS configuration looks something like this:</p>

<div class="wp_syntax"><div class="code"><pre class="text" style="font-family:monospace;">$ dig example.com mx
...
example.com.		IN	MX	50 mx0.example.com.
mx0.example.com.	IN	A	(your provider's mail server IP)
...</pre></div></div>

<p>In order to pre-process mails with greylisting and blacklisting, your server will handle mails as intermediary, i.e., mails will always traverse your server first; in the above case something like <strong>Google&#8217;s mail server → your mail server → your provider&#8217;s mail server</strong>. Consequently, the MX record has to be changed to the IP address of your server:</p>

<div class="wp_syntax"><div class="code"><pre class="text" style="font-family:monospace;">$ dig example.com mx
...
example.com.		IN	MX	50 mx0.example.com.
mx0.example.com.	IN	A	(your server IP)
...</pre></div></div>

<p><strong>But</strong>, first things first: we need to configure our server before we change the DNS records!</p>
<h3 id="toc-3-installation-configuration">3. Installation &amp; Configuration</h3>
<p>If you have a Debian based system, install Postfix, SQLgrey and MySQL using apt-get:</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">$ <span style="color: #c20cb9; font-weight: bold;">apt-get</span> <span style="color: #c20cb9; font-weight: bold;">install</span> postfix sqlgrey mysql-server</pre></div></div>

<p>This will install:</p>
<ul>
<li><strong><a href="http://www.postfix.org/">Postfix</a></strong>: a fully functioning MTA which will be configured as mail relay, i.e., instead of storing arriving mails on the system, it will just greylist them and then forward them to their real destination (your provider&#8217;s mail server).</li>
<li><strong><a href="http://sqlgrey.sourceforge.net/">SQLgrey</a></strong>: a SQL-based greylisting add-on for Postfix. Before accepting mails blindly, Postfix will ask the SQLgrey daemon whether to accept the mail or not. SQLgrey keeps track of mail delivery attempts and only replies with success if the foreign MTA tried delivering the mail at least twice.</li>
<li><strong><a href="http://www.mysql.com/">MySQL</a></strong>: a RDBMS which will be used as back-end for storing Postfix&#8217;s routing tables and SQLgrey&#8217;s caching tables. Both Postfix and SQLgrey also support other back-ends such as <a href="http://www.postgresql.org/">PostgreSQL</a>.</li>
</ul>
<h4 id="toc-3-1-configuring-sqlgrey">3.1. Configuring SQLgrey</h4>
<p>SQLgrey&#8217;s config files reside in <em>/etc/sqlgrey/</em>, the main configuration happens in <em>/etc/sqlgrey/sqlgrey.conf</em>. The file is well documented and offers many possibilities. </p>
<p>The most important options are:</p>
<ul>
<li><strong>inet</strong>: IP address and port to bind the daemon to, default is 127.0.0.1:2501</li>
<li><strong>db_*</strong>: database connection details, i.e., database, user and password</li>
<li><strong>greymethod</strong>: defines which <a href="http://en.wikipedia.org/wiki/Classful_network#Introduction_of_address_classes">IP class</a> to use for greylisting. Especially important for big e-mail service providers since the same mail might be delivered from two different IP addresses (Class C greylisting recommended!).</li>
<li><strong>optmethod</strong>: defines if greylisting is enabled by default (optout), or has to be enabled specifically for each address or domain (optin).</li>
</ul>
<h5 id="toc-3-1-1-config-file-etcsqlgreysqlgrey-conf">3.1.1. Config file /etc/sqlgrey/sqlgrey.conf</h5>
<p>My configuration looks like this:</p>

<div class="wp_syntax"><div class="code"><pre class="properties" style="font-family:monospace;"><span style="color: #000080; font-weight:bold;">inet</span> <span style="color: #000000;">=</span><span style="color: #008000; font-weight:bold;"> 10101 </span><span style="color: #808080; font-style: italic;"># bind to localhost:10101</span>
<span style="color: #000080; font-weight:bold;">reconnect_delay</span> <span style="color: #000000;">=</span><span style="color: #008000; font-weight:bold;"> 5 </span><span style="color: #808080; font-style: italic;"># no reconnect before 5 minutes</span>
<span style="color: #000080; font-weight:bold;">max_connect_age</span> <span style="color: #000000;">=</span><span style="color: #008000; font-weight:bold;"> 24 </span><span style="color: #808080; font-style: italic;"># no reconnect after 24 hours</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># database settings</span>
<span style="color: #000080; font-weight:bold;">db_type</span> <span style="color: #000000;">=</span><span style="color: #008000; font-weight:bold;"> mysql</span>
<span style="color: #000080; font-weight:bold;">db_name</span> <span style="color: #000000;">=</span><span style="color: #008000; font-weight:bold;"> sqlgrey</span>
<span style="color: #000080; font-weight:bold;">db_host</span> <span style="color: #000000;">=</span><span style="color: #008000; font-weight:bold;"> localhost</span>
<span style="color: #000080; font-weight:bold;">db_user</span> <span style="color: #000000;">=</span><span style="color: #008000; font-weight:bold;"> sqlgrey</span>
<span style="color: #000080; font-weight:bold;">db_pass</span> <span style="color: #000000;">=</span><span style="color: #008000; font-weight:bold;"> sqlgreypassword</span>
<span style="color: #000080; font-weight:bold;">db_cleandelay</span> <span style="color: #000000;">=</span><span style="color: #008000; font-weight:bold;"> 1800 </span>
<span style="color: #000080; font-weight:bold;">clean_method</span> <span style="color: #000000;">=</span><span style="color: #008000; font-weight:bold;"> sync </span><span style="color: #808080; font-style: italic;"># 'async' is said to be buggy</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># greylist by class C network. eg: 2.3.4.6 connection</span>
<span style="color: #808080; font-style: italic;"># accepted if 2.3.4.145 did connect earlier</span>
<span style="color: #000080; font-weight:bold;">greymethod</span> <span style="color: #000000;">=</span><span style="color: #008000; font-weight:bold;"> classc</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># one must optin to have its (incoming) messages being greylisted</span>
<span style="color: #000080; font-weight:bold;">optmethod</span> <span style="color: #000000;">=</span><span style="color: #008000; font-weight:bold;"> optin</span></pre></div></div>

<h5 id="toc-3-1-2-database">3.1.2. Database</h5>
<p>SQLgrey has a fixed database structure which is set up automatically when the script is started. All that needs to be done is to create a new database <em>sqlgrey</em> with a corresponding user. You can do this manually, or with a tool like <a href="http://www.phpmyadmin.net/">phpMyAdmin</a>:</p>

<div class="wp_syntax"><div class="code"><pre class="sql" style="font-family:monospace;"><span style="color: #993333; font-weight: bold;">CREATE</span> <span style="color: #993333; font-weight: bold;">USER</span> <span style="color: #ff0000;">'sqlgrey'</span>@<span style="color: #ff0000;">'localhost'</span> <span style="color: #993333; font-weight: bold;">IDENTIFIED</span> <span style="color: #993333; font-weight: bold;">BY</span> <span style="color: #ff0000;">'sqlgreypassword'</span>;
<span style="color: #993333; font-weight: bold;">CREATE</span> <span style="color: #993333; font-weight: bold;">DATABASE</span> <span style="color: #993333; font-weight: bold;">IF</span> <span style="color: #993333; font-weight: bold;">NOT</span> <span style="color: #993333; font-weight: bold;">EXISTS</span> <span style="color: #ff0000;">`sqlgrey`</span> ;
<span style="color: #993333; font-weight: bold;">GRANT</span> <span style="color: #993333; font-weight: bold;">ALL</span> PRIVILEGES <span style="color: #993333; font-weight: bold;">ON</span> <span style="color: #ff0000;">`sqlgrey`</span> <span style="color: #66cc66;">.</span> <span style="color: #66cc66;">*</span> <span style="color: #993333; font-weight: bold;">TO</span> <span style="color: #ff0000;">'sqlgrey'</span>@<span style="color: #ff0000;">'localhost'</span>;
<span style="color: #993333; font-weight: bold;">FLUSH</span> PRIVILEGES;</pre></div></div>

<h5 id="toc-3-1-3-populating-the-database">3.1.3. Populating the database</h5>
<p>SQLgrey automatically creates the required tables when it starts for the first time. So start the daemon using the provided init.d-script:</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">$ <span style="color: #000000; font-weight: bold;">/</span>etc<span style="color: #000000; font-weight: bold;">/</span>init.d<span style="color: #000000; font-weight: bold;">/</span>sqlgrey start</pre></div></div>

<p>This creates a couple of tables in the <em>sqlgrey</em>-database. For our purpose and configuration, the tables <em>optin_email</em> and <em>optin_domain</em> are most interesting because only domains and e-mail addresses in these tables will be greylisted.</p>
<p>For our example, we will enable greylisting for the whole domain <em>example.com</em>:</p>

<div class="wp_syntax"><div class="code"><pre class="sql" style="font-family:monospace;"><span style="color: #993333; font-weight: bold;">INSERT</span> <span style="color: #993333; font-weight: bold;">INTO</span> <span style="color: #ff0000;">`sqlgrey`</span><span style="color: #66cc66;">.</span><span style="color: #ff0000;">`optin_domain`</span> <span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">`domain`</span><span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">VALUES</span> <span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'example.com'</span><span style="color: #66cc66;">&#41;</span>;</pre></div></div>

<p>That&#8217;s it for SQLgrey. Once we connect it to Postfix, it&#8217;ll provide us with the greylisting service we want. </p>
<h4 id="toc-3-2-configuring-postfix">3.2. Configuring Postfix</h4>
<p>Postfix is a very flexible and powerful mail transfer agent (MTA) and can be used as final destination, or mail forwarder (mail relay). For this scenario, Postfix will be a <em>mail relay</em> which only forwards an e-mail if</p>
<ul>
<li>its recipient is listed in the database</li>
<li>and it passes the greylisting-filter</li>
</ul>
<p>The configuration files of Postfix reside in <em>/etc/postfix/</em>. The most interesting file for our purpose is <em>/etc/postfix/main.cf</em>.</p>
<p>In order to not be confused by all the more or less useful config parameters, the file shown here is <em>minimal</em>, i.e., you <em>cannot</em> remove any parameter without major consequences. Details to each of them can be found in the <a href="http://www.postfix.org/postconf.5.html">Postfix configuration man-page</a>.</p>
<p>The most important parameters for the configuration as mail relay are:</p>
<ul>
<li><strong><a href="http://www.postfix.org/postconf.5.html#myhostname">myhostname</a></strong>: this defines your hostname, i.e., in this case <em>relay.example.com</em>. Regarding the hostname, two things must be considered very thoroughly:
<ol>
<li>The hostname must resolve to the IP address of your server, i.e., make sure you don&#8217;t state a fake host here. Postfix uses this value as <a href="http://en.wikipedia.org/wiki/Simple_Mail_Transfer_Protocol">HELO/EHLO</a> identification, and some mail servers might <strong>reject</strong> your mails if  this value doesn&#8217;t resolve to your server&#8217;s IP address.</li>
<li>If you use your top level domain here, e.g. example.com, some mail servers might additionally perform a <a href="http://en.wikipedia.org/wiki/MX_record">MX lookup</a> and match your server&#8217;s IP address with the one of the MX record. In case the MX record points to a different IP address than the A record of the TLD, foreign servers might also <strong>reject</strong> all your mails. In my case, this resulted in log entries like this:

<div class="wp_syntax"><div class="code"><pre class="text" style="font-family:monospace;">postfix/smtp: to=&lt;john.doe@example.com&gt;, 
  relay=mx.my-esp.tld:25,  status=bounced 
  (host mx.somedomain.com[1.2.3.4] refused to talk to me: 
  550 Forged HELO: you are not example.com)</pre></div></div>

<p>As you can see, the foreign hosts suspected me of forging the HELO name, and denied relaying my mails.</li>
</ol>
</li>
<li><strong><a href="http://www.postfix.org/postconf.5.html#relay_domains">relay_domains</a></strong>: this option links to the database table <em>relay_domains</em> and defines the domains managed by this mail server. If a recipient-domain is not in this table, Postfix will reject the mail. For this example, the domain <em>example.com</em> must be added to this DB table.</li>
<li><strong><a href="http://www.postfix.org/postconf.5.html#relay_recipient_maps">relay_recipient_maps</a></strong>: this option links to the database table <em>relay_recipients</em> and defines the e-mail addresses managed by this mail server. If a recipient address is not in this table, Postfix will reject the mail. This option is closely linked to <em>relay_domains</em> and will not work without it!
<p>In this case, only one address will be added to this table: <em>john.doe@example.com</em>.</li>
<li><strong><a href="http://www.postfix.org/postconf.5.html#transport_maps">transport_maps</a></strong>: this option links to the database table <em>transport</em> and defines to which mail server incoming mails will be forwarded. Routing can happen address- or domain-based.
<p>In this case, mails for <em>example.com</em> shall be forwarded to our provider&#8217;s mail server, i.e., this table must have an entry of the form <em>example.com</em> → <em>smtp:[mx.my-esp.tld]</em>.</p>
<p>For details on the value format, read the <a href="http://www.postfix.org/transport.5.html">transport man page</a>.</li>
<li><strong><a href="http://www.postfix.org/postconf.5.html#smtpd_recipient_restrictions">smtpd_recipient_restrictions</a></strong>: this is where the actual magic happens. This option checks the RCPT TO field of each incoming mail, i.e., the recipient, and then queries the greylisting service. Its options closely relate to the <em>relay_*</em>-tables from above:
<ul>
<li><strong><a href="http://www.postfix.org/postconf.5.html#permit_mynetworks">permit_mynetworks</a></strong> allows local applications to send e-mails. If you have web sites running on localhost that may use e-mail, do not remove this option.</li>
<li><strong><a href="http://www.postfix.org/postconf.5.html#reject_unauth_destination">reject_unauth_destination</a></strong> queries the <em>relay_domains</em> SQL table, i.e., it checks whether a the incoming recipient domain is relayed by our server.</li>
<li><strong><a href="http://www.postfix.org/postconf.5.html#reject_unlisted_recipient">reject_unlisted_recipient</a></strong> queries the <em>relay_recipients</em> SQL table to find out if the exact address is relayed.</li>
<li><strong><a href="http://www.postfix.org/postconf.5.html#check_policy_service">check_policy_service</a></strong> queries the SQLgrey daemon which in turn either allows or rejects the mail.</li>
</ul>
</li>
</ul>
<h5 id="toc-3-2-1-config-file-etcpostfixmain-cf">3.2.1 Config file /etc/postfix/main.cf</h5>
<p>Here&#8217;s the minimal <em>main.cf</em> config file to make Postfix a mail relay with greylisting support:</p>

<div class="wp_syntax"><div class="code"><pre class="properties" style="font-family:monospace;"><span style="color: #808080; font-style: italic;"># This is a minimal main.cf config file. Make sure to read the above </span>
<span style="color: #808080; font-style: italic;"># comments so you understand what each option means.</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># server name; must resolve to your server's IP address</span>
<span style="color: #000080; font-weight:bold;">myhostname</span> <span style="color: #000000;">=</span><span style="color: #008000; font-weight:bold;"> relay.example.com</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># avoid warning message 'dict_nis_init: NIS ...'</span>
<span style="color: #000080; font-weight:bold;">alias_maps</span> <span style="color: #000000;">=</span> 
&nbsp;
<span style="color: #000080; font-weight:bold;">relay_domains</span> <span style="color: #000000;">=</span><span style="color: #008000; font-weight:bold;"> mysql:/etc/postfix/mysql_relay_domains.cf</span>
<span style="color: #000080; font-weight:bold;">relay_recipient_maps</span> <span style="color: #000000;">=</span><span style="color: #008000; font-weight:bold;"> mysql:/etc/postfix/mysql_relay_recipient_maps.cf</span>
<span style="color: #000080; font-weight:bold;">transport_maps</span> <span style="color: #000000;">=</span><span style="color: #008000; font-weight:bold;"> mysql:/etc/postfix/mysql_transport_maps.cf</span>
&nbsp;
<span style="color: #000080; font-weight:bold;">smtpd_recipient_restrictions</span> <span style="color: #000000;">=</span>
        permit_mynetworks,
        reject_unauth_destination,
        reject_unlisted_recipient,
        check_policy_service inet:127.0.0.1:<span style="">10101</span></pre></div></div>

<h5 id="toc-3-2-2-database">3.2.2. Database</h5>
<p>Postfix is very flexible when it comes to address and route handling. In fact, its configuration doesn&#8217;t need a database back-end at all. However, using a SQL database makes everything much easier. I decided to use a very straight forward database structure which directly relates to Postfix&#8217; configuration options. </p>
<p>First, create a database <em>postfix</em> and a corresponding read-only user:</p>

<div class="wp_syntax"><div class="code"><pre class="sql" style="font-family:monospace;"><span style="color: #993333; font-weight: bold;">CREATE</span> <span style="color: #993333; font-weight: bold;">USER</span> <span style="color: #ff0000;">'postfix'</span>@<span style="color: #ff0000;">'127.0.0.1'</span> <span style="color: #993333; font-weight: bold;">IDENTIFIED</span> <span style="color: #993333; font-weight: bold;">BY</span> <span style="color: #ff0000;">'postfixpassword'</span>;
<span style="color: #993333; font-weight: bold;">CREATE</span> <span style="color: #993333; font-weight: bold;">DATABASE</span> <span style="color: #993333; font-weight: bold;">IF</span> <span style="color: #993333; font-weight: bold;">NOT</span> <span style="color: #993333; font-weight: bold;">EXISTS</span> <span style="color: #ff0000;">`postfix`</span> ;
<span style="color: #993333; font-weight: bold;">GRANT</span> <span style="color: #993333; font-weight: bold;">SELECT</span> <span style="color: #993333; font-weight: bold;">ON</span> <span style="color: #ff0000;">`postfix`</span> <span style="color: #66cc66;">.</span> <span style="color: #66cc66;">*</span> <span style="color: #993333; font-weight: bold;">TO</span> <span style="color: #ff0000;">'postfix'</span>@<span style="color: #ff0000;">'127.0.0.1'</span>;
<span style="color: #993333; font-weight: bold;">FLUSH</span> PRIVILEGES;</pre></div></div>

<p><strong>Note</strong>: It is important that you use <em>127.0.0.1</em> as host, and not <em>localhost</em>, because Postfix runs in a <a href="http://en.wikipedia.org/wiki/Chroot">chroot</a>-environment and wouldn&#8217;t be able to access <em>localhost</em>. </p>
<p>After setting up the database, add the following three tables:</p>

<div class="wp_syntax"><div class="code"><pre class="sql" style="font-family:monospace;"><span style="color: #993333; font-weight: bold;">CREATE</span> <span style="color: #993333; font-weight: bold;">TABLE</span> <span style="color: #ff0000;">`relay_domains`</span> <span style="color: #66cc66;">&#40;</span>
  <span style="color: #ff0000;">`domain`</span> <span style="color: #993333; font-weight: bold;">VARCHAR</span><span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">255</span><span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">NOT</span> <span style="color: #993333; font-weight: bold;">NULL</span><span style="color: #66cc66;">,</span>
  <span style="color: #ff0000;">`active`</span> enum<span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'y'</span><span style="color: #66cc66;">,</span><span style="color: #ff0000;">'n'</span><span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">NOT</span> <span style="color: #993333; font-weight: bold;">NULL</span> <span style="color: #993333; font-weight: bold;">DEFAULT</span> <span style="color: #ff0000;">'y'</span><span style="color: #66cc66;">,</span>
  <span style="color: #993333; font-weight: bold;">PRIMARY</span> <span style="color: #993333; font-weight: bold;">KEY</span>  <span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">`domain`</span><span style="color: #66cc66;">&#41;</span>
<span style="color: #66cc66;">&#41;</span>;
&nbsp;
<span style="color: #993333; font-weight: bold;">CREATE</span> <span style="color: #993333; font-weight: bold;">TABLE</span> <span style="color: #ff0000;">`relay_recipients`</span> <span style="color: #66cc66;">&#40;</span>
  <span style="color: #ff0000;">`email`</span> <span style="color: #993333; font-weight: bold;">VARCHAR</span><span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">255</span><span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">NOT</span> <span style="color: #993333; font-weight: bold;">NULL</span><span style="color: #66cc66;">,</span>
  <span style="color: #ff0000;">`active`</span> enum<span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'y'</span><span style="color: #66cc66;">,</span><span style="color: #ff0000;">'n'</span><span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">NOT</span> <span style="color: #993333; font-weight: bold;">NULL</span> <span style="color: #993333; font-weight: bold;">DEFAULT</span> <span style="color: #ff0000;">'y'</span><span style="color: #66cc66;">,</span>
  <span style="color: #993333; font-weight: bold;">PRIMARY</span> <span style="color: #993333; font-weight: bold;">KEY</span>  <span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">`email`</span><span style="color: #66cc66;">&#41;</span>
<span style="color: #66cc66;">&#41;</span>;
&nbsp;
<span style="color: #993333; font-weight: bold;">CREATE</span> <span style="color: #993333; font-weight: bold;">TABLE</span> <span style="color: #ff0000;">`transport`</span> <span style="color: #66cc66;">&#40;</span>
  <span style="color: #ff0000;">`pattern`</span> <span style="color: #993333; font-weight: bold;">VARCHAR</span><span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">255</span><span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">NOT</span> <span style="color: #993333; font-weight: bold;">NULL</span><span style="color: #66cc66;">,</span>
  <span style="color: #ff0000;">`relay`</span> <span style="color: #993333; font-weight: bold;">VARCHAR</span><span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">255</span><span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">NOT</span> <span style="color: #993333; font-weight: bold;">NULL</span><span style="color: #66cc66;">,</span>
  <span style="color: #ff0000;">`active`</span> enum<span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'y'</span><span style="color: #66cc66;">,</span><span style="color: #ff0000;">'n'</span><span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">NOT</span> <span style="color: #993333; font-weight: bold;">NULL</span> <span style="color: #993333; font-weight: bold;">DEFAULT</span> <span style="color: #ff0000;">'y'</span><span style="color: #66cc66;">,</span>
  <span style="color: #993333; font-weight: bold;">PRIMARY</span> <span style="color: #993333; font-weight: bold;">KEY</span>  <span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">`pattern`</span><span style="color: #66cc66;">&#41;</span>
<span style="color: #66cc66;">&#41;</span>;</pre></div></div>

<p>In order to connect Postfix with the database, we need to create the three config files specified above: /etc/postfix/mysql_*.cf:</p>

<div class="wp_syntax"><div class="code"><pre class="properties" style="font-family:monospace;"><span style="color: #808080; font-style: italic;"># /etc/postfix/mysql_relay_domains.cf</span>
<span style="color: #000080; font-weight:bold;">hosts</span> <span style="color: #000000;">=</span><span style="color: #008000; font-weight:bold;"> 127.0.0.1</span>
<span style="color: #000080; font-weight:bold;">user</span> <span style="color: #000000;">=</span><span style="color: #008000; font-weight:bold;"> postfix-read</span>
<span style="color: #000080; font-weight:bold;">password</span> <span style="color: #000000;">=</span><span style="color: #008000; font-weight:bold;"> postfixpassword</span>
<span style="color: #000080; font-weight:bold;">dbname</span> <span style="color: #000000;">=</span><span style="color: #008000; font-weight:bold;"> postfix</span>
<span style="color: #000080; font-weight:bold;">query</span> <span style="color: #000000;">=</span><span style="color: #008000; font-weight:bold;"> SELECT domain FROM relay_domains WHERE domain='%s' AND active='y'</span></pre></div></div>


<div class="wp_syntax"><div class="code"><pre class="properties" style="font-family:monospace;"><span style="color: #808080; font-style: italic;"># /etc/postfix/mysql_relay_recipient_maps.cf</span>
<span style="color: #000080; font-weight:bold;">hosts</span> <span style="color: #000000;">=</span><span style="color: #008000; font-weight:bold;"> 127.0.0.1</span>
<span style="color: #000080; font-weight:bold;">user</span> <span style="color: #000000;">=</span><span style="color: #008000; font-weight:bold;"> postfix-read</span>
<span style="color: #000080; font-weight:bold;">password</span> <span style="color: #000000;">=</span><span style="color: #008000; font-weight:bold;"> postfixpassword</span>
<span style="color: #000080; font-weight:bold;">dbname</span> <span style="color: #000000;">=</span><span style="color: #008000; font-weight:bold;"> postfix</span>
<span style="color: #000080; font-weight:bold;">query</span> <span style="color: #000000;">=</span><span style="color: #008000; font-weight:bold;"> SELECT email FROM relay_recipients WHERE email='%s' AND active='y'</span></pre></div></div>


<div class="wp_syntax"><div class="code"><pre class="properties" style="font-family:monospace;"><span style="color: #808080; font-style: italic;"># /etc/postfix/mysql_transport_maps.cf</span>
<span style="color: #000080; font-weight:bold;">hosts</span> <span style="color: #000000;">=</span><span style="color: #008000; font-weight:bold;"> 127.0.0.1</span>
<span style="color: #000080; font-weight:bold;">user</span> <span style="color: #000000;">=</span><span style="color: #008000; font-weight:bold;"> postfix-read</span>
<span style="color: #000080; font-weight:bold;">password</span> <span style="color: #000000;">=</span><span style="color: #008000; font-weight:bold;"> postfixpassword</span>
<span style="color: #000080; font-weight:bold;">dbname</span> <span style="color: #000000;">=</span><span style="color: #008000; font-weight:bold;"> postfix</span>
<span style="color: #000080; font-weight:bold;">query</span> <span style="color: #000000;">=</span><span style="color: #008000; font-weight:bold;"> SELECT relay FROM transport WHERE pattern='%s' AND active='y'</span></pre></div></div>

<p>Before we can now start testing our server, we need to compile these config files to Postfix compatible lookup tables. Do that by running the following command:</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">$ postmap <span style="color: #000000; font-weight: bold;">/</span>etc<span style="color: #000000; font-weight: bold;">/</span>postfix<span style="color: #000000; font-weight: bold;">/</span>mysql_<span style="color: #000000; font-weight: bold;">*</span>.cf</pre></div></div>

<h5 id="toc-3-2-3-populate-the-database">3.2.3. Populate the database</h5>
<p>Now we have to fill Postfix&#8217; database with the domains and addresses we&#8217;d like to relay. In particular, that means we have to add <em>example.com</em> to <em>relay_domains</em> and <em>transport</em>, and the full addresses to <em>relay_recipients</em>:</p>

<div class="wp_syntax"><div class="code"><pre class="sql" style="font-family:monospace;"><span style="color: #993333; font-weight: bold;">INSERT</span> <span style="color: #993333; font-weight: bold;">INTO</span> <span style="color: #ff0000;">`postfix`</span><span style="color: #66cc66;">.</span><span style="color: #ff0000;">`relay_domains`</span> <span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">`domain`</span> <span style="color: #66cc66;">,</span><span style="color: #ff0000;">`active`</span><span style="color: #66cc66;">&#41;</span>
   <span style="color: #993333; font-weight: bold;">VALUES</span> <span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'example.com'</span><span style="color: #66cc66;">,</span> <span style="color: #ff0000;">'y'</span><span style="color: #66cc66;">&#41;</span>;
&nbsp;
<span style="color: #993333; font-weight: bold;">INSERT</span> <span style="color: #993333; font-weight: bold;">INTO</span> <span style="color: #ff0000;">`postfix`</span><span style="color: #66cc66;">.</span><span style="color: #ff0000;">`relay_recipients`</span> <span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">`email`</span> <span style="color: #66cc66;">,</span><span style="color: #ff0000;">`active`</span><span style="color: #66cc66;">&#41;</span>
   <span style="color: #993333; font-weight: bold;">VALUES</span> <span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'john.doe@example.com'</span><span style="color: #66cc66;">,</span> <span style="color: #ff0000;">'y'</span><span style="color: #66cc66;">&#41;</span>;
&nbsp;
<span style="color: #993333; font-weight: bold;">INSERT</span> <span style="color: #993333; font-weight: bold;">INTO</span> <span style="color: #ff0000;">`postfix`</span><span style="color: #66cc66;">.</span><span style="color: #ff0000;">`transport`</span> <span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">`pattern`</span> <span style="color: #66cc66;">,</span><span style="color: #ff0000;">`relay`</span> <span style="color: #66cc66;">,</span><span style="color: #ff0000;">`active`</span><span style="color: #66cc66;">&#41;</span>
   <span style="color: #993333; font-weight: bold;">VALUES</span> <span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'example.com'</span><span style="color: #66cc66;">,</span> <span style="color: #ff0000;">'smtp:[mx.my-e-mail-service-provider.tld]'</span><span style="color: #66cc66;">,</span> <span style="color: #ff0000;">'y'</span><span style="color: #66cc66;">&#41;</span>;</pre></div></div>

<p>The entry structure for each table is different. Please refer to the Postfix manual for details (cp. <a href="http://www.postfix.org/transport.5.html">transport</a>, <a href="http://www.postfix.org/postconf.5.html#relay_domains">relay_domains</a>, and <a href="http://www.postfix.org/postconf.5.html#relay_recipient_maps">relay_recipient_maps</a>).</p>
<p><strong>Note</strong>: the database structure above is not optimal since it requires redundant entries in three different tables. Even though the structure is not perfect, I have chosen this layout to make it easily understandable!</p>
<h3 id="toc-4-test-your-server">4. Test your server</h3>
<p>After this short configuration period it&#8217;s now time to finally start the Postfix server:</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">$ <span style="color: #000000; font-weight: bold;">/</span>etc<span style="color: #000000; font-weight: bold;">/</span>init.d<span style="color: #000000; font-weight: bold;">/</span>postfix start</pre></div></div>

<p>To make sure you didn&#8217;t make any mistakes in the configuration, you should now check the log files. Postfix and SQLgrey both use syslog so that you should be able to determine the system&#8217;s status like this:</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">$ <span style="color: #c20cb9; font-weight: bold;">tail</span> <span style="color: #660033;">-n</span> <span style="color: #000000;">20</span> <span style="color: #660033;">-f</span> <span style="color: #000000; font-weight: bold;">/</span>var<span style="color: #000000; font-weight: bold;">/</span>log<span style="color: #000000; font-weight: bold;">/</span>syslog</pre></div></div>

<p>If the log doesn&#8217;t show any errors, we can now try if everything works as expected. To do so, simply connect to the server from your home computer via telnet:</p>

<div class="wp_syntax"><div class="code"><pre class="text" style="font-family:monospace;">$ telnet relay.example.com 25
Connected to relay.example.com.
Escape character is '^]'.
220 relay.example.com ESMTP Postfix
HELO somebody
250 relay.example.com
MAIL FROM: some@address.tld
250 2.1.0 Ok
RCPT TO: john.doe@example.com
450 4.7.1 &lt;john.doe@example.com&gt;: 
   Recipient address rejected: Greylisted for 5 minutes</pre></div></div>

<p>If Postfix replies with a 450 error code, i.e., relay temporarily denied, everything works just fine. On the server side, the log should output something like this:</p>

<div class="wp_syntax"><div class="code"><pre class="text" style="font-family:monospace;">postfix/smtpd: connect from 1-2-3-4.your-isp.tld[4.3.2.1]
&nbsp;
sqlgrey: grey: new: 4.3.2(4.3.2.1), some@address.tld-&gt;john.doe@example.com 
postfix/smtpd: NOQUEUE: reject: RCPT from 1-2-3-4.your-isp.tld[4.3.2.1]: 
    450 4.7.1 &lt;john.doe@example.com&gt;: 
    Recipient address rejected: Greylisted for 5 minutes; 
    from=&lt;some@address.tld&gt; to=&lt;john.doe@example.com&gt; ....
&nbsp;
postfix/smtpd: disconnect from 1-2-3-4.your-isp.tld[4.3.2.1]</pre></div></div>

<p>Wait 5 minutes and try connecting again via telnet. This time, SQLgrey will detect that this is your second delivery attempt and add the sender e-mail and its IP address to the automatic white list (AWL). Postfix will accept your mail and forward it to your provider&#8217;s mail server (according to the <em>transport</em>-table):</p>

<div class="wp_syntax"><div class="code"><pre class="text" style="font-family:monospace;">postfix/smtpd: connect from 1-2-3-4.your-isp.tld[4.3.2.1]
&nbsp;
sqlgrey: grey: reconnect ok: 4.3.2(4.3.2.1), 
    some@address.tld -&gt; john.doe@example.com (00:22:42) 
sqlgrey: grey: from awl: 4.3.2, some@address.tld added 
&nbsp;
postfix/smtpd: client=1-2-3-4.your-isp.tld[4.3.2.1]
postfix/cleanup: message-id=&lt;201001...@relay.example.com&gt;
postfix/qmgr: from=&lt;some@address.tld&gt;, size=422, ...
postfix/smtp: to=&lt;john.doe@example.com&gt;, 
    relay=mx.my-esp.tld[12.34.56.78]:25, status=sent, ...
postfix/qmgr: removed
&nbsp;
postfix/smtpd: disconnect from 1-2-3-4.your-isp.tld[4.3.2.1]</pre></div></div>

<h3 id="toc-5-go-live-change-the-dns-record">5. Go live: change the DNS record</h3>
<p>Play around a little and make sure that everything works as expected. If it does, change the DNS record like described above, i.e., set the MX record of the domains to be relayed to your server&#8217;s IP address.</p>
<p><strong>Note</strong>: For the first few mails, you should definitely watch the logs. If anything goes wrong, you can always change back the MX record. But be aware that DNS changes might take up to 48h!</p>
<p>If you have any questions, please comment below. I am open for suggestions!</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.philippheckel.com/2010/01/28/how-to-postfix-as-mail-relay-with-greylisting-support/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

