<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
     xmlns:content="http://purl.org/rss/1.0/modules/content/"
     xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
     xmlns:atom="http://www.w3.org/2005/Atom"
     xmlns:dc="http://purl.org/dc/elements/1.1/"
     xmlns:wfw="http://wellformedweb.org/CommentAPI/"
     >
  <channel>
    <title>Topdog.za.net</title>
    <link>http://www.topdog.za.net</link>
    <description>A bored sysadmin</description>
    <pubDate>Fri, 26 Feb 2016 10:06:56 GMT</pubDate>
    <generator>Blogofile</generator>
    <sy:updatePeriod>hourly</sy:updatePeriod>
    <sy:updateFrequency>1</sy:updateFrequency>
    <item>
      <title>Automating translation of software using the Microsoft Translator and Python</title>
      <link>http://www.topdog.za.net/2013/01/25/automating-translation-of-software-using-the-microsoft-translator-and-python</link>
      <pubDate>Fri, 25 Jan 2013 07:40:00 SAST</pubDate>
      <category><![CDATA[Sysadmin]]></category>
      <category><![CDATA[Tips]]></category>
      <category><![CDATA[Unix]]></category>
      <category><![CDATA[Linux]]></category>
      <guid isPermaLink="true">http://www.topdog.za.net/2013/01/25/automating-translation-of-software-using-the-microsoft-translator-and-python</guid>
      <description>Automating translation of software using the Microsoft Translator and Python</description>
      <content:encoded><![CDATA[<p>The <a href="http://msdn.microsoft.com/en-us/library/dd576287.aspx">Microsoft translator</a> provides an
API that you can use for automated translation. It currently supports about 39 languages.</p>
<p>True to the nature of open source i found that someone had already written
a <a href="https://github.com/openlabs/Microsoft-Translator-Python-API">python wrapper</a>
to the API. I extended the wrapper to use the <a href="http://docs.python-requests.org/en/latest/">requests</a>
and <a href="http://polib.readthedocs.org/en/latest/">pofile</a> packages.</p>
<p>My extended script is able to read gettext Portable Object <code>PO</code> source files and translate
the strings and write the translations back into <code>PO</code> files, here by automating the whole
translation process.</p>
<h2>Source</h2>
<div class="pygments_murphy"><pre><span class="c">#!/usr/bin/env python</span>
<span class="c"># -*- coding: utf-8 -*-</span>
<span class="c"># vim: ai ts=4 sts=4 et sw=4</span>

<span class="sd">&quot;&quot;&quot;Automatic translation using m$ translator</span>
<span class="sd">    :copyright: 2012 Andrew Colin Kissa</span>
<span class="sd">    :copyright: 2011 by Openlabs Technologies &amp; Consulting (P) Limited</span>
<span class="sd">    :license: BSD, see LICENSE for more details.</span>
<span class="sd">&quot;&quot;&quot;</span>

<span class="kn">import</span> <span class="nn">os</span>
<span class="kn">import</span> <span class="nn">re</span>
<span class="kn">import</span> <span class="nn">json</span>
<span class="kn">import</span> <span class="nn">time</span>
<span class="kn">import</span> <span class="nn">urllib</span>
<span class="kn">import</span> <span class="nn">logging</span>
<span class="kn">import</span> <span class="nn">datetime</span>

<span class="kn">import</span> <span class="nn">requests</span>

<span class="kn">from</span> <span class="nn">optparse</span> <span class="kn">import</span> <span class="n">OptionParser</span>

<span class="kn">from</span> <span class="nn">polib</span> <span class="kn">import</span> <span class="n">pofile</span>

<span class="n">__all__</span> <span class="o">=</span> <span class="p">[</span><span class="s">&#39;Translator&#39;</span><span class="p">,</span> <span class="s">&#39;TranslateApiException&#39;</span><span class="p">]</span>

<span class="k">class</span> <span class="nc">ArgumentException</span><span class="p">(</span><span class="ne">Exception</span><span class="p">):</span>
    <span class="sd">&quot;&quot;&quot;Argument&quot;&quot;&quot;</span>
    <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">):</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">message</span> <span class="o">=</span> <span class="n">message</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s">&#39;ArgumentException: &#39;</span><span class="p">,</span> <span class="s">&#39;&#39;</span><span class="p">)</span>
        <span class="nb">super</span><span class="p">(</span><span class="n">ArgumentException</span><span class="p">,</span> <span class="bp">self</span><span class="p">)</span><span class="o">.</span><span class="n">__init__</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">message</span><span class="p">)</span>

<span class="k">class</span> <span class="nc">ArgumentOutOfRangeException</span><span class="p">(</span><span class="ne">Exception</span><span class="p">):</span>
    <span class="sd">&quot;&quot;&quot;ArgumentOutOfRange&quot;&quot;&quot;</span>
    <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">):</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">message</span> <span class="o">=</span> <span class="n">message</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s">&#39;ArgumentOutOfRangeException: &#39;</span><span class="p">,</span> <span class="s">&#39;&#39;</span><span class="p">)</span>
        <span class="nb">super</span><span class="p">(</span><span class="n">ArgumentOutOfRangeException</span><span class="p">,</span> <span class="bp">self</span><span class="p">)</span><span class="o">.</span><span class="n">__init__</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">message</span><span class="p">)</span>

<span class="k">class</span> <span class="nc">TranslateApiException</span><span class="p">(</span><span class="ne">Exception</span><span class="p">):</span>
    <span class="sd">&quot;&quot;&quot;TranslateApi&quot;&quot;&quot;</span>
    <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">):</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">message</span> <span class="o">=</span> <span class="n">message</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s">&#39;TranslateApiException: &#39;</span><span class="p">,</span> <span class="s">&#39;&#39;</span><span class="p">)</span>
        <span class="nb">super</span><span class="p">(</span><span class="n">TranslateApiException</span><span class="p">,</span> <span class="bp">self</span><span class="p">)</span><span class="o">.</span><span class="n">__init__</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">message</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">)</span>

<span class="k">class</span> <span class="nc">Translator</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>
    <span class="sd">&quot;&quot;&quot;Implements AJAX API for the Microsoft Translator service</span>
<span class="sd">    </span>
<span class="sd">    &quot;&quot;&quot;</span>
    <span class="n">lang_url</span> <span class="o">=</span> <span class="s">&#39;http://api.microsofttranslator.com/V2/Ajax.svc/GetLanguagesForTranslate&#39;</span>
    <span class="n">oauth_url</span> <span class="o">=</span> <span class="s">&#39;https://datamarket.accesscontrol.windows.net/v2/OAuth2-13&#39;</span>
    <span class="n">translate_url</span> <span class="o">=</span> <span class="s">&quot;http://api.microsofttranslator.com/V2/Ajax.svc/Translate&quot;</span>
    <span class="n">translate_array_url</span> <span class="o">=</span> <span class="s">&quot;http://api.microsofttranslator.com/V2/Ajax.svc/TranslateArray&quot;</span>

    <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">client_id</span><span class="p">,</span> <span class="n">client_secret</span><span class="p">,</span>
            <span class="n">scope</span><span class="o">=</span><span class="s">&quot;http://api.microsofttranslator.com&quot;</span><span class="p">,</span> <span class="n">debug</span><span class="o">=</span><span class="bp">False</span><span class="p">):</span>
        <span class="sd">&quot;&quot;&quot;</span>

<span class="sd">        :param client_id: The client ID that you specified when you registered</span>
<span class="sd">                          your application with Azure DataMarket.</span>
<span class="sd">        :param client_secret: The client secret value that you obtained when</span>
<span class="sd">                              you registered your application with Azure</span>
<span class="sd">                              DataMarket.</span>
<span class="sd">        :param scope: Defaults to http://api.microsofttranslator.com</span>
<span class="sd">        :param debug: If true, the logging level will be set to debug</span>
<span class="sd">        &quot;&quot;&quot;</span>

        <span class="bp">self</span><span class="o">.</span><span class="n">client_id</span> <span class="o">=</span> <span class="n">client_id</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">client_secret</span> <span class="o">=</span> <span class="n">client_secret</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">scope</span> <span class="o">=</span> <span class="n">scope</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">grant_type</span> <span class="o">=</span> <span class="s">&quot;client_credentials&quot;</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">access_token</span> <span class="o">=</span> <span class="bp">None</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">debug</span> <span class="o">=</span> <span class="n">debug</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">logger</span> <span class="o">=</span> <span class="n">logging</span><span class="o">.</span><span class="n">getLogger</span><span class="p">(</span><span class="s">&quot;microsofttranslator&quot;</span><span class="p">)</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">session</span> <span class="o">=</span> <span class="bp">None</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">langs</span> <span class="o">=</span> <span class="p">[]</span>
        <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">debug</span><span class="p">:</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">logger</span><span class="o">.</span><span class="n">setLevel</span><span class="p">(</span><span class="n">level</span><span class="o">=</span><span class="n">logging</span><span class="o">.</span><span class="n">DEBUG</span><span class="p">)</span>

    <span class="k">def</span> <span class="nf">create_session</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="s">&quot;create a requests session&quot;</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">session</span> <span class="o">=</span> <span class="n">requests</span><span class="o">.</span><span class="n">session</span><span class="p">()</span>

    <span class="k">def</span> <span class="nf">get_access_token</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">force</span><span class="o">=</span><span class="bp">None</span><span class="p">):</span>
        <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">        .. note::</span>
<span class="sd">            The value of access token can be used for subsequent calls to the</span>
<span class="sd">            Microsoft Translator API. The access token expires after 10</span>
<span class="sd">            minutes. It is always better to check elapsed time between time at</span>
<span class="sd">            which token issued and current time. If elapsed time exceeds 10</span>
<span class="sd">            minute time period renew access token by following obtaining</span>
<span class="sd">            access token procedure.</span>

<span class="sd">        :return: The access token to be used with subsequent requests</span>
<span class="sd">        &quot;&quot;&quot;</span>
        <span class="n">args</span> <span class="o">=</span> <span class="n">urllib</span><span class="o">.</span><span class="n">urlencode</span><span class="p">({</span>
            <span class="s">&#39;client_id&#39;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">client_id</span><span class="p">,</span>
            <span class="s">&#39;client_secret&#39;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">client_secret</span><span class="p">,</span>
            <span class="s">&#39;scope&#39;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">scope</span><span class="p">,</span>
            <span class="s">&#39;grant_type&#39;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">grant_type</span>
        <span class="p">})</span>

        <span class="k">if</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">session</span> <span class="ow">or</span> <span class="n">force</span><span class="p">:</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">create_session</span><span class="p">()</span>

        <span class="n">response</span> <span class="o">=</span> <span class="n">json</span><span class="o">.</span><span class="n">loads</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">session</span><span class="o">.</span><span class="n">post</span><span class="p">(</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">oauth_url</span><span class="p">,</span>
            <span class="n">data</span><span class="o">=</span><span class="n">args</span>
        <span class="p">)</span><span class="o">.</span><span class="n">content</span><span class="p">)</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">access_token</span> <span class="o">=</span> <span class="n">response</span><span class="p">[</span><span class="s">&#39;access_token&#39;</span><span class="p">]</span>
        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">access_token</span>

    <span class="k">def</span> <span class="nf">call</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">url</span><span class="p">,</span> <span class="n">params</span><span class="p">):</span>
        <span class="sd">&quot;&quot;&quot;Calls the given url with the params urlencoded</span>
<span class="sd">        &quot;&quot;&quot;</span>
        <span class="k">if</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">access_token</span><span class="p">:</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">get_access_token</span><span class="p">()</span>

        <span class="k">if</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">session</span><span class="p">:</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">create_session</span><span class="p">()</span>

        <span class="n">headers</span> <span class="o">=</span> <span class="p">{</span><span class="s">&#39;Authorization&#39;</span><span class="p">:</span> <span class="s">&#39;Bearer </span><span class="si">%s</span><span class="s">&#39;</span> <span class="o">%</span> <span class="bp">self</span><span class="o">.</span><span class="n">access_token</span><span class="p">}</span>
        <span class="n">translation_url</span> <span class="o">=</span> <span class="s">&#39;</span><span class="si">%s</span><span class="s">?</span><span class="si">%s</span><span class="s">&#39;</span> <span class="o">%</span> <span class="p">(</span><span class="n">url</span><span class="p">,</span> <span class="n">urllib</span><span class="o">.</span><span class="n">urlencode</span><span class="p">(</span><span class="n">params</span><span class="p">))</span>
        <span class="n">response</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">session</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">translation_url</span><span class="p">,</span> <span class="n">headers</span><span class="o">=</span><span class="n">headers</span><span class="p">)</span>
        <span class="n">retval</span> <span class="o">=</span> <span class="n">json</span><span class="o">.</span><span class="n">loads</span><span class="p">(</span><span class="n">response</span><span class="o">.</span><span class="n">content</span><span class="o">.</span><span class="n">decode</span><span class="p">(</span><span class="s">&quot;UTF-8-sig&quot;</span><span class="p">))</span>

        <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">retval</span><span class="p">,</span> <span class="nb">basestring</span><span class="p">)</span> <span class="ow">and</span> \
                <span class="n">retval</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="s">&quot;ArgumentOutOfRangeException&quot;</span><span class="p">):</span>
            <span class="k">raise</span> <span class="n">ArgumentOutOfRangeException</span><span class="p">(</span><span class="n">retval</span><span class="p">)</span>

        <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">retval</span><span class="p">,</span> <span class="nb">basestring</span><span class="p">)</span> <span class="ow">and</span> \
                <span class="n">retval</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="s">&quot;TranslateApiException&quot;</span><span class="p">):</span>
            <span class="k">raise</span> <span class="n">TranslateApiException</span><span class="p">(</span><span class="n">retval</span><span class="p">)</span>

        <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">retval</span><span class="p">,</span> <span class="nb">basestring</span><span class="p">)</span> <span class="ow">and</span> \
                <span class="n">retval</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="s">&quot;ArgumentException&quot;</span><span class="p">):</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">access_token</span> <span class="o">=</span> <span class="bp">None</span>
            <span class="k">raise</span> <span class="n">ArgumentException</span><span class="p">(</span><span class="n">retval</span><span class="p">)</span>

        <span class="k">return</span> <span class="n">retval</span>

    <span class="k">def</span> <span class="nf">languages</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="sd">&quot;&quot;&quot;Check languages supported&quot;&quot;&quot;</span>
        <span class="k">if</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">session</span><span class="p">:</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">create_session</span><span class="p">()</span>

        <span class="k">if</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">langs</span><span class="p">:</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">langs</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">call</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">lang_url</span><span class="p">,</span> <span class="p">{})</span>
        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">langs</span>

    <span class="k">def</span> <span class="nf">translate</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">text</span><span class="p">,</span> <span class="n">to_lang</span><span class="p">,</span> <span class="n">from_lang</span><span class="o">=</span><span class="bp">None</span><span class="p">,</span>
            <span class="n">content_type</span><span class="o">=</span><span class="s">&#39;text/plain&#39;</span><span class="p">):</span>
        <span class="sd">&quot;&quot;&quot;Translates a text string from one language to another.</span>

<span class="sd">        :param text: A string representing the text to translate.</span>
<span class="sd">        :param to_lang: A string representing the language code to</span>
<span class="sd">            translate the text into.</span>
<span class="sd">        :param from_lang: A string representing the language code of the</span>
<span class="sd">            translation text. If left None the response will include the</span>
<span class="sd">            result of language auto-detection. (Default: None)</span>
<span class="sd">        :param content_type: The format of the text being translated.</span>
<span class="sd">            The supported formats are &quot;text/plain&quot; and &quot;text/html&quot;. Any HTML</span>
<span class="sd">            needs to be well-formed.</span>
<span class="sd">        &quot;&quot;&quot;</span>
        <span class="n">params</span> <span class="o">=</span> <span class="p">{</span>
            <span class="s">&#39;text&#39;</span><span class="p">:</span> <span class="n">text</span><span class="o">.</span><span class="n">encode</span><span class="p">(</span><span class="s">&#39;utf8&#39;</span><span class="p">),</span>
            <span class="s">&#39;to&#39;</span><span class="p">:</span> <span class="n">to_lang</span><span class="p">,</span>
            <span class="s">&#39;contentType&#39;</span><span class="p">:</span> <span class="n">content_type</span><span class="p">,</span>
            <span class="s">&#39;category&#39;</span><span class="p">:</span> <span class="s">&#39;general&#39;</span><span class="p">,</span>
            <span class="p">}</span>
        <span class="k">if</span> <span class="n">from_lang</span> <span class="ow">is</span> <span class="ow">not</span> <span class="bp">None</span><span class="p">:</span>
            <span class="n">params</span><span class="p">[</span><span class="s">&#39;from&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">from_lang</span>
        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">call</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">translate_url</span><span class="p">,</span> <span class="n">params</span><span class="p">)</span>

    <span class="k">def</span> <span class="nf">translate_array</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">texts</span><span class="p">,</span> <span class="n">to_lang</span><span class="p">,</span> <span class="n">from_lang</span><span class="o">=</span><span class="bp">None</span><span class="p">,</span> <span class="o">**</span><span class="n">options</span><span class="p">):</span>
        <span class="sd">&quot;&quot;&quot;Translates an array of text strings from one language to another.</span>

<span class="sd">        :param texts: A list containing texts for translation.</span>
<span class="sd">        :param to_lang: A string representing the language code to </span>
<span class="sd">            translate the text into.</span>
<span class="sd">        :param from_lang: A string representing the language code of the </span>
<span class="sd">            translation text. If left None the response will include the </span>
<span class="sd">            result of language auto-detection. (Default: None)</span>
<span class="sd">        :param options: A TranslateOptions element containing the values below. </span>
<span class="sd">            They are all optional and default to the most common settings.</span>

<span class="sd">                Category: A string containing the category (domain) of the </span>
<span class="sd">                    translation. Defaults to &quot;general&quot;.</span>
<span class="sd">                ContentType: The format of the text being translated. The </span>
<span class="sd">                    supported formats are &quot;text/plain&quot; and &quot;text/html&quot;. Any </span>
<span class="sd">                    HTML needs to be well-formed.</span>
<span class="sd">                Uri: A string containing the content location of this </span>
<span class="sd">                    translation.</span>
<span class="sd">                User: A string used to track the originator of the submission.</span>
<span class="sd">                State: User state to help correlate request and response. The </span>
<span class="sd">                    same contents will be returned in the response.</span>
<span class="sd">        &quot;&quot;&quot;</span>
        <span class="n">options</span> <span class="o">=</span> <span class="p">{</span>
            <span class="s">&#39;Category&#39;</span><span class="p">:</span> <span class="s">&quot;general&quot;</span><span class="p">,</span>
            <span class="s">&#39;Contenttype&#39;</span><span class="p">:</span> <span class="s">&quot;text/plain&quot;</span><span class="p">,</span>
            <span class="s">&#39;Uri&#39;</span><span class="p">:</span> <span class="s">&#39;&#39;</span><span class="p">,</span>
            <span class="s">&#39;User&#39;</span><span class="p">:</span> <span class="s">&#39;default&#39;</span><span class="p">,</span>
            <span class="s">&#39;State&#39;</span><span class="p">:</span> <span class="s">&#39;&#39;</span>
            <span class="p">}</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="n">options</span><span class="p">)</span>
        <span class="n">params</span> <span class="o">=</span> <span class="p">{</span>
            <span class="s">&#39;texts&#39;</span><span class="p">:</span> <span class="n">json</span><span class="o">.</span><span class="n">dumps</span><span class="p">(</span><span class="n">texts</span><span class="p">),</span>
            <span class="s">&#39;to&#39;</span><span class="p">:</span> <span class="n">to_lang</span><span class="p">,</span>
            <span class="s">&#39;options&#39;</span><span class="p">:</span> <span class="n">json</span><span class="o">.</span><span class="n">dumps</span><span class="p">(</span><span class="n">options</span><span class="p">),</span>
            <span class="p">}</span>
        <span class="k">if</span> <span class="n">from_lang</span> <span class="ow">is</span> <span class="ow">not</span> <span class="bp">None</span><span class="p">:</span>
            <span class="n">params</span><span class="p">[</span><span class="s">&#39;from&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">from_lang</span>

        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">call</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">translate_array_url</span><span class="p">,</span> <span class="n">params</span><span class="p">)</span>

<span class="k">def</span> <span class="nf">format_date</span><span class="p">():</span>
    <span class="s">&quot;Return a date string in required format&quot;</span>
    <span class="k">return</span> <span class="n">time</span><span class="o">.</span><span class="n">strftime</span><span class="p">(</span><span class="s">&quot;%Y-%m-</span><span class="si">%d</span><span class="s"> %R+0200&quot;</span><span class="p">,</span> <span class="n">time</span><span class="o">.</span><span class="n">strptime</span><span class="p">(</span><span class="n">time</span><span class="o">.</span><span class="n">ctime</span><span class="p">()))</span>

<span class="k">def</span> <span class="nf">first_pass</span><span class="p">(</span><span class="n">items</span><span class="p">,</span> <span class="n">thestring</span><span class="p">):</span>
    <span class="s">&quot;replace </span><span class="si">%(xxx)s</span><span class="s"> vars&quot;</span>
    <span class="k">for</span> <span class="n">item</span> <span class="ow">in</span> <span class="n">items</span><span class="p">:</span>
        <span class="n">thestring</span> <span class="o">=</span> <span class="n">thestring</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="n">item</span><span class="p">,</span> <span class="s">&#39;|^^|&#39;</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>
    <span class="k">return</span> <span class="n">thestring</span>

<span class="k">def</span> <span class="nf">second_pass</span><span class="p">(</span><span class="n">items</span><span class="p">,</span> <span class="n">thestring</span><span class="p">):</span>
    <span class="s">&quot;replace </span><span class="si">%s</span><span class="s"> with actual </span><span class="si">%(xxx)s</span><span class="s">&quot;</span>
    <span class="k">for</span> <span class="n">item</span> <span class="ow">in</span> <span class="n">items</span><span class="p">:</span>
        <span class="n">thestring</span> <span class="o">=</span> <span class="n">thestring</span>\
                    <span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s">&#39;|^^|&#39;</span><span class="p">,</span> <span class="n">item</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>\
                    <span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s">&#39;| ^ ^ |&#39;</span><span class="p">,</span> <span class="n">item</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>
    <span class="k">return</span> <span class="n">thestring</span>

<span class="k">def</span> <span class="nf">getpofs</span><span class="p">(</span><span class="n">matched</span><span class="p">,</span> <span class="n">dirname</span><span class="p">,</span> <span class="n">files</span><span class="p">):</span>
    <span class="s">&quot;utility to get po files&quot;</span>
    <span class="n">matched</span><span class="o">.</span><span class="n">extend</span><span class="p">([</span><span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">dirname</span><span class="p">,</span> <span class="n">filename</span><span class="p">)</span>
                    <span class="k">for</span> <span class="n">filename</span> <span class="ow">in</span> <span class="n">files</span>
                    <span class="k">if</span> <span class="n">filename</span><span class="o">.</span><span class="n">endswith</span><span class="p">(</span><span class="s">&#39;.po&#39;</span><span class="p">)])</span>

<span class="k">def</span> <span class="nf">get_lang</span><span class="p">(</span><span class="n">dirname</span><span class="p">):</span>
    <span class="s">&quot;Get the language from directory name&quot;</span>
    <span class="k">return</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">basename</span><span class="p">(</span>
                <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">dirname</span><span class="p">(</span>
                    <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">dirname</span><span class="p">(</span><span class="n">dirname</span><span class="p">)</span>
                <span class="p">)</span>
            <span class="p">)</span>

<span class="k">def</span> <span class="nf">process</span><span class="p">(</span><span class="n">translator</span><span class="p">,</span> <span class="n">raw_entry</span><span class="p">,</span> <span class="n">language</span><span class="p">,</span> <span class="n">sentry</span><span class="p">,</span> <span class="n">regex</span><span class="p">):</span>
    <span class="s">&quot;Process and Translate the string&quot;</span>
    <span class="n">languages_bidi</span> <span class="o">=</span> <span class="p">[</span><span class="s">&quot;he&quot;</span><span class="p">,</span> <span class="s">&quot;ar&quot;</span><span class="p">,</span> <span class="s">&quot;fa&quot;</span><span class="p">,</span> <span class="s">&quot;yi&quot;</span><span class="p">]</span>
    <span class="n">found</span> <span class="o">=</span> <span class="n">regex</span><span class="o">.</span><span class="n">findall</span><span class="p">(</span><span class="n">raw_entry</span><span class="p">)</span>
    <span class="k">if</span> <span class="n">found</span><span class="p">:</span>
        <span class="k">if</span> <span class="n">language</span> <span class="ow">in</span> <span class="n">languages_bidi</span><span class="p">:</span>
            <span class="k">return</span> <span class="bp">None</span>
        <span class="n">raw_entry</span> <span class="o">=</span> <span class="n">first_pass</span><span class="p">(</span><span class="n">found</span><span class="p">,</span> <span class="n">raw_entry</span><span class="p">)</span>
    <span class="k">if</span> <span class="n">datetime</span><span class="o">.</span><span class="n">datetime</span><span class="o">.</span><span class="n">now</span><span class="p">()</span> <span class="o">&gt;=</span> <span class="n">sentry</span><span class="p">:</span>
        <span class="k">print</span> <span class="s">&quot;Renewing token&quot;</span>
        <span class="n">translator</span><span class="o">.</span><span class="n">get_access_token</span><span class="p">(</span><span class="bp">True</span><span class="p">)</span>
        <span class="n">sentry</span> <span class="o">=</span> <span class="p">(</span><span class="n">datetime</span><span class="o">.</span><span class="n">datetime</span><span class="o">.</span><span class="n">now</span><span class="p">()</span> <span class="o">+</span>
                <span class="n">datetime</span><span class="o">.</span><span class="n">timedelta</span><span class="p">(</span><span class="n">minutes</span><span class="o">=</span><span class="mi">8</span><span class="p">))</span>
    <span class="n">new_entry</span> <span class="o">=</span> <span class="n">translator</span><span class="o">.</span><span class="n">translate</span><span class="p">(</span><span class="n">raw_entry</span><span class="p">,</span> <span class="n">language</span><span class="p">)</span>
    <span class="k">if</span> <span class="n">found</span><span class="p">:</span>
        <span class="n">new_entry</span> <span class="o">=</span> <span class="n">second_pass</span><span class="p">(</span><span class="n">found</span><span class="p">,</span> <span class="n">new_entry</span><span class="p">)</span>
    <span class="k">return</span> <span class="n">new_entry</span>

<span class="k">def</span> <span class="nf">createps</span><span class="p">(</span><span class="n">filename</span><span class="p">,</span> <span class="n">client_id</span><span class="p">,</span> <span class="n">api_key</span><span class="p">,</span> <span class="n">meta</span><span class="p">,</span> <span class="n">default_lang</span><span class="p">):</span>
    <span class="s">&quot;update po file&quot;</span>
    <span class="n">do_save</span> <span class="o">=</span> <span class="bp">False</span>
    <span class="n">trans</span> <span class="o">=</span> <span class="n">Translator</span><span class="p">(</span><span class="n">client_id</span><span class="p">,</span> <span class="n">api_key</span><span class="p">)</span>
    <span class="k">print</span> <span class="s">&quot;Processing: </span><span class="si">%s</span><span class="s">&quot;</span> <span class="o">%</span> <span class="n">filename</span>
    <span class="n">pobj</span> <span class="o">=</span> <span class="n">pofile</span><span class="p">(</span><span class="n">filename</span><span class="p">)</span>
    <span class="n">lang</span> <span class="o">=</span> <span class="n">get_lang</span><span class="p">(</span><span class="n">filename</span><span class="p">)</span>

    <span class="k">if</span> <span class="p">(</span><span class="ow">not</span> <span class="n">lang</span> <span class="ow">in</span> <span class="n">trans</span><span class="o">.</span><span class="n">languages</span><span class="p">()</span> <span class="ow">or</span> <span class="n">lang</span> <span class="o">==</span> <span class="n">default_lang</span><span class="p">)</span> <span class="ow">and</span> <span class="n">lang</span> <span class="o">!=</span> <span class="s">&#39;zh&#39;</span><span class="p">:</span>
        <span class="k">print</span> <span class="s">&quot;Language: </span><span class="si">%s</span><span class="s"> not supported by API&quot;</span> <span class="o">%</span> <span class="n">lang</span>
        <span class="k">return</span>

    <span class="k">try</span><span class="p">:</span>
        <span class="n">match_re</span> <span class="o">=</span> <span class="n">re</span><span class="o">.</span><span class="n">compile</span><span class="p">(</span><span class="s">r&#39;((?:%\([^\W]{1,}\)(?:s|d))|(?:{{\w+}}))&#39;</span><span class="p">)</span>
        <span class="n">sentry</span> <span class="o">=</span> <span class="n">datetime</span><span class="o">.</span><span class="n">datetime</span><span class="o">.</span><span class="n">now</span><span class="p">()</span> <span class="o">+</span> <span class="n">datetime</span><span class="o">.</span><span class="n">timedelta</span><span class="p">(</span><span class="n">minutes</span><span class="o">=</span><span class="mi">8</span><span class="p">)</span>
        <span class="k">if</span> <span class="n">lang</span> <span class="o">==</span> <span class="s">&#39;zh&#39;</span><span class="p">:</span>
            <span class="n">lang</span> <span class="o">=</span> <span class="s">&#39;zh-CHS&#39;</span>
        <span class="k">for</span> <span class="n">entry</span> <span class="ow">in</span> <span class="n">pobj</span><span class="o">.</span><span class="n">untranslated_entries</span><span class="p">():</span>
            <span class="k">try</span><span class="p">:</span>
                <span class="n">msgstr</span> <span class="o">=</span> <span class="n">process</span><span class="p">(</span><span class="n">trans</span><span class="p">,</span> <span class="n">entry</span><span class="o">.</span><span class="n">msgid</span><span class="p">,</span> <span class="n">lang</span><span class="p">,</span> <span class="n">sentry</span><span class="p">,</span> <span class="n">match_re</span><span class="p">)</span>
                <span class="k">if</span> <span class="n">entry</span><span class="o">.</span><span class="n">msgid_plural</span><span class="p">:</span>
                    <span class="k">if</span> <span class="n">msgstr</span><span class="p">:</span>
                        <span class="n">entry</span><span class="o">.</span><span class="n">msgstr_plural</span><span class="p">[</span><span class="s">&#39;0&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">msgstr</span>
                    <span class="n">msgstr_plural</span> <span class="o">=</span> <span class="n">process</span><span class="p">(</span><span class="n">trans</span><span class="p">,</span> <span class="n">entry</span><span class="o">.</span><span class="n">msgid_plural</span><span class="p">,</span>
                                            <span class="n">lang</span><span class="p">,</span> <span class="n">sentry</span><span class="p">,</span> <span class="n">match_re</span><span class="p">)</span>
                    <span class="k">if</span> <span class="n">msgstr_plural</span><span class="p">:</span>
                        <span class="n">entry</span><span class="o">.</span><span class="n">msgstr_plural</span><span class="p">[</span><span class="s">&#39;1&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">msgstr_plural</span>
                <span class="k">else</span><span class="p">:</span>
                    <span class="k">if</span> <span class="n">msgstr</span><span class="p">:</span>
                        <span class="n">entry</span><span class="o">.</span><span class="n">msgstr</span> <span class="o">=</span> <span class="n">msgstr</span>
                <span class="n">do_save</span> <span class="o">=</span> <span class="bp">True</span>
            <span class="k">except</span> <span class="p">(</span><span class="n">TranslateApiException</span><span class="p">,</span> <span class="n">ArgumentOutOfRangeException</span><span class="p">),</span> <span class="n">ermsg</span><span class="p">:</span>
                <span class="k">print</span> <span class="s">&#39;Error occured: </span><span class="si">%s</span><span class="s">&#39;</span> <span class="o">%</span> <span class="nb">str</span><span class="p">(</span><span class="n">ermsg</span><span class="p">)</span>

        <span class="k">if</span> <span class="n">do_save</span><span class="p">:</span>
            <span class="n">pobj</span><span class="o">.</span><span class="n">metadata</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="n">meta</span><span class="p">)</span>
            <span class="n">pobj</span><span class="o">.</span><span class="n">metadata</span><span class="p">[</span><span class="s">&#39;PO-Revision-Date&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">format_date</span><span class="p">()</span>
            <span class="n">pobj</span><span class="o">.</span><span class="n">save</span><span class="p">(</span><span class="n">filename</span><span class="p">)</span>
    <span class="k">except</span> <span class="n">ArgumentException</span><span class="p">,</span> <span class="n">errstr</span><span class="p">:</span>
        <span class="k">print</span> <span class="s">&quot;Access Error: </span><span class="si">%s</span><span class="s">&quot;</span> <span class="o">%</span> <span class="nb">str</span><span class="p">(</span><span class="n">errstr</span><span class="p">)</span>

<span class="k">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="s">&#39;__main__&#39;</span><span class="p">:</span>
    <span class="c"># Run tings mon</span>

    <span class="n">CLIENT_ID</span> <span class="o">=</span> <span class="s">&#39;xxxxx&#39;</span>
    <span class="n">API_KEY</span> <span class="o">=</span> <span class="s">&#39;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx&#39;</span>

    <span class="n">metadata</span> <span class="o">=</span> <span class="p">{</span>
        <span class="s">&#39;Report-Msgid-Bugs-To&#39;</span><span class="p">:</span> <span class="s">&#39;baruwa@lists.baruwa.org&#39;</span><span class="p">,</span>
        <span class="s">&#39;Last-Translator&#39;</span><span class="p">:</span> <span class="s">&#39;Andrew Colin Kissa &lt;andrew@topdog.za.net&gt;&#39;</span><span class="p">,</span>
        <span class="s">&#39;Generated-By&#39;</span><span class="p">:</span> <span class="s">&#39;auto-translate.py 0.0.1&#39;</span><span class="p">,</span>
        <span class="s">&#39;Language-Team&#39;</span><span class="p">:</span> <span class="s">&#39;Baruwa Project&#39;</span><span class="p">,</span>
    <span class="p">}</span>

    <span class="n">usage</span> <span class="o">=</span> <span class="s">&quot;usage: %prog directory&quot;</span>
    <span class="n">parser</span> <span class="o">=</span> <span class="n">OptionParser</span><span class="p">(</span><span class="n">usage</span><span class="p">)</span>
    <span class="n">parser</span><span class="o">.</span><span class="n">add_option</span><span class="p">(</span><span class="s">&#39;-s&#39;</span><span class="p">,</span> <span class="s">&#39;--source&#39;</span><span class="p">,</span> <span class="n">dest</span><span class="o">=</span><span class="s">&quot;source_lang&quot;</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="s">&quot;en&quot;</span><span class="p">)</span>
    <span class="n">opts</span><span class="p">,</span> <span class="n">arguments</span> <span class="o">=</span> <span class="n">parser</span><span class="o">.</span><span class="n">parse_args</span><span class="p">()</span>

    <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">arguments</span><span class="p">)</span> <span class="o">!=</span> <span class="mi">1</span><span class="p">:</span>
        <span class="n">parser</span><span class="o">.</span><span class="n">error</span><span class="p">(</span><span class="s">&quot;Please specify the directory to process&quot;</span><span class="p">)</span>

    <span class="n">directory</span> <span class="o">=</span> <span class="n">arguments</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>

    <span class="k">if</span> <span class="ow">not</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">exists</span><span class="p">(</span><span class="n">directory</span><span class="p">):</span>
        <span class="n">parser</span><span class="o">.</span><span class="n">error</span><span class="p">(</span><span class="s">&quot;Directory: </span><span class="si">%s</span><span class="s"> does not exist&quot;</span> <span class="o">%</span> <span class="n">directory</span><span class="p">)</span>

    <span class="k">try</span><span class="p">:</span>        
        <span class="n">pofiles</span> <span class="o">=</span> <span class="p">[]</span>
        <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">walk</span><span class="p">(</span><span class="n">directory</span><span class="p">,</span> <span class="n">getpofs</span><span class="p">,</span> <span class="n">pofiles</span><span class="p">)</span>
        <span class="n">_</span> <span class="o">=</span> <span class="p">[</span><span class="n">createps</span><span class="p">(</span><span class="n">path</span><span class="p">,</span> <span class="n">CLIENT_ID</span><span class="p">,</span> <span class="n">API_KEY</span><span class="p">,</span> <span class="n">metadata</span><span class="p">,</span> <span class="n">opts</span><span class="o">.</span><span class="n">source_lang</span><span class="p">)</span>
            <span class="k">for</span> <span class="n">path</span> <span class="ow">in</span> <span class="n">pofiles</span><span class="p">]</span>
    <span class="k">except</span> <span class="ne">KeyboardInterrupt</span><span class="p">:</span>
        <span class="k">print</span> <span class="s">&quot;</span><span class="se">\n</span><span class="s">CTRL-C pressed, exiting&quot;</span>
</pre></div>

<h2>Usage</h2>
<p>You need to obtain an access token from the Azure Marketplace instructions can be
found <a href="http://msdn.microsoft.com/en-us/library/hh454950.aspx">here</a></p>
<p>Set the <code>CLIENT_ID</code> and <code>API_KEY</code> variables in the script to the values you
obtain from Azure DataMarket.</p>
<p>Then point the script to the directory containing the <code>PO</code> files you want to translate
and let it do its thing.</p>
<pre><code>/auto-translate.py &lt;directory&gt;
</code></pre>
<h2>Download</h2>
<p>You can download the script from <a href="https://github.com/akissa/auto-translate">github</a></p>]]></content:encoded>
    </item>
    <item>
      <title>Boot into single user mode on various unixes</title>
      <link>http://www.topdog.za.net/2013/01/24/boot-into-single-user-mode-on-various-unixes</link>
      <pubDate>Thu, 24 Jan 2013 07:40:00 SAST</pubDate>
      <category><![CDATA[Sysadmin]]></category>
      <category><![CDATA[Tips]]></category>
      <category><![CDATA[Unix]]></category>
      <category><![CDATA[Linux]]></category>
      <guid isPermaLink="true">http://www.topdog.za.net/2013/01/24/boot-into-single-user-mode-on-various-unixes</guid>
      <description>Boot into single user mode on various unixes</description>
      <content:encoded><![CDATA[<h2>Linux/Grub</h2>
<p>Press <code>a</code> to append to the boot options then add <code>single</code></p>
<pre><code>grub append&gt; ro root=LABEL=/ single
</code></pre>
<h2>Solaris/OpenBoot PROM</h2>
<p>Press <code>L1+a</code> or <code>STOP+a</code> to enter OpenBoot PROM then type</p>
<pre><code>boot -s
</code></pre>
<h2>AIX</h2>
<p>Select <code>maintanance</code> mode from the boot menu or type <code>telinit S</code> on
a running machine</p>
<h2>HP-UX</h2>
<p>Interrupt the boot process when prompted and at the prompt type
<code>boot pri isl</code> to get the ISL prompt that allows you to boot into
single user mode. At the ISL prompt type</p>
<pre><code>ISL&gt; prompt: hpux -iS /stand/vmunix
</code></pre>]]></content:encoded>
    </item>
    <item>
      <title>How to update man keywords database</title>
      <link>http://www.topdog.za.net/2013/01/16/how-to-update-man-keywords-database</link>
      <pubDate>Wed, 16 Jan 2013 07:40:00 SAST</pubDate>
      <category><![CDATA[Centos]]></category>
      <category><![CDATA[Ubuntu]]></category>
      <category><![CDATA[Sysadmin]]></category>
      <category><![CDATA[Unix]]></category>
      <category><![CDATA[RHEL]]></category>
      <category><![CDATA[Linux]]></category>
      <category><![CDATA[Tips]]></category>
      <guid isPermaLink="true">http://www.topdog.za.net/2013/01/16/how-to-update-man-keywords-database</guid>
      <description>How to update man keywords database</description>
      <content:encoded><![CDATA[<p>Man keywords database allow you to search for man pages using keywords,
the database needs to be updated when ever man pages are added or removed.</p>
<p>This is how you do it for various *nix types.</p>
<h2>Debian/Ubuntu/SUSE</h2>
<pre><code>mandb
</code></pre>
<h2>RHEL/CENTOS/SL/Fedora</h2>
<pre><code>makewhatis
</code></pre>
<h2>AIX/Solaris/HP-UX</h2>
<pre><code>catman -w
</code></pre>]]></content:encoded>
    </item>
    <item>
      <title>Strongswan now supports PAM authentication</title>
      <link>http://www.topdog.za.net/2012/11/07/strongswan-now-supports-pam-authentication</link>
      <pubDate>Wed, 07 Nov 2012 07:40:00 SAST</pubDate>
      <category><![CDATA[Centos]]></category>
      <category><![CDATA[Sysadmin]]></category>
      <category><![CDATA[RHEL]]></category>
      <category><![CDATA[Linux]]></category>
      <category><![CDATA[Tips]]></category>
      <category><![CDATA[Security]]></category>
      <category><![CDATA[IPSEC]]></category>
      <guid isPermaLink="true">http://www.topdog.za.net/2012/11/07/strongswan-now-supports-pam-authentication</guid>
      <description>Strongswan now supports PAM authentication</description>
      <content:encoded><![CDATA[<p>Strongswan release 5.0.1 includes a XAuth PAM plugin which
requests username/password XAuth credentials and verifies them
against Pluggable Authentication Modules (PAM).</p>
<p>This plugin is not enabled by default to enable it you need
to add the following to your ./configure options</p>
<pre><code>--enable-xauth-pam
</code></pre>
<p>You do require the pam development headers and libraries on your
build machine to successfully compile.</p>
<h2>System Configuration</h2>
<p>The plugin is configurable in the strongswan.conf file, you are
able to change the pam service that is used for authentication.</p>
<p>By default the login pam service is used for authentication.</p>
<p>I will create a new service called ipsec for demonstration.</p>
<div class="pygments_murphy"><pre>charon {
    plugins{
        xauth-pam {
            pam_service = ipsec
        }
    }
}
</pre></div>

<p>The pam service configuration file is as follows.</p>
<div class="pygments_murphy"><pre>#%PAM-1.0
# /etc/pam.d/ipsec
auth        required      pam_env.so
auth        sufficient    pam_unix.so nullok try_first_pass
auth        requisite     pam_succeed_if.so uid &gt;= 500 quiet
auth        required      pam_deny.so

account     required      pam_unix.so
account     sufficient    pam_localuser.so
account     sufficient    pam_succeed_if.so uid &lt; 500 quiet
account     required      pam_permit.so

password    requisite     pam_cracklib.so try_first_pass retry=3 type=
password    sufficient    pam_unix.so sha512 shadow nullok try_first_pass use_authtok
password    required      pam_deny.so

session     optional      pam_keyinit.so revoke
session     required      pam_limits.so
session     [success=1 default=ignore] pam_succeed_if.so service in crond quiet use_uid
session     required      pam_unix.so
</pre></div>

<p>Now to use PAM authentication in your connections you set for XAuth:</p>
<pre><code>rightauth2=xauth-pam
</code></pre>
<p>Hybrid Authentication:</p>
<pre><code>rightauth=xauth-pam
</code></pre>
<p>You are good to go and should be able to use any pam module to
authenticate your users to your VPN. The options are endless: SQL,
LDAP, RADIUS, LOCAL etc.</p>
<h2>Related articles</h2>
<ul>
<li><a href="http://bit.ly/WABVAZ">Iphone/Ipad/Mac OSX IPSEC VPN with Strongswan 5 on Centos/RHEL 6</a></li>
<li><a href="http://bit.ly/Ujih5I">Mac OSX IPSEC VPN via command line using builtin Racoon client</a></li>
<li><a href="http://bit.ly/SN5z1k">IPSEC split tunneling VPN with Mac OSX and Strongswan 5 on Centos/RHEL 6</a></li>
</ul>]]></content:encoded>
    </item>
    <item>
      <title>Strongswan now supports Cisco unity extensions</title>
      <link>http://www.topdog.za.net/2012/11/07/strongswan-now-supports-cisco-unity-extensions</link>
      <pubDate>Wed, 07 Nov 2012 07:40:00 SAST</pubDate>
      <category><![CDATA[Centos]]></category>
      <category><![CDATA[Sysadmin]]></category>
      <category><![CDATA[RHEL]]></category>
      <category><![CDATA[Linux]]></category>
      <category><![CDATA[Tips]]></category>
      <category><![CDATA[Security]]></category>
      <category><![CDATA[IPSEC]]></category>
      <guid isPermaLink="true">http://www.topdog.za.net/2012/11/07/strongswan-now-supports-cisco-unity-extensions</guid>
      <description>Strongswan now supports Cisco unity extensions</description>
      <content:encoded><![CDATA[<p>I previously <a href="http://bit.ly/OIHOq4">wrote</a> about setting up split
tunneling on Strongswan using the <a href="http://bit.ly/NI7Mpx">attr-sql plugin</a></p>
<p>With the release of Strongswan 5.0.1 it is no longer the only way
to support split tunneling.</p>
<p>Strongswan 5.0.1 introduces the unity plugin which allows for the
configuration of split tunneling either using a charon option or
using the attr plugin which is enabled by default.</p>
<p>The unity plugin is not enabled by default to enable it you need
to add the following to your ./configure options</p>
<pre><code>--enable-unity
</code></pre>
<h2>Charon option</h2>
<p>To enable this option you need to edit the strongswan.conf file
and set</p>
<div class="pygments_murphy"><pre>charon {
    # ... other options
    cisco_unity = yes
    #...
}
</pre></div>

<p>As a client strongswan will install policies only for the received
Split-Include attributes and IPsec bypass policies for received
Local-LAN attributes.</p>
<p>As a server strongswan will send Split-Include attributes for leftsubnet
definitions containing multiple subnets to clients that support the
IKEv1 Cisco Unity Extensions.</p>
<h2>Attr plugin option</h2>
<p>It is also possible to configure split tunneling using the attr plugin.
Two new options have been added:</p>
<ul>
<li>split-include - Comma-separated list of subnets to tunnel</li>
<li>split-exclude - Comma-separated list of subnets not to tunnel</li>
</ul>
<div class="pygments_murphy"><pre>charon {
    # ... other options
    split-include = 192.168.1.0/24, 172.16.0.0/16
    split-exclude = 10.128.0.0/16
    #...
}
</pre></div>

<h2>Related articles</h2>
<ul>
<li><a href="http://bit.ly/WABVAZ">Iphone/Ipad/Mac OSX IPSEC VPN with Strongswan 5 on Centos/RHEL 6</a></li>
<li><a href="http://bit.ly/Ujih5I">Mac OSX IPSEC VPN via command line using builtin Racoon client</a></li>
<li><a href="http://bit.ly/SN5z1k">IPSEC split tunneling VPN with Mac OSX and Strongswan 5 on Centos/RHEL 6</a></li>
</ul>]]></content:encoded>
    </item>
    <item>
      <title>Mac OSX IPSEC VPN via command line using builtin Racoon client</title>
      <link>http://www.topdog.za.net/2012/09/19/mac-osx-ipsec-vpn-via-command-line-using-builtin-racoon-client</link>
      <pubDate>Wed, 19 Sep 2012 07:30:00 SAST</pubDate>
      <category><![CDATA[Mac OS X]]></category>
      <category><![CDATA[Howto]]></category>
      <category><![CDATA[Sysadmin]]></category>
      <category><![CDATA[Linux]]></category>
      <category><![CDATA[Tips]]></category>
      <category><![CDATA[Security]]></category>
      <category><![CDATA[IPSEC]]></category>
      <guid isPermaLink="true">http://www.topdog.za.net/2012/09/19/mac-osx-ipsec-vpn-via-command-line-using-builtin-racoon-client</guid>
      <description>Mac OSX IPSEC VPN via command line using builtin Racoon client</description>
      <content:encoded><![CDATA[<h2>Introduction</h2>
<p>The Mac OSX IPSEC VPN client setup via "System preferences" only supports
IPSEC/XAUTH and IPSEC/L2TP both of which give you a different IP address for
your tunnel interface. System preferences on the backend uses Racoon
so it is possible via the command line to setup a pure IPSEC connection.</p>
<p>In my <a href="http://bit.ly/WABVAZ">previous post</a> i described how to configure a Strongswan server for
use with Mac OSX, Ipad, Iphone clients. For the sake of brevity i will not
repeat that in this post.</p>
<p>This scenario assumes you are connected to a lan 10.128.1.0/24 and your
IP address is 10.128.1.2 and you are connecting to a remote network 
192.168.1.0/24 protected by an IPSEC VPN running Strongswan on a gateway with
a dynamic address being resolved via dynamic DNS.
IPSEC Authentication is done using Certificates.</p>
<h2>Configuration</h2>
<h3>Client configuration.</h3>
<p>Edit /etc/racoon/racoon.conf and add the following to the bottom.</p>
<div class="pygments_murphy"><pre>include &quot;/opt/local/etc/cmdline-ipsec.conf&quot; ;
</pre></div>

<p>Create a configuration template file /opt/local/etc/cmdline-ipsec.conf.tmpl. I am using
a template because the remote side has a dynamic ip address and racoon does
not support DNS names only IP addresses, a custom script resolves the hostname
and then generates an updated racoon configuration from this template file with the
resolved IP address.</p>
<div class="pygments_murphy"><pre>remote %SERVERIP% {
        exchange_mode main;
        ca_type x509 &quot;/opt/local/etc/pki/cacert.pem&quot;;
        certificate_type x509 &quot;/opt/local/etc/pki/example.pem&quot; &quot;/opt/local/etc/pki/example.key.pem&quot;;
        proposal_check obey;
        mode_cfg off;
        dpd_delay 360;
        nat_traversal on;
        my_identifier asn1dn;
        ike_frag on;
        script &quot;/opt/local/bin/phase1-up.sh&quot; phase1_up;
        script &quot;/opt/local/bin/phase1-down.sh&quot; phase1_down;
        lifetime time 24 hour;
        passive off;
        proposal {
                encryption_algorithm aes256;
                hash_algorithm sha512;
                authentication_method rsasig;
                dh_group 2;
       }
}

sainfo anonymous {
        lifetime time 24 hour;
        pfs_group modp2048;
        encryption_algorithm aes256;
        authentication_algorithm hmac_sha1, hmac_sha256, hmac_sha512;
        compression_algorithm deflate ;
}
</pre></div>

<p>Create the phase1 up script /opt/local/bin/phase1-up.sh</p>
<div class="pygments_murphy"><pre><span class="c">#!/bin/sh</span>

<span class="c">#</span>
<span class="c"># sa-up.sh local configuration for a new SA</span>
<span class="c">#</span>
<span class="nv">PATH</span><span class="o">=</span>/bin:/sbin:/usr/bin:/usr/sbin:/opt/local/bin:/opt/local/sbin
<span class="nv">MYIP</span><span class="o">=</span>10.128.1.2
<span class="nv">PROTECTEDNET</span><span class="o">=</span>192.168.1.0/24

<span class="nb">echo</span> <span class="nv">$@</span>
<span class="nb">echo</span> <span class="s2">&quot;LOCAL_ADDR = ${LOCAL_ADDR}&quot;</span>
<span class="nb">echo</span> <span class="s2">&quot;LOCAL_PORT = ${LOCAL_PORT}&quot;</span>
<span class="nb">echo</span> <span class="s2">&quot;REMOTE_ADDR = ${REMOTE_ADDR}&quot;</span>
<span class="nb">echo</span> <span class="s2">&quot;REMOTE_PORT = ${REMOTE_PORT}&quot;</span>

<span class="nv">LOCAL</span><span class="o">=</span><span class="s2">&quot;${LOCAL_ADDR}[${LOCAL_PORT}]&quot;</span>
<span class="nv">REMOTE</span><span class="o">=</span><span class="s2">&quot;${REMOTE_ADDR}[${REMOTE_PORT}]&quot;</span>

<span class="nb">echo</span> <span class="s2">&quot;</span>
<span class="s2">spdadd ${MYIP}/32[any] ${PROTECTEDNET}[any] any</span>
<span class="s2">       -P out ipsec esp/tunnel/${LOCAL}-${REMOTE}/require;</span>
<span class="s2">spdadd ${PROTECTEDNET} ${MYIP}[any] any</span>
<span class="s2">       -P in ipsec esp/tunnel/${REMOTE}-${LOCAL}/require;</span>
<span class="s2">&quot;</span> | setkey -c
</pre></div>

<p>Create the phase1 down script /opt/local/bin/phase1-down.sh</p>
<div class="pygments_murphy"><pre><span class="c">#!/bin/sh</span>

<span class="c">#</span>
<span class="c"># sa-down.sh local remove SA</span>
<span class="c">#</span>

<span class="nv">PATH</span><span class="o">=</span>/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin
<span class="nv">MYIP</span><span class="o">=</span>10.128.1.2
<span class="nv">PROTECTEDNET</span><span class="o">=</span>192.168.1.0/24

<span class="nb">echo</span> <span class="nv">$@</span>
<span class="nb">echo</span> <span class="s2">&quot;LOCAL_ADDR = ${LOCAL_ADDR}&quot;</span>
<span class="nb">echo</span> <span class="s2">&quot;LOCAL_PORT = ${LOCAL_PORT}&quot;</span>
<span class="nb">echo</span> <span class="s2">&quot;REMOTE_ADDR = ${REMOTE_ADDR}&quot;</span>
<span class="nb">echo</span> <span class="s2">&quot;REMOTE_PORT = ${REMOTE_PORT}&quot;</span>

<span class="nv">LOCAL</span><span class="o">=</span><span class="s2">&quot;${LOCAL_ADDR}[${LOCAL_PORT}]&quot;</span>
<span class="nv">REMOTE</span><span class="o">=</span><span class="s2">&quot;${REMOTE_ADDR}[${REMOTE_PORT}]&quot;</span>

<span class="nb">echo</span> <span class="s2">&quot;</span>
<span class="s2">deleteall ${REMOTE_ADDR} ${LOCAL_ADDR} esp;</span>
<span class="s2">deleteall ${LOCAL_ADDR} ${REMOTE_ADDR} esp; </span>
<span class="s2">spddelete ${MYIP}/32[any] ${PROTECTEDNET}[any] any</span>
<span class="s2">        -P out ipsec esp/tunnel/${LOCAL}-${REMOTE}/require;</span>
<span class="s2">spddelete ${PROTECTEDNET}[any] ${MYIP}[any] any</span>
<span class="s2">        -P in ipsec esp/tunnel/${REMOTE}-${LOCAL}/require;</span>
<span class="s2">&quot;</span> | setkey -c
</pre></div>

<p>Create the custom start script /opt/local/sbin/start-vpn</p>
<div class="pygments_murphy"><pre><span class="c">#!/bin/bash</span>
<span class="c">#</span>
<span class="c">#</span>
<span class="nv">SERVERNAME</span><span class="o">=</span><span class="s2">&quot;strongswan-example.dyndns.org&quot;</span>
<span class="nv">SERVERIP</span><span class="o">=</span><span class="k">$(</span>host <span class="nv">$SERVERNAME</span>|awk <span class="s1">&#39;{print $4}&#39;</span><span class="k">)</span>
<span class="nv">status</span><span class="o">=</span><span class="k">$(</span>racoonctl show-sa isakmp|wc -l|awk <span class="s1">&#39;{print $1}&#39;</span><span class="k">)</span>
<span class="k">if</span> <span class="o">[</span> <span class="s2">&quot;$status&quot;</span> !<span class="o">=</span> <span class="s2">&quot;2&quot;</span> <span class="o">]</span>; <span class="k">then</span>
<span class="k">   </span><span class="nb">echo</span> <span class="s2">&quot;Not connected, starting conn&quot;</span>
   sed -e <span class="s2">&quot;s:%SERVERIP%:${SERVERIP}:&quot;</span> <span class="se">\</span>
   /opt/local/etc/cmdline-ipsec.conf.tmpl &gt; /opt/local/etc/cmdline-ipsec.conf
   racoonctl reload-config
   racoonctl vpn-connect <span class="nv">$SERVERIP</span>
<span class="k">else</span>
<span class="k">   </span>racoonctl show-sa isakmp
   <span class="nb">echo</span> <span class="s2">&quot;Already connect, exiting&quot;</span>
<span class="k">fi</span>
</pre></div>

<p>Make the script executable</p>
<pre><code>chmod +x /opt/local/sbin/start-vpn
</code></pre>
<h3>Server configuration</h3>
<p>Update the ipsec.conf configuration from my previous post to add the following
conn</p>
<div class="pygments_murphy"><pre>conn rw
        leftcert=vpn.example.org.pem
        leftid=@vpn.example.org
        leftfirewall=yes
        right=%any
        rightsubnet=0.0.0.0/0
        rekey=yes
</pre></div>

<h2>Testing</h2>
<p>Open a command prompt and run the command, as root or using sudo.</p>
<pre><code>start-vpn
</code></pre>
<p>You should be able to connect to hosts on the protected network (192.168.1.0/24)</p>
<p>To stop the connection run the command.</p>
<pre><code>racoonctl vpn-disconnect strongswan-example.dyndns.org
</code></pre>
<h2>Related articles</h2>
<ul>
<li><a href="http://bit.ly/SN5z1k">IPSEC split tunneling VPN with Mac OSX and Strongswan 5 on Centos/RHEL 6</a></li>
<li><a href="http://bit.ly/WABVAZ">Iphone/Ipad/Mac OSX IPSEC VPN with Strongswan 5 on Centos/RHEL 6</a></li>
</ul>]]></content:encoded>
    </item>
    <item>
      <title>MailScanner Ubuntu and Debian packages</title>
      <link>http://www.topdog.za.net/2012/09/10/mailscanner-ubuntu-and-debian-packages</link>
      <pubDate>Mon, 10 Sep 2012 07:39:00 SAST</pubDate>
      <category><![CDATA[Sysadmin]]></category>
      <category><![CDATA[Security]]></category>
      <category><![CDATA[Email]]></category>
      <category><![CDATA[Linux]]></category>
      <guid isPermaLink="true">http://www.topdog.za.net/2012/09/10/mailscanner-ubuntu-and-debian-packages</guid>
      <description>MailScanner Ubuntu and Debian packages</description>
      <content:encoded><![CDATA[<p>The Debian and Ubuntu MailScanner packages have not been maintained for a long time.
Recently both distributions dropped support for MailScanner within their repo's.</p>
<p>The <a href="http://bit.ly/UE4N6D">Baruwa project</a> provides up to date deb packages for both
distributions.</p>
<p>Packages are available for:</p>
<ul>
<li>squeeze</li>
<li>wheezy</li>
<li>sid</li>
<li>lucid</li>
<li>maverick</li>
<li>natty</li>
<li>oneiric</li>
<li>precise</li>
<li>quantal</li>
</ul>
<h2>Usage</h2>
<p>To use the packages you need to enable the baruwa apt repo.</p>
<pre><code>cat &gt; /etc/apt/sources.list.d/baruwa.list &lt;&lt; 'EOF'
deb http://apt.baruwa.org/ubuntu precise main
EOF
</code></pre>
<p><strong>Change "precise" to your specific release name</strong></p>
<p>Add the repo's GPG key</p>
<pre><code>wget -O - http://apt.baruwa.org/baruwa-apt-keys.gpg | apt-key add -
</code></pre>
<p>Then run</p>
<pre><code>apt-get update
apt-get install mailscanner
</code></pre>
<h2>Support &amp; Assistance</h2>
<p>Use the friendly Baruwa project <a href="http://bit.ly/Rwj1I4">mailing list</a> </p>]]></content:encoded>
    </item>
    <item>
      <title>IPSEC split tunneling VPN with Mac OSX and Strongswan 5 on Centos/RHEL 6</title>
      <link>http://www.topdog.za.net/2012/09/01/ipsec-split-tunneling-vpn-with-mac-osx-and-strongswan-5-on-centos-rhel-6</link>
      <pubDate>Sat, 01 Sep 2012 10:08:00 SAST</pubDate>
      <category><![CDATA[Centos]]></category>
      <category><![CDATA[Mac OS X]]></category>
      <category><![CDATA[Howto]]></category>
      <category><![CDATA[Sysadmin]]></category>
      <category><![CDATA[RHEL]]></category>
      <category><![CDATA[Linux]]></category>
      <category><![CDATA[Tips]]></category>
      <category><![CDATA[Security]]></category>
      <category><![CDATA[IPSEC]]></category>
      <guid isPermaLink="true">http://www.topdog.za.net/2012/09/01/ipsec-split-tunneling-vpn-with-mac-osx-and-strongswan-5-on-centos-rhel-6</guid>
      <description>IPSEC split tunneling VPN with Mac OSX and Strongswan 5 on Centos/RHEL 6</description>
      <content:encoded><![CDATA[<h2>Introduction</h2>
<p>In my <a href="http://bit.ly/WABVAZ">previous post</a> i described how to setup an IPSEC VPN for use with Iphone,
Ipad and Mac OSX IPSEC VPN clients.</p>
<p>This post describes how to enable split tunneling which is supported by the
Mac OSX IPSEC client. Although split tunneling is considered insecure there
are cases where it is ideal to run split tunnels.</p>
<p>The scenario for this post is that you are connected to a LAN (10.128.0.0/24) with
internet access via a gateway on the LAN, you want to connect to a different
network 192.168.1.0/24 which is only accessible via VPN, but you want to retain
access to resources on the LAN while accessing the remote 192.168.1.0/24 network.</p>
<p>To follow this howto you need to have strongswan rpm with the <a href="http://bit.ly/NI7Mpx">attr-sql plugin</a>
enabled with a <a href="http://bit.ly/R5d4f8">sqlite</a> or <a href="http://bit.ly/R5d4f8">mysql</a> backed plugin enabled.
The <a href="http://bit.ly/NCWf0x">EPEL rpm</a> does not support these features at the time of writing. You need to build your own
custom strongswan rpm. You can download my <a href="http://bit.ly/OP75xw">spec file</a> and use it to build 
yourself the rpm.</p>
<h2>Installation</h2>
<p>Install the rpm</p>
<pre><code>rpm -Uvh strongswan-5.0.0-5.el6.x86_64.rpm
</code></pre>
<h2>Configuration</h2>
<p>Use the following configuration files, if you installation is new refer to
my <a href="http://bit.ly/WABVAZ">previous post</a> on how to create the certificates</p>
<h3>Create strongswan configuration</h3>
<p>This strongswan configuration allows you to use both certificates and pre shared
keys.</p>
<p>Add the username and password to /etc/strongswan/ipsec.secrets</p>
<div class="pygments_murphy"><pre>andrew : XAUTH &quot;5tr0ngp4ss0rd&quot;
</pre></div>

<p>Add the preshared key to /etc/strongswan/ipsec.secrets</p>
<div class="pygments_murphy"><pre>: PSK &quot;very long pre shared key difficlult to guess&quot;
</pre></div>

<p>Edit /etc/strongswan/ipsec.conf with the following content.</p>
<div class="pygments_murphy"><pre>config setup

conn %default
        ikelifetime=60m
        keylife=20m
        rekeymargin=3m
        keyingtries=1
        keyexchange=ikev1
        left=%defaultroute
        leftsubnet=192.168.1.0/24
        esp=aes256-sha256-modp2048,aes256-sha1!
        ike=aes256-sha1-modp1536,aes256-sha512-modp1024,aes256-sha1-modp1024!
        auto=add

conn rw-xauth
        leftcert=vpn.example.org.pem
        leftid=@vpn.example.org
        leftauth=pubkey
        leftfirewall=yes
        right=%any
        rightauth=pubkey
        rightauth2=xauth
        rightsourceip=%vpnclients
        rekey=yes

conn rw-xauth-psk
        leftfirewall=yes
        leftauth=psk
        right=%any
        rightauth=psk
        rightauth2=xauth
        rightsourceip=%vpnclients
        rekey=yes
</pre></div>

<p>Add the attr-sql plugin configuration to /etc/strongswan/strongswan.conf</p>
<div class="pygments_murphy"><pre>libhydra {
        plugins {
                attr-sql {
                        database = sqlite:///var/lib/strongswan/ipsec.db
                }
        }
}
</pre></div>

<h3>Restart the service</h3>
<p>Restart the service for the configurations to take effect.</p>
<pre><code>service strongswan restart
</code></pre>
<h3>Create sql attr Database</h3>
<p>Create a sqlite database to store the pool information.</p>
<pre><code>wget http://bit.ly/PyMe08
cat sqlite.sql | sqlite3 /var/lib/strongswan/ipsec.db
</code></pre>
<h3>Create a database based pool</h3>
<p>The pool will store the address range, the split tunnel network (192.168.1.0/24),
dns server to assign and a banner.</p>
<pre><code>strongswan pool --add vpnclients --start 192.168.2.0 --end 192.168.2.254 --timeout 48
strongswan pool --addattr dns --server 192.168.1.1 --pool vpnclients
strongswan pool --addattr unity_def_domain --string "example.org" --pool vpnclients
strongswan pool --addattr banner --string "example.org - all activity is monitored" --pool vpnclients
strongswan pool --addattr unity_split_include --subnet "192.168.1.0/255.255.255.0" --pool vpnclients
</code></pre>
<h2>Testing</h2>
<p>Configure your Mac OSX VPN client.</p>
<ul>
<li>Launch System preferences then select <strong>Network</strong> &gt; <strong>+</strong> &gt; <strong>Interface &gt; VPN</strong> &gt; <strong>VPN Type &gt; Cisco IPSEC</strong> &gt; <strong>Create</strong></li>
</ul>
<p>Set the Fields</p>
<pre><code>Description      Strongswan-IPSEC
Server           vpn.example.org
Account          andrew
Password         5tr0ngp4ss0rd
Use Certificate  ON
Certificate      name.example.org
</code></pre>
<p>Now when you connect, you will remain connected to your LAN as well as the remote network 10.128.0.0/24
if you run netstat -rn you will see the 10.128.0.0/24 network being routed via the tunnel interface.</p>
<h2>Related articles</h2>
<ul>
<li><a href="http://bit.ly/WABVAZ">Iphone/Ipad/Mac OSX IPSEC VPN with Strongswan 5 on Centos/RHEL 6</a></li>
<li><a href="http://bit.ly/Ujih5I">Mac OSX IPSEC VPN via command line using builtin Racoon client</a></li>
</ul>]]></content:encoded>
    </item>
    <item>
      <title>Iphone/Ipad/Mac OSX IPSEC VPN with Strongswan 5 on Centos/RHEL 6</title>
      <link>http://www.topdog.za.net/2012/08/23/iphone-ipad-mac-osx-ipsec-vpn-with-strongswan-5-on-centos-rhel-6</link>
      <pubDate>Thu, 23 Aug 2012 10:21:00 SAST</pubDate>
      <category><![CDATA[Centos]]></category>
      <category><![CDATA[Mac OS X]]></category>
      <category><![CDATA[Howto]]></category>
      <category><![CDATA[Sysadmin]]></category>
      <category><![CDATA[RHEL]]></category>
      <category><![CDATA[Linux]]></category>
      <category><![CDATA[Tips]]></category>
      <category><![CDATA[Security]]></category>
      <category><![CDATA[IPSEC]]></category>
      <guid isPermaLink="true">http://www.topdog.za.net/2012/08/23/iphone-ipad-mac-osx-ipsec-vpn-with-strongswan-5-on-centos-rhel-6</guid>
      <description>Iphone/Ipad/Mac OSX IPSEC VPN with Strongswan 5 on Centos/RHEL 6</description>
      <content:encoded><![CDATA[<h2>Introduction</h2>
<p>This howto describes setting up an IPSEC VPN for use with the Iphone, Ipad and
Mac OSX VPN clients on Centos/RHEL 6. I am using the 5.x branch of Strongswan
which is now the mainline actively maintained branch. At the time of writing the
5.x EPEL package was only available in the testing repo.</p>
<p>The configuration should work both with NAT and without NAT on both sides, if
you are NATing on the server side make sure your forward UDP 500 and 4500 to
the machine running strongswan.</p>
<p>This howto uses example.org and 192.168.1.0/24 and 192.168.2.0/24 networks for
illustration purposes, you need to change these to suit your own setup.</p>
<h2>Install</h2>
<p>To access the EPEL packages you need to <a href="https://fedoraproject.org/wiki/EPEL/FAQ#howtouse">enable</a> the EPEL repo.
You are then able to install the strongswan package.</p>
<pre><code>yum install --enablerepo=epel-testing strongswan
</code></pre>
<p>Create the required configuration directories</p>
<pre><code>mkdir -p /etc/strongswan/ipsec.d/{aacerts,acerts,cacerts,certs,crls,ocspcerts,private}
</code></pre>
<h2>Configuration</h2>
<h3>Create a CA</h3>
<p>For RSA authentication you need to setup a CA which will issue the certificates to be
used by the server and the clients.</p>
<pre><code>cd /etc/pki/tls/misc
./CA -newca
echo 00 &gt; /etc/pki/CA/crlnumber
openssl ca -gencrl -out /etc/pki/CA/crl.pem
</code></pre>
<p>Install to strongswan directories</p>
<pre><code>ln -s /etc/pki/CA/cacert.pem /etc/strongswan/ipsec.d/cacerts/
ln -s /etc/pki/CA/crl.pem /etc/strongswan/ipsec.d/crls/
</code></pre>
<h3>Create the server certificate</h3>
<p>Apple clients require that the servers certificate subjectAltName attribute contain either
the server IP address or server DNS name. To ensure the server certificate contains the
subjectAltName attribute edit the openssl.cnf and set it under the [ usr_cert ] section</p>
<p>For DNS name set it to</p>
<div class="pygments_murphy"><pre>subjectAltName=DNS:vpn.example.org
</pre></div>

<p>For IP address set it to</p>
<div class="pygments_murphy"><pre>subjectAltName=IP:192.168.1.1
</pre></div>

<p>Now generate and sign the server certitifcate</p>
<pre><code>./CA -newreq
./CA -sign
</code></pre>
<p>Install to strongswan directories.</p>
<pre><code>mv newcert.pem /etc/strongswan/ipsec.d/certs/vpn.example.org.pem
mv newkey.pem /etc/strongswan/ipsec.d/private/vpn.example.org.key
</code></pre>
<p>Add the private key password to /etc/strongswan/ipsec.secrets</p>
<div class="pygments_murphy"><pre>: RSA vpn.example.org.key &quot;p4ssw0rd&quot;
</pre></div>

<h3>Create the client certificate</h3>
<p>This is the certificate that will be used by you VPN clients ie Ipad/Iphone, edit the openssl.cnf
and comment out the subjectAltName attribute setting.</p>
<p>Now generate and sign the client certificate, do this for all the clients you expect to use.</p>
<pre><code>./CA -newreq
./CA -sign
openssl pkcs12 -export -in ipad.example.org.pem -inkey ipad.example.org.key \
 -certfile /etc/pki/CA/cacert.pem -out ipad.p12
</code></pre>
<p>You now need to import the CA certificate and the client p12 certificate on to the device. You
need to download the <a href="https://support.apple.com/kb/DL1465">Iphone configuration utility</a> and
use it to import the certificates to your device.</p>
<p><img alt="Iphone configuration utility;" src="/imgs/iphone-config.png" /></p>
<p>Add the username and password to /etc/strongswan/ipsec.secrets</p>
<div class="pygments_murphy"><pre>andrew : XAUTH &quot;5tr0ngp4ss0rd&quot;
</pre></div>

<h3>Create strongswan configuration</h3>
<p>Edit /etc/strongswan/ipsec.conf with the following content.</p>
<div class="pygments_murphy"><pre>config setup

conn %default
        ikelifetime=60m
        keylife=20m
        rekeymargin=3m
        keyingtries=1
        keyexchange=ikev1
        left=%defaultroute
        leftsubnet=192.168.1.0/24
        auto=add

conn rw-xauth
        leftcert=vpn.example.org.pem
        leftid=@vpn.example.org
        leftauth=pubkey
        leftfirewall=yes
        right=%any
        rightauth=pubkey
        rightauth2=xauth
        rightsourceip=192.168.2.0/24
</pre></div>

<p>The above setup assumes the network behind the vpn is 192.168.1.0/24 and virtual IP addresses will
be assigned to VPN clients from the 192.168.2.0/24 network block.</p>
<h3>Enable packet forwarding</h3>
<p>If your system is not setup for packet forwarding enable it.</p>
<pre><code>echo 1 &gt; /proc/sys/net/ipv4/ip_forward
</code></pre>
<p>Edit /etc/sysctl.conf and set</p>
<div class="pygments_murphy"><pre>net.ipv4.ip_forward = 1
</pre></div>

<h2>Testing</h2>
<p>Start strongswan.</p>
<pre><code>service strongswan start
</code></pre>
<p>Check /var/log/messages and /var/log/secure for any errors.</p>
<h3>Ipad configuration</h3>
<ul>
<li>Launch Settings then select <strong>General</strong> &gt; <strong>Network</strong> &gt; <strong>VPN</strong> &gt; <strong>Add VPN Configuration</strong></li>
<li>Toggle <strong>VPN</strong> type to <strong>IPSec</strong></li>
</ul>
<p>Set the Fields</p>
<pre><code>Description      Strongswan-IPSEC
Server           vpn.example.org
Account          andrew
Password         5tr0ngp4ss0rd
Use Certificate  ON
Certificate      ipad.example.org
</code></pre>
<p>A VPN connection should now be possible by toggling <strong>VPN</strong> to <strong>ON</strong> under <strong>Settings</strong> &gt; <strong>VPN</strong>.</p>
<h2>Related articles</h2>
<ul>
<li><a href="http://bit.ly/SN5z1k">IPSEC split tunneling VPN with Mac OSX and Strongswan 5 on Centos/RHEL 6</a></li>
<li><a href="http://bit.ly/Ujih5I">Mac OSX IPSEC VPN via command line using builtin Racoon client</a></li>
</ul>]]></content:encoded>
    </item>
    <item>
      <title>Fix Bind error (broken trust chain) resolving</title>
      <link>http://www.topdog.za.net/2012/08/22/fix-bind-error--broken-trust-chain--resolving</link>
      <pubDate>Wed, 22 Aug 2012 20:21:00 SAST</pubDate>
      <category><![CDATA[Tips]]></category>
      <category><![CDATA[RHEL]]></category>
      <category><![CDATA[Centos]]></category>
      <category><![CDATA[DNS]]></category>
      <category><![CDATA[Linux]]></category>
      <guid isPermaLink="true">http://www.topdog.za.net/2012/08/22/fix-bind-error--broken-trust-chain--resolving</guid>
      <description>Fix Bind error (broken trust chain) resolving</description>
      <content:encoded><![CDATA[<p>This Bind named issue results in queries failing and log messages
such as the following being logged</p>
<pre><code>error (no valid KEY) resolving 'dlv.isc.org/DNSKEY/IN': 156.154.101.23#53
error (broken trust chain) resolving './NS/IN': 193.0.14.129#53
</code></pre>
<p>The issue is caused by the date on the system falling out of sync, which
causes DLV validation to fail.</p>
<p>This issue can be fixed by doing the following on Centos / RHEL.</p>
<pre><code>ntpdate ntp.pool.org
hwclock --systohc
rm /var/named/dynamic/managed-keys.bind*
service named restart
</code></pre>
<p>Name resolution so now work without any issues.</p>]]></content:encoded>
    </item>
  </channel>
</rss>
