<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="https://blog.arnonerba.com/feed.xml" rel="self" type="application/atom+xml" /><link href="https://blog.arnonerba.com/" rel="alternate" type="text/html" /><updated>2026-03-11T06:14:24+00:00</updated><id>https://blog.arnonerba.com/feed.xml</id><title type="html">Arnon on Technology</title><subtitle>The assorted musings of a professional sysadmin. All opinions and content are my own.</subtitle><author><name>Arnon Erba</name><email>arnon at arnon erba dot com</email></author><entry><title type="html">Adding Custom CSS to Minima v3 on GitHub Pages</title><link href="https://blog.arnonerba.com/2026/02/custom-css-minima-v3" rel="alternate" type="text/html" title="Adding Custom CSS to Minima v3 on GitHub Pages" /><published>2026-02-21T00:00:00+00:00</published><updated>2026-02-21T00:00:00+00:00</updated><id>https://blog.arnonerba.com/2026/02/custom-css-minima-v3</id><content type="html" xml:base="https://blog.arnonerba.com/2026/02/custom-css-minima-v3"><![CDATA[<p>At the moment, I’m hosting <a href="/2025/12/starting-again">the current iteration of my blog</a> on <a href="https://pages.github.com/">GitHub Pages</a>, and I’m using Jekyll’s default <a href="https://github.com/jekyll/minima">Minima</a> theme for simplicity. Using the method described in this post, I’ve added some custom CSS to refine Minima’s appearance.</p>

<h2 id="using-custom-stylesscss">Using custom-styles.scss</h2>

<p>Minima v3 provides a built-in method for adding your own custom CSS. All you have to do is create a file at <code class="language-plaintext highlighter-rouge">_sass/minima/custom-styles.scss</code>, relative to the root of your Git repository. Any CSS you add to this file will augment – or override – Minima’s default styles.</p>

<p>If you want to add Sass variables and mixins, there’s a file for that, too: <code class="language-plaintext highlighter-rouge">_sass/minima/custom-variables.scss</code>.</p>

<p>Here’s an excerpt from the <a href="https://github.com/jekyll/minima?tab=readme-ov-file#customizing-templates">“customizing templates” section of Minima’s README</a> that explains exactly how these override files are meant to be used:</p>
<blockquote>
  <p>To have your CSS overrides [remain] in sync with upstream changes released in future versions, you can collect all your overrides for the Sass variables and mixins inside a sass file placed at <code class="language-plaintext highlighter-rouge">_sass/minima/custom-variables.scss</code> and all other overrides inside a sass file placed at path <code class="language-plaintext highlighter-rouge">_sass/minima/custom-styles.scss</code>.</p>
</blockquote>

<h2 id="bonus-section-minima-v2-versus-v3">Bonus Section: Minima v2 Versus v3</h2>

<p>At the time of this writing, GitHub Pages still uses Minima v2 by default. This is important, since Minima v3 (which hasn’t yet been officially released) includes several non-backwards-compatible changes, including what’s discussed in this post. Adding custom CSS to Minima v2 is totally different.</p>

<p>If you want to use Minima v3 on GitHub Pages – like I’ve done on this site – you have to load the theme in via the <a href="https://github.com/benbalter/jekyll-remote-theme">jekyll-remote-theme</a> plugin. This can be accomplished with a single line in your site’s <code class="language-plaintext highlighter-rouge">_config.yml</code> file:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>remote_theme: "jekyll/minima"
</code></pre></div></div>]]></content><author><name>Arnon Erba</name></author><summary type="html"><![CDATA[At the moment, I’m hosting the current iteration of my blog on GitHub Pages, and I’m using Jekyll’s default Minima theme for simplicity. Using the method described in this post, I’ve added some custom CSS to refine Minima’s appearance.]]></summary></entry><entry><title type="html">Enabling Duo Unix on Ubuntu With a PAM Profile &amp;amp; pam-auth-update</title><link href="https://blog.arnonerba.com/2026/01/duo-unix-ubuntu-pam-auth-update" rel="alternate" type="text/html" title="Enabling Duo Unix on Ubuntu With a PAM Profile &amp;amp; pam-auth-update" /><published>2026-01-29T00:00:00+00:00</published><updated>2026-01-29T00:00:00+00:00</updated><id>https://blog.arnonerba.com/2026/01/duo-unix-ubuntu-pam-auth-update</id><content type="html" xml:base="https://blog.arnonerba.com/2026/01/duo-unix-ubuntu-pam-auth-update"><![CDATA[<p>Enabling <a href="https://duo.com/docs/duounix">Duo Unix</a> on Ubuntu involves integrating the <code class="language-plaintext highlighter-rouge">pam_duo</code> module into your system’s <a href="https://en.wikipedia.org/wiki/Pluggable_Authentication_Module">Pluggable Authentication Modules (PAM)</a> stack. This can be done by manually editing the files in <code class="language-plaintext highlighter-rouge">/etc/pam.d/</code>, but Ubuntu provides a safer way to do this in the form of <code class="language-plaintext highlighter-rouge">pam-auth-update</code> and its associated PAM config framework.</p>

<h2 id="ubuntus-pam-config-framework">Ubuntu’s PAM Config Framework</h2>

<p>The <a href="https://manpages.ubuntu.com/manpages/noble/en/man8/pam-auth-update.8.html">pam-auth-update</a> script and its associated <a href="https://wiki.ubuntu.com/PAMConfigFrameworkSpec">PAMConfigFrameworkSpec</a> were <a href="https://raphaelhertzog.com/2011/05/06/people-behind-debian-steve-langasek-release-wizard/">originally written by Steve Langasek</a><sup id="fnref:1" role="doc-noteref"><a href="#fn:1" class="footnote" rel="footnote">1</a></sup> and were added to Debian and its derivatives in 2008<sup id="fnref:2" role="doc-noteref"><a href="#fn:2" class="footnote" rel="footnote">2</a></sup>.</p>

<p>The spec page linked above is the best online resource for understanding this framework that I am aware of, but I’ll provide a brief summary here:</p>
<ol>
  <li>Packages – or enterprising administrators – can install custom PAM profiles into <code class="language-plaintext highlighter-rouge">/usr/share/pam-configs/</code>. This allows packages to specify how their PAM modules should be integrated into the system PAM stack.</li>
  <li>Once installed, these custom PAM profiles can be enabled or disabled with the <code class="language-plaintext highlighter-rouge">pam-auth-update</code> script.</li>
  <li>When PAM profiles are enabled or disabled, <code class="language-plaintext highlighter-rouge">pam-auth-update</code> modifies the system-wide PAM configuration files at <code class="language-plaintext highlighter-rouge">/etc/pam.d/common-*</code> accordingly.</li>
  <li>The script can be run interactively by an administrator or non-interactively by configuration management tools or package maintainer scripts.</li>
</ol>

<h2 id="pam-basics">PAM Basics</h2>

<p>First, let’s review some PAM basics. As described in the <a href="https://manpages.ubuntu.com/manpages/noble/en/man5/pam.d.5.html">man page for pam.d</a>, there are four types of PAM modules:</p>
<ol>
  <li>
    <p><strong>account</strong></p>

    <blockquote>
      <p>this module type performs non-authentication based account management. It is typically used to restrict/permit access to a service based on the time of day, currently available system resources (maximum number of users) or perhaps the location of the applicant user – ‘root’ login only on the console.</p>
    </blockquote>
  </li>
  <li>
    <p><strong>auth</strong></p>

    <blockquote>
      <p>this module type provides two aspects of authenticating the user. Firstly, it establishes that the user is who they claim to be, by instructing the application to prompt the user for a password or other means of identification. Secondly, the module can grant group membership or other privileges through its credential granting properties.</p>
    </blockquote>
  </li>
  <li>
    <p><strong>password</strong></p>

    <blockquote>
      <p>this module type is required for updating the authentication token associated with the user. Typically, there is one module for each ‘challenge/response’ based authentication (auth) type.</p>
    </blockquote>
  </li>
  <li>
    <p><strong>session</strong></p>

    <blockquote>
      <p>this module type is associated with doing things that need to be done for the user before/after they can be given service. Such things include the logging of information concerning the opening/closing of some data exchange with a user, mounting directories, etc.</p>
    </blockquote>
  </li>
</ol>

<p>The PAM module for Duo Unix falls into the <code class="language-plaintext highlighter-rouge">auth</code> management group, so, for the purposes of this post, that’s the only relevant module type.</p>

<h2 id="ubuntus-system-wide-pam-configuration">Ubuntu’s System-Wide PAM Configuration</h2>

<p>Ubuntu provides five system-wide PAM configuration files in <code class="language-plaintext highlighter-rouge">/etc/pam.d</code> that correspond to these four types of PAM modules and are designed to be included by services that rely on PAM, such as <code class="language-plaintext highlighter-rouge">sshd</code> and <code class="language-plaintext highlighter-rouge">sudo</code>:</p>
<ol>
  <li><code class="language-plaintext highlighter-rouge">/etc/pam.d/common-account</code>: Authorization settings common to all services.</li>
  <li><code class="language-plaintext highlighter-rouge">/etc/pam.d/common-auth</code>: Authentication settings common to all services.</li>
  <li><code class="language-plaintext highlighter-rouge">/etc/pam.d/common-password</code>: Password-related modules common to all services.</li>
  <li><code class="language-plaintext highlighter-rouge">/etc/pam.d/common-session</code>: Session-related modules common to all services.</li>
  <li><code class="language-plaintext highlighter-rouge">/etc/pam.d/common-session-noninteractive</code>: Session-related modules common to all non-interactive services.</li>
</ol>

<p>These are the files that <code class="language-plaintext highlighter-rouge">pam-auth-update</code> manages. For context, our PAM profile for Duo Unix will only affect <code class="language-plaintext highlighter-rouge">/etc/pam.d/common-auth</code>.</p>

<p>With all this in mind, we can move on to writing the profile.</p>

<h2 id="writing-the-pam-profile">Writing the PAM Profile</h2>

<p>Here is the PAM profile I’ve come up with for Duo Unix:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Name: Duo two-factor authentication
Default: no
Priority: 128
Auth-Type: Additional
Auth:
	required	/usr/lib64/security/pam_duo.so
</code></pre></div></div>

<p>The table below describes what each individual field does and explains why I chose the options I did:</p>

<table>
  <thead>
    <tr>
      <th>Field</th>
      <th>Description</th>
      <th>Justification</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">Name</code></td>
      <td>A human-readable string that’s displayed when <code class="language-plaintext highlighter-rouge">pam-auth-update</code> is run in interactive mode.</td>
      <td>This can be anything that makes sense to you.</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">Default</code></td>
      <td>Whether the profile should be enabled by default.</td>
      <td>For the purposes of this post, this is irrelevant, since we’re not providing this profile as part of a package.</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">Priority</code></td>
      <td>Where to insert this module in the relevant system-wide PAM configuration file. Higher-priority modules will be listed earlier in the file.</td>
      <td>I’ve chosen <code class="language-plaintext highlighter-rouge">128</code> based on the <a href="https://wiki.ubuntu.com/PAMConfigFrameworkSpec">framework spec page</a> and on the choices made by other packages. <br /><br /> <strong>Note:</strong> This value depends on the value of <code class="language-plaintext highlighter-rouge">Auth-Type</code> below, since priorities are evaluated separately for the <code class="language-plaintext highlighter-rouge">Primary</code> and <code class="language-plaintext highlighter-rouge">Additional</code> sections!</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">Auth-Type</code></td>
      <td>This field supports two options, <code class="language-plaintext highlighter-rouge">Primary</code> and <code class="language-plaintext highlighter-rouge">Additional</code>, that correspond to separate sections in the aforementioned system-wide PAM configuration files. <br /><br /> The <code class="language-plaintext highlighter-rouge">Primary</code> section is intended for modules where the success of any one module indicates an overall success, such as when <code class="language-plaintext highlighter-rouge">pam_unix.so</code> and <code class="language-plaintext highlighter-rouge">pam_sss.so</code> are enabled simultaneously<sup id="fnref:3" role="doc-noteref"><a href="#fn:3" class="footnote" rel="footnote">3</a></sup>. <br /><br /> The <code class="language-plaintext highlighter-rouge">Additional</code> section is intended for modules that should run regardless of the success of other modules.</td>
      <td>Based on this guidance, I’ve chosen to add Duo Unix in the <code class="language-plaintext highlighter-rouge">Additional</code> section, since it should only run after the primary authentication flow has completed.</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">Auth</code></td>
      <td>The desired PAM-API control, the name of the PAM module as found on disk, and any optional module arguments.</td>
      <td>I’m using <code class="language-plaintext highlighter-rouge">required</code> here so that the PAM-API will deny access if Duo authentication fails but will still process the rest of the PAM stack first. (Other valid control values can be found in the <a href="https://manpages.ubuntu.com/manpages/noble/en/man5/pam.d.5.html">man page for pam.d</a>.) <br /><br /> I’ve also included the canonical path to the module since it resides outside of PAM’s normal search path on Ubuntu.</td>
    </tr>
  </tbody>
</table>

<p>Finally, the profile must be installed at <code class="language-plaintext highlighter-rouge">/usr/share/pam-configs/duo-unix</code> in order for it to be readable by <code class="language-plaintext highlighter-rouge">pam-auth-update</code>. I’ve chosen to use <code class="language-plaintext highlighter-rouge">duo-unix</code> as the filename for the profile since convention dictates it should match the related package or module name.</p>

<h2 id="enabling-the-pam-profile">Enabling the PAM Profile</h2>

<p>Once the profile has been installed, it can be activated with <code class="language-plaintext highlighter-rouge">pam-auth-update</code>. There are three ways to do this:</p>
<ol>
  <li>
    <p>Interactively, as an administrator:</p>

    <p>Run <code class="language-plaintext highlighter-rouge">pam-auth-update</code> as root, check the box next to “Duo two-factor authentication”, and select “OK”.</p>
  </li>
  <li>
    <p>Non-interactively, as a package maintainer script:</p>

    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> pam-auth-update --enable duo-unix --package
</code></pre></div>    </div>
  </li>
  <li>
    <p>Non-interactively, as an administrator or as a configuration management tool:</p>

    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> pam-auth-update --enable duo-unix --force
</code></pre></div>    </div>
  </li>
</ol>

<p><strong>Note:</strong> The third option will overwrite your current system-wide PAM configuration without prompting, which should be safe unless you’ve manually edited the aforementioned system-wide PAM configuration files in <code class="language-plaintext highlighter-rouge">/etc/pam.d</code>.</p>

<h2 id="example-puppet-code">Example Puppet Code</h2>

<p>Here’s a minimal working example for how to do all of this in a Puppet module:</p>
<div class="language-puppet highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">file</span> <span class="p">{</span> <span class="s1">'/usr/share/pam-configs/duo-unix'</span><span class="p">:</span>
  <span class="py">ensure</span>  <span class="p">=&gt;</span> <span class="n">file</span><span class="p">,</span>
  <span class="py">owner</span>   <span class="p">=&gt;</span> <span class="s1">'root'</span><span class="p">,</span>
  <span class="py">group</span>   <span class="p">=&gt;</span> <span class="s1">'root'</span><span class="p">,</span>
  <span class="py">mode</span>    <span class="p">=&gt;</span> <span class="s1">'0644'</span><span class="p">,</span>
  <span class="py">content</span> <span class="p">=&gt;</span> <span class="nf">file</span><span class="p">(</span><span class="s2">"</span><span class="nv">${module_name}</span><span class="s2">/pam-config-duo-unix"</span><span class="p">),</span>
<span class="p">}</span> <span class="p">~&gt;</span>
<span class="n">exec</span> <span class="p">{</span> <span class="s2">"</span><span class="nv">${module_name}</span><span class="s2">_enable_pam_module"</span><span class="p">:</span>
  <span class="py">command</span> <span class="p">=&gt;</span> <span class="s1">'pam-auth-update --enable duo-unix --force'</span><span class="p">,</span>
  <span class="py">unless</span>  <span class="p">=&gt;</span> <span class="s1">'grep -q pam_duo\.so /etc/pam.d/common-auth'</span><span class="p">,</span>
  <span class="py">path</span>    <span class="p">=&gt;</span> <span class="p">[</span> <span class="s1">'/sbin'</span><span class="p">,</span> <span class="s1">'/usr/sbin'</span><span class="p">,</span> <span class="s1">'/bin'</span><span class="p">,</span> <span class="s1">'/usr/bin'</span> <span class="p">],</span>
<span class="p">}</span>
</code></pre></div></div>

<h2 id="closing-thoughts">Closing Thoughts</h2>

<p>In doing things this way, I’m breaking with Duo’s official recommendation for Ubuntu systems, which is to modify the default call to <code class="language-plaintext highlighter-rouge">pam_unix.so</code> in <code class="language-plaintext highlighter-rouge">/etc/pam.d/common-auth</code> and insert a call to <code class="language-plaintext highlighter-rouge">pam_duo.so</code> directly afterwards. However, what I propose here should be both functionally identical and safer. Also, if you’re using <code class="language-plaintext highlighter-rouge">pam_sss.so</code> in conjunction with (or instead of) <code class="language-plaintext highlighter-rouge">pam_unix.so</code> to enable authentication via <a href="https://sssd.io/">SSSD</a>, Duo’s recommendation won’t work anyway.</p>

<p>It’s also worth mentioning that enabling Duo Unix in the manner described above should enable Duo for any authentication flow that relies on PAM’s <code class="language-plaintext highlighter-rouge">common-auth</code> stack, including <code class="language-plaintext highlighter-rouge">sudo</code>. One notable exception to this rule is key-based authentication in SSH, which evidently <a href="https://serverfault.com/a/592591">bypasses the PAM auth stack</a> entirely. Enabling Duo for SSH key authentication is outside the scope of this post<sup id="fnref:4" role="doc-noteref"><a href="#fn:4" class="footnote" rel="footnote">4</a></sup>.</p>

<p>Also, the legacy <code class="language-plaintext highlighter-rouge">login_duo</code> approach for enabling Duo Unix<sup id="fnref:5" role="doc-noteref"><a href="#fn:5" class="footnote" rel="footnote">5</a></sup> is outside the scope of this post. It relies on OpenSSH’s <code class="language-plaintext highlighter-rouge">ForceCommand</code> directive and is nowhere near as robust as the PAM module.</p>

<hr />

<div class="footnotes" role="doc-endnotes">
  <ol>
    <li id="fn:1" role="doc-endnote">
      <p>Tragically, <a href="https://discourse.ubuntu.com/t/remembering-and-thanking-steve-langasek/52665">Steve passed away early last year</a>. <a href="#fnref:1" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:2" role="doc-endnote">
      <p>Those of you who are familiar with other distros may note that Fedora and its derivatives use <a href="https://github.com/authselect/authselect">authselect</a> (which replaces the older <code class="language-plaintext highlighter-rouge">authconfig</code> utility) instead. <a href="#fnref:2" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:3" role="doc-endnote">
      <p>For example, this might be done to allow both local and domain accounts to log into a system. <a href="#fnref:3" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:4" role="doc-endnote">
      <p><strong>Hint:</strong> This can be accomplished by editing the package-provided <code class="language-plaintext highlighter-rouge">sshd</code> PAM stack at <code class="language-plaintext highlighter-rouge">/etc/pam.d/sshd</code>, but this carries its own risks. Caveat emptor. <a href="#fnref:4" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:5" role="doc-endnote">
      <p>If you’re curious, <a href="https://duo.com/docs/loginduo">here’s the documentation</a>. <a href="#fnref:5" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
  </ol>
</div>]]></content><author><name>Arnon Erba</name></author><summary type="html"><![CDATA[Enabling Duo Unix on Ubuntu involves integrating the pam_duo module into your system’s Pluggable Authentication Modules (PAM) stack. This can be done by manually editing the files in /etc/pam.d/, but Ubuntu provides a safer way to do this in the form of pam-auth-update and its associated PAM config framework.]]></summary></entry><entry><title type="html">Finding the Serial Number of a Windows PC With PowerShell</title><link href="https://blog.arnonerba.com/2026/01/find-serial-number-windows" rel="alternate" type="text/html" title="Finding the Serial Number of a Windows PC With PowerShell" /><published>2026-01-15T00:00:00+00:00</published><updated>2026-01-15T00:00:00+00:00</updated><id>https://blog.arnonerba.com/2026/01/find-serial-number-windows</id><content type="html" xml:base="https://blog.arnonerba.com/2026/01/find-serial-number-windows"><![CDATA[<p>It’s now possible to locate your PC’s serial number in the Settings app, but nothing beats a simple command-line query.</p>

<h2 id="powershell-method-modern">PowerShell Method (Modern)</h2>

<p>Since <a href="https://techcommunity.microsoft.com/blog/windows-itpro-blog/wmi-command-line-wmic-utility-deprecation-next-steps/4039242">the WMIC utility is now deprecated</a>, the modern way to perform this query is with <a href="https://learn.microsoft.com/en-us/powershell/module/cimcmdlets/get-ciminstance">the <code class="language-plaintext highlighter-rouge">Get-CimInstance</code> cmdlet</a> in PowerShell:</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">Get-CimInstance</span><span class="w"> </span><span class="nt">-ClassName</span><span class="w"> </span><span class="nx">Win32_BIOS</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">Select-Object</span><span class="w"> </span><span class="nx">SerialNumber</span><span class="w">
</span></code></pre></div></div>

<p>That’s the right way to do it if you’re running this query in a script. However, if you’re doing this by hand, that’s a lot to remember and type, so I’d recommend using an abbreviated version instead:</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">(</span><span class="n">gcim</span><span class="w"> </span><span class="nx">Win32_BIOS</span><span class="p">)</span><span class="o">.</span><span class="nf">SerialNumber</span><span class="w">
</span></code></pre></div></div>

<p>You can also use the following version, which returns more than just the serial number but is even easier to remember:</p>
<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">gcim</span><span class="w"> </span><span class="nx">win32_bios</span><span class="w">
</span></code></pre></div></div>

<p><strong>Note:</strong> Some sources suggest using the <code class="language-plaintext highlighter-rouge">Get-WmiObject</code> cmdlet, but <a href="https://learn.microsoft.com/en-us/powershell/scripting/learn/ps101/07-working-with-wmi">that’s deprecated too</a>.</p>

<h2 id="wmic-method-legacy">WMIC Method (Legacy)</h2>

<p>This is hardcoded into my brain from years of manual Windows deployments, so even though it no longer works on recent Windows installations, I’ll include it here for posterity:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>wmic bios get serialnumber
</code></pre></div></div>

<p><strong>Remember:</strong> <a href="https://stackoverflow.com/q/57121875">wmic.exe is deprecated and will eventually stop working</a>.</p>]]></content><author><name>Arnon Erba</name></author><summary type="html"><![CDATA[It’s now possible to locate your PC’s serial number in the Settings app, but nothing beats a simple command-line query.]]></summary></entry><entry><title type="html">Non-Destructively Disabling Netplan on Ubuntu</title><link href="https://blog.arnonerba.com/2026/01/disable-netplan-ubuntu" rel="alternate" type="text/html" title="Non-Destructively Disabling Netplan on Ubuntu" /><published>2026-01-05T00:00:00+00:00</published><updated>2026-01-05T00:00:00+00:00</updated><id>https://blog.arnonerba.com/2026/01/disable-netplan-ubuntu</id><content type="html" xml:base="https://blog.arnonerba.com/2026/01/disable-netplan-ubuntu"><![CDATA[<p><a href="https://netplan.io/">Netplan</a> has been part of Ubuntu <a href="https://ubuntu.com/blog/a-declarative-approach-to-linux-networking-with-netplan">for almost a decade now</a>, and it’s actually pretty good at its job, which is to provide a unified, human-readable interface for configuring either systemd-networkd (on Ubuntu Server) or NetworkManager (on Ubuntu Desktop). Let’s be honest, manually configuring systemd-networkd isn’t for the faint of heart, especially for more complex scenarios like bonding.</p>

<p>However: I don’t need Netplan, because I can configure systemd-networkd directly <a href="https://forge.puppet.com/modules/puppet/systemd">with Puppet</a> (or possibly <a href="https://voxpupuli.org/openvox/">OpenVox</a> in the future). Netplan can play nice in this scenario, since it writes to <code class="language-plaintext highlighter-rouge">/run/systemd/network/</code> instead of <code class="language-plaintext highlighter-rouge">/etc/systemd/network/</code>, but I don’t want it fighting with my configuration management tools over something as critical as network configuration.</p>

<h2 id="problem-metapackages">Problem: Metapackages</h2>

<p>So, why not just purge Netplan with <code class="language-plaintext highlighter-rouge">apt purge netplan.io &amp;&amp; apt autoremove</code>? Well, because doing so breaks the <code class="language-plaintext highlighter-rouge">ubuntu-minimal</code> metapackage:</p>
<blockquote>
  <p>This package [ubuntu-minimal] depends on all of the packages in the Ubuntu minimal system … It is also used to help ensure proper upgrades, so it is recommended that it not be removed.</p>
</blockquote>

<p>Ubuntu certainly won’t stop you from doing this, but breaking metapackages is a great way to run into weird issues down the road.</p>

<h2 id="solution-purge-config--reapply">Solution: Purge Config &amp; Reapply</h2>

<p>Here’s my compromise: Leave Netplan installed, but purge its config files. Fortunately, this is pretty simple. <a href="https://netplan.io/faq">According to the FAQ</a>, Netplan config files may exist in three different directories, in order of precedence:</p>
<ol>
  <li><code class="language-plaintext highlighter-rouge">/run/netplan/</code></li>
  <li><code class="language-plaintext highlighter-rouge">/etc/netplan/</code></li>
  <li><code class="language-plaintext highlighter-rouge">/lib/netplan/</code></li>
</ol>

<p>The key is to run <code class="language-plaintext highlighter-rouge">netplan apply</code> after removing the relevant files from those directories. This removes Netplan’s generated configuration from the network stack.</p>

<p><strong>Note:</strong> This is a disruptive action, so make sure you have an alternate network configuration ready to take over after Netplan lets go of the reins!</p>

<p>All together, the whole process might look something like this:</p>
<div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gp">$</span><span class="w"> </span><span class="nb">sudo rm</span> <span class="nt">-f</span> /run/netplan/<span class="k">*</span>.yaml /etc/netplan/<span class="k">*</span>.yaml /lib/netplan/<span class="k">*</span>.yaml <span class="o">&amp;&amp;</span> <span class="nb">sudo </span>netplan apply
</code></pre></div></div>

<h2 id="example-puppet-code">Example Puppet Code</h2>

<p>If you’re a Puppet aficionado, here’s one way to do this from inside a module:</p>
<div class="language-puppet highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">file</span> <span class="p">{</span> <span class="s1">'/etc/netplan/'</span><span class="p">:</span>
  <span class="py">ensure</span>  <span class="p">=&gt;</span> <span class="n">directory</span><span class="p">,</span>
  <span class="py">owner</span>   <span class="p">=&gt;</span> <span class="s1">'root'</span><span class="p">,</span>
  <span class="py">group</span>   <span class="p">=&gt;</span> <span class="s1">'root'</span><span class="p">,</span>
  <span class="py">mode</span>    <span class="p">=&gt;</span> <span class="s1">'0755'</span><span class="p">,</span>
  <span class="py">purge</span>   <span class="p">=&gt;</span> <span class="kc">true</span><span class="p">,</span>
  <span class="py">recurse</span> <span class="p">=&gt;</span> <span class="kc">true</span><span class="p">,</span>
  <span class="py">force</span>   <span class="p">=&gt;</span> <span class="kc">true</span><span class="p">,</span>
<span class="p">}</span> <span class="p">~&gt;</span>
<span class="n">exec</span> <span class="p">{</span> <span class="s2">"</span><span class="nv">${module_name}</span><span class="s2">_regenerate_config"</span><span class="p">:</span>
  <span class="py">command</span>     <span class="p">=&gt;</span> <span class="s1">'netplan apply'</span><span class="p">,</span>
  <span class="py">path</span>        <span class="p">=&gt;</span> <span class="p">[</span> <span class="s1">'/sbin'</span><span class="p">,</span> <span class="s1">'/usr/sbin'</span><span class="p">,</span> <span class="s1">'/bin'</span><span class="p">,</span> <span class="s1">'/usr/bin'</span> <span class="p">],</span>
  <span class="py">refreshonly</span> <span class="p">=&gt;</span> <span class="kc">true</span><span class="p">,</span>
<span class="p">}</span>
</code></pre></div></div>]]></content><author><name>Arnon Erba</name></author><summary type="html"><![CDATA[Netplan has been part of Ubuntu for almost a decade now, and it’s actually pretty good at its job, which is to provide a unified, human-readable interface for configuring either systemd-networkd (on Ubuntu Server) or NetworkManager (on Ubuntu Desktop). Let’s be honest, manually configuring systemd-networkd isn’t for the faint of heart, especially for more complex scenarios like bonding.]]></summary></entry><entry><title type="html">Starting Again</title><link href="https://blog.arnonerba.com/2025/12/starting-again" rel="alternate" type="text/html" title="Starting Again" /><published>2025-12-29T00:00:00+00:00</published><updated>2025-12-29T00:00:00+00:00</updated><id>https://blog.arnonerba.com/2025/12/starting-again</id><content type="html" xml:base="https://blog.arnonerba.com/2025/12/starting-again"><![CDATA[<p>It’s been a little under two years now since I took this site offline and embarked on one of my longest breaks from publishing since I started blogging back in 2012.</p>

<p>Recently, I’ve been compelled to start again. Maybe it’s the result of reading one too many <a href="https://www.wired.com/story/ai-generated-medium-posts-content-moderation/">AI-generated Medium articles</a>, or maybe it’s a reaction to my growing sense of dismay about the <a href="https://en.wikipedia.org/wiki/Dead_Internet_theory">perceived death of the Web</a> I grew up with, a place where people wrote their own content and Google Search actually worked. Or, maybe I just feel indebted to people like <a href="https://utcc.utoronto.ca/~cks/space/blog/">Chris Siebenmann</a>, <a href="https://www.joelonsoftware.com/">Joel Spolsky</a>, and all others whose content has helped me over the years.</p>

<p>In any case, here we are again, this time on <a href="https://pages.github.com/">GitHub Pages</a>. Let’s see what happens next.</p>]]></content><author><name>Arnon Erba</name></author><summary type="html"><![CDATA[It’s been a little under two years now since I took this site offline and embarked on one of my longest breaks from publishing since I started blogging back in 2012.]]></summary></entry><entry><title type="html">How to Fix “No Pattern File Found” in Stata’s dm0082 Package</title><link href="https://blog.arnonerba.com/2021/06/how-to-fix-no-pattern-file-found-in-statas-dm0082-package" rel="alternate" type="text/html" title="How to Fix “No Pattern File Found” in Stata’s dm0082 Package" /><published>2021-06-23T00:00:00+00:00</published><updated>2026-01-06T00:00:00+00:00</updated><id>https://blog.arnonerba.com/2021/06/how-to-fix-no-pattern-file-found-in-statas-dm0082-package</id><content type="html" xml:base="https://blog.arnonerba.com/2021/06/how-to-fix-no-pattern-file-found-in-statas-dm0082-package"><![CDATA[<p>If you’re using the <a href="https://www.stata-journal.com/article.html?article=dm0082">dm0082</a> package in Stata, you may encounter the following error when using commands such as <code class="language-plaintext highlighter-rouge">stnd_compname</code>:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>No pattern file found in ~/ado/plus/p/
</code></pre></div></div>

<p>This error indicates that your installation of the dm0082 package is missing several important ancillary files. We specifically encountered this error on a Linux system, but you’ll likely see a similar message on Windows or macOS.</p>

<h2 id="solution-install-the-missing-ancillary-files">Solution: Install the Missing Ancillary Files</h2>

<p>The root cause of this error is that the ancillary files for dm0082 are not automatically placed in the correct location when they are installed. Instead, they are copied to your current working directory. The following pattern files will need to be moved from your current working directory to the folder referenced in the error message above:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>P10_namecomp_patterns.csv
P21_spchar_namespecialcases.csv
P22_spchar_remove.csv
P23_spchar_rplcwithspace.csv
P30_std_entity.csv
P40_std_commonwrd_name.csv
P50_std_commonwrd_all.csv
P60_std_numbers.csv
P70_std_nesw.csv
P81_std_smallwords_all.csv
P82_std_smallwords_address.csv
P90_entity_patterns.csv
P110_std_streettypes.csv
P120_pobox_patterns.csv
P131_std_secondaryadd.csv
P132_secondaryadd_patterns.csv
</code></pre></div></div>

<p>On Linux, the proper destination for these files will likely be <code class="language-plaintext highlighter-rouge">~/ado/plus/p/</code>. If you are on Windows, it will likely be <code class="language-plaintext highlighter-rouge">c:\ado\plus\p\</code> instead.</p>

<p><strong>Note:</strong> Make sure that the name of each pattern file starts with a capital “P” rather than a lowercase “p”. The filenames may change to all lowercase when the ancillary files are downloaded. If that happens to you and you’re running Linux, you can use the <code class="language-plaintext highlighter-rouge">rename</code> command as described in <a href="https://askubuntu.com/questions/1069263/changing-first-letter-of-a-filename-to-uppercase">this Ask Ubuntu post</a> to quickly fix all the filenames at once.</p>

<h2 id="bonus-section-finding-statas-plus-directory">Bonus Section: Finding Stata’s PLUS Directory</h2>

<p>If you want to confirm whether the folder referenced in the error message is correct, you can find your local Stata PLUS directory by running the <code class="language-plaintext highlighter-rouge">sysdir</code> command:</p>
<div class="language-stata highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">.</span><span class="w"> </span><span class="n">sysdir</span>
<span class="w">   </span><span class="n">STATA</span><span class="o">:</span><span class="w"> </span><span class="o">/</span><span class="n">usr</span><span class="o">/</span><span class="kt">local</span><span class="o">/</span><span class="n">stata17</span><span class="o">/</span>
<span class="w">    </span><span class="n">BASE</span><span class="o">:</span><span class="w"> </span><span class="o">/</span><span class="n">usr</span><span class="o">/</span><span class="kt">local</span><span class="o">/</span><span class="n">stata17</span><span class="o">/</span><span class="n">ado</span><span class="o">/</span><span class="n">base</span><span class="o">/</span>
<span class="w">    </span><span class="n">SITE</span><span class="o">:</span><span class="w"> </span><span class="o">/</span><span class="n">usr</span><span class="o">/</span><span class="kt">local</span><span class="o">/</span><span class="n">ado</span><span class="o">/</span>
<span class="w">    </span><span class="n">PLUS</span><span class="o">:</span><span class="w"> </span><span class="o">~/</span><span class="n">ado</span><span class="o">/</span><span class="n">plus</span><span class="o">/</span>
<span class="n">PERSONAL</span><span class="o">:</span><span class="w"> </span><span class="o">~/</span><span class="n">ado</span><span class="o">/</span><span class="n">personal</span><span class="o">/</span>
<span class="n">OLDPLACE</span><span class="o">:</span><span class="w"> </span><span class="o">~/</span><span class="n">ado</span><span class="o">/</span>
</code></pre></div></div>

<p>More info about the PLUS directory from the <a href="https://www.stata.com/support/faqs/programming/personal-ado-directory/">Stata FAQ</a>:</p>
<blockquote>
  <p>PLUS is where Stata installs ado-files from the SJ and STB and ado-files that you have downloaded from the Internet through the help system or with the net command.</p>
</blockquote>

<hr />

<p><strong>References:</strong></p>
<ul>
  <li><a href="https://www.kaichen.work/?p=291">Fuzzy match in Stata - Kai Chen</a></li>
</ul>]]></content><author><name>Arnon Erba</name></author><summary type="html"><![CDATA[If you’re using the dm0082 package in Stata, you may encounter the following error when using commands such as stnd_compname: No pattern file found in ~/ado/plus/p/]]></summary></entry><entry><title type="html">Troubleshooting SELinux Issues</title><link href="https://blog.arnonerba.com/2021/03/how-to-fix-almost-any-selinux-issue" rel="alternate" type="text/html" title="Troubleshooting SELinux Issues" /><published>2021-03-29T00:00:00+00:00</published><updated>2026-01-07T00:00:00+00:00</updated><id>https://blog.arnonerba.com/2021/03/how-to-fix-almost-any-selinux-issue</id><content type="html" xml:base="https://blog.arnonerba.com/2021/03/how-to-fix-almost-any-selinux-issue"><![CDATA[<p>SELinux has a well-earned reputation for being hard to use. It’s infamous for causing strange, illogical faults that can’t be fixed via normal troubleshooting routines, and, as a consequence, many guides and blog posts recommend disabling it outright. However, SELinux is a great way to secure and harden Linux systems, and with a few simple steps it’s possible to fix most common problems you might encounter while using it.</p>

<h2 id="examples-of-common-issues">Examples of Common Issues</h2>

<p>Let’s start by looking at a few issues I’ve had in the past that turned out to be caused by SELinux:</p>
<ol>
  <li>A user could no longer log in with an SSH key after their home directory was restored from a backup. Their <code class="language-plaintext highlighter-rouge">authorized_keys</code> file was configured correctly but was being ignored by SSH.</li>
  <li>A service wouldn’t start after replacing its config file with a modified version that had been uploaded via SFTP. The service complained about the config file being inaccessible even though its permissions were set correctly.</li>
  <li>Postfix couldn’t communicate with OpenDKIM when the latter was set to use a UNIX socket instead of a TCP/IP socket. The Postfix user was in the correct security group and the socket was configured correctly.</li>
</ol>

<p>Without a general understanding of how SELinux works, you might guess that the issues above were caused by bad file permissions. That’s why it’s important to understand SELinux and to identify it as a possible culprit early in the troubleshooting process.</p>

<h2 id="what-is-selinux-exactly">What is SELinux, Exactly?</h2>

<p>At its core, SELinux is a set of rules that tell applications what they can and can’t do. SELinux is separate from the regular Linux file permissions model and is therefore able to protect against issues like misconfigured permissions or privilege escalation exploits. In order for an operation to succeed on an SELinux-enabled system, it must be permitted by file permissions as well as by the active SELinux policy.</p>

<p>Regular file permissions are a form of discretionary access control, or DAC. On the other hand, SELinux is a form of mandatory access control, or MAC. With DAC, a user or service can do anything they have permission to do, even if it’s something undesirable or dangerous. With MAC, malicious or dangerous actions can be stopped, even if a DAC policy would otherwise permit them to happen.</p>

<p>Here’s an example of why you’d want to keep SELinux enabled. Normally, Apache shouldn’t be able to read <code class="language-plaintext highlighter-rouge">/etc/shadow</code>, and the default file permissions prevent that from happening. However, if those permissions were misconfigured and Apache was configured to serve files from <code class="language-plaintext highlighter-rouge">/etc</code>, it would be possible for anyone with a web browser to download <code class="language-plaintext highlighter-rouge">/etc/shadow</code>. A properly configured SELinux policy would override both misconfigurations and prevent Apache from serving sensitive system files from <code class="language-plaintext highlighter-rouge">/etc</code>.</p>

<h2 id="putting-things-in-context">Putting Things in Context</h2>

<p>Extra protection is great, but what happens when SELinux interferes when it shouldn’t? If SELinux is interfering with something “normal” that should otherwise work, chances are you have one simple problem: incorrect file security contexts. Security contexts are how SELinux categorizes files and decides which applications can access them. By default, security contexts are applied to files based on their location. For example, files in home directories get different security contexts from files in <code class="language-plaintext highlighter-rouge">/etc</code> or <code class="language-plaintext highlighter-rouge">/tmp</code>.</p>

<p>You can inspect a file’s security context with <code class="language-plaintext highlighter-rouge">ls -Z</code>, but you’re probably better off using <a href="https://linux.die.net/man/8/restorecon">restorecon</a> to reset contexts to their default values if you suspect a problem. To save time, you can run <code class="language-plaintext highlighter-rouge">restorecon -rv /path/to/directory</code> to recursively reset the security contexts for an entire directory. If things are bad enough, you can relabel your entire filesystem by running <code class="language-plaintext highlighter-rouge">touch /.autorelabel</code> and then rebooting.</p>

<p>The <code class="language-plaintext highlighter-rouge">restorecon</code> tool was the solution to problems #1 and #2 from the list at the beginning of this post. Incorrect security contexts can be applied when files are restored from a backup or copied from a nonstandard location.</p>

<h2 id="adjusting-the-policy">Adjusting the Policy</h2>

<p>In most mainstream Linux distributions, the default SELinux policy is carefully crafted by a group of upstream maintainers. Creating a perfect one-size-fits-all policy is impossible, so the maintainers provide built-in policy exceptions in the form of SELinux booleans. SELinux booleans can be easily enabled or disabled to cover common use cases where the default SELinux policy falls short. If you have an SELinux problem that can’t be fixed by restoring default file security contexts, you should check to see if an available SELinux boolean covers your use case.</p>

<p>You can use <a href="https://linux.die.net/man/8/getsebool">getsebool</a> to retrieve a list of available booleans on your system and then use <a href="https://linux.die.net/man/8/setsebool">setsebool</a> to enable or disable them. Alternatively, you can use <a href="https://linux.die.net/man/8/semanage">semanage</a> to see more detailed information about available booleans. Examples of SELinux booleans include:</p>
<ul>
  <li><code class="language-plaintext highlighter-rouge">use_nfs_home_dirs</code>: Support NFS home directories.</li>
  <li><code class="language-plaintext highlighter-rouge">httpd_can_network_connect</code>: Allow HTTPD scripts and modules to connect to the network.</li>
  <li><code class="language-plaintext highlighter-rouge">ftpd_full_access</code>: Allow full filesystem access over FTP.</li>
</ul>

<h2 id="rewriting-the-policy">Rewriting the Policy</h2>

<p>If fixing security contexts and enabling booleans hasn’t worked, ask yourself if you’re doing something abnormal. “Abnormal” in this context might include running a service on a nonstandard port, serving web files from an unconventional location, or moving config files out of their default directory. If you are, there’s a good chance your system’s default SELinux policy won’t cover your use case.</p>

<p>Before you proceed, you should think hard about what benefit you’re getting from running a nonstandard configuration. Standards exist for good reasons: troubleshooting is easier, malicious activity is simpler to detect, and applications can be configured to behave more predictably. With that said, there’s plenty of vendor software out there that relies on an “abnormal” configuration to work properly.</p>

<p>If you’ve evaluated your configuration and decided to proceed, you have two options. First, you may have discovered a bug in your platform’s SELinux policy, which means you should submit a bug report so that the policy can be fixed upstream. This is the course I ended up pursuing for the <a href="https://bugzilla.redhat.com/show_bug.cgi?id=1563423">OpenDKIM issue</a> mentioned above, and the Red Hat maintainers updated the upstream policy after a few months.</p>

<p>Alternatively, you can write and compile a custom SELinux policy module. This is not as difficult as it sounds, as <a href="https://linux.die.net/man/1/audit2allow">audit2allow</a> can generate SELinux modules directly from audit log entries. A brief description of how to make use of the audit log is below, but a full explanation is beyond the scope of this post.</p>

<h2 id="the-audit-log">The Audit Log</h2>

<p>By default, SELinux violations are logged to the audit log, which is generally located at <code class="language-plaintext highlighter-rouge">/var/log/audit/audit.log</code>. The best way to troubleshoot potential SELinux issues is to consult the audit log, but the default log format is not particularly user-friendly and raw entries are not always easy to understand. Instead of reading the audit log file directly, you can search the log with <a href="https://linux.die.net/man/8/ausearch">ausearch</a> or generate comprehensive, human-readable reports from it with <a href="https://linux.die.net/man/8/sealert">sealert</a>. Additional resources for how to use those tools are provided at the bottom of this post.</p>

<h2 id="wrapping-up">Wrapping Up</h2>

<p>SELinux has been around for a long time, and many mainstream Linux distributions now ship with robust SELinux policies that cover a range of use cases. Additionally, configuration management tools like Puppet can automatically set SELinux contexts for you and help you avoid inadvertently mislabeling files.</p>

<p>That said, the default SELinux policy can’t possibly cover all possible use cases, so you may still need to enable SELinux booleans or compile custom policy modules to make SELinux work for you. In any case, you should avoid disabling it outright, especially if you’re running a derivative of Fedora such as RHEL or CentOS where SELinux is intended to be the primary form of mandatory access control.</p>

<hr />

<p><strong>References:</strong></p>
<ul>
  <li><a href="https://www.redhat.com/en/topics/linux/what-is-selinux">What is SELinux? - Red Hat</a></li>
  <li><a href="https://wiki.centos.org/HowTos/SELinux">HowTos/SELinux - CentOS Wiki</a></li>
  <li><a href="https://docs.fedoraproject.org/en-US/quick-docs/selinux-getting-started/">Getting started with SELinux :: Fedora Docs</a></li>
  <li><a href="https://docs.fedoraproject.org/en-US/quick-docs/selinux-troubleshooting/">Troubleshooting SELinux :: Fedora Docs</a></li>
  <li><a href="https://access.redhat.com/articles/2191331">Basic SELinux Troubleshooting in CLI - Red Hat Customer Portal</a></li>
  <li><a href="https://docs.redhat.com/en/documentation/red_hat_enterprise_linux/8/html/using_selinux/index">Using SELinux - Red Hat Enterprise Linux 8 - Red Hat Customer Portal</a></li>
</ul>]]></content><author><name>Arnon Erba</name></author><summary type="html"><![CDATA[SELinux has a well-earned reputation for being hard to use. It’s infamous for causing strange, illogical faults that can’t be fixed via normal troubleshooting routines, and, as a consequence, many guides and blog posts recommend disabling it outright. However, SELinux is a great way to secure and harden Linux systems, and with a few simple steps it’s possible to fix most common problems you might encounter while using it.]]></summary></entry><entry><title type="html">Bitdefender Antivirus Breaks RDP (Remote Desktop) on Windows</title><link href="https://blog.arnonerba.com/2021/01/bitdefender-antivirus-breaks-the-windows-remote-desktop-client" rel="alternate" type="text/html" title="Bitdefender Antivirus Breaks RDP (Remote Desktop) on Windows" /><published>2021-01-06T00:00:00+00:00</published><updated>2026-01-07T00:00:00+00:00</updated><id>https://blog.arnonerba.com/2021/01/bitdefender-antivirus-breaks-the-windows-remote-desktop-client</id><content type="html" xml:base="https://blog.arnonerba.com/2021/01/bitdefender-antivirus-breaks-the-windows-remote-desktop-client"><![CDATA[<p><strong>Update:</strong> This may have been fixed by now, but back in 2021, <a href="https://www.bitdefender.com/solutions/free.html">the free edition of Bitdefender Antivirus</a> was interfering with Remote Desktop Protocol (RDP) connections on Windows. The remainder of this post has been preserved for posterity.</p>

<hr />

<p>Affected users on Windows endpoints with Bitdefender Antivirus installed may receive the following error when they try to log on to a remote PC or server with Network Level Authentication (NLA) enabled:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>An authentication error has occurred.
The Local Security Authority cannot be contacted.
This could be due to an expired password.
</code></pre></div></div>

<p>While an expired password or a server-side misconfiguration can cause this error, it may also indicate a client-side issue. In this case, the error appears to be caused by Bitdefender Antivirus replacing the remote computer’s certificate in order to inspect encrypted RDP traffic. This process breaks Network Level Authentication and causes the connection to fail.</p>

<h2 id="solution-add-file-level-exclusions-for-mstsc">Solution: Add File-Level Exclusions for MSTSC</h2>

<p>One workaround is to add file-level exclusions in Bitdefender for both the 64-bit and 32-bit versions of the Windows RDP client:</p>
<ul>
  <li><code class="language-plaintext highlighter-rouge">C:\Windows\system32\mstsc.exe</code></li>
  <li><code class="language-plaintext highlighter-rouge">C:\Windows\syswow64\mstsc.exe</code></li>
</ul>

<p>This is not an ideal solution, but the free version of Bitdefender Antivirus has a limited control panel and does not provide alternative workarounds.</p>

<hr />

<p><strong>References:</strong></p>
<ul>
  <li><a href="https://www.reddit.com/r/BitDefender/comments/hqmcqu/bitdefender_antivirus_free_edition_breaking_rdp/">Bitdefender Antivirus Free Edition breaking RDP : BitDefender</a></li>
  <li><a href="https://answers.microsoft.com/en-us/windows/forum/windows_10-networking/remote-desktop-connection-issue-solved/8e382bf1-b26a-4730-b9d0-c8a166fa33a3">Remote Desktop Connection Issue - Microsoft Community</a></li>
  <li><a href="https://community.bitdefender.com/en/discussion/82563/bitdefender-antivirus-free-remote-desktop-block">Bitdefender Antivirus Free - remote Desktop block - The Bitdefender Expert Community</a></li>
  <li><a href="https://stackoverflow.com/questions/62531042/aws-ec2-windows-login-error-saying-an-authentication-error-has-occured-the-loca">AWS ec2 windows login error - Stack Overflow</a></li>
</ul>]]></content><author><name>Arnon Erba</name></author><summary type="html"><![CDATA[Update: This may have been fixed by now, but back in 2021, the free edition of Bitdefender Antivirus was interfering with Remote Desktop Protocol (RDP) connections on Windows. The remainder of this post has been preserved for posterity.]]></summary></entry><entry><title type="html">Automatically Updating Stata on Linux With Cron</title><link href="https://blog.arnonerba.com/2020/10/how-to-automatically-update-stata-on-linux" rel="alternate" type="text/html" title="Automatically Updating Stata on Linux With Cron" /><published>2020-10-20T00:00:00+00:00</published><updated>2026-01-08T00:00:00+00:00</updated><id>https://blog.arnonerba.com/2020/10/how-to-automatically-update-stata-on-linux</id><content type="html" xml:base="https://blog.arnonerba.com/2020/10/how-to-automatically-update-stata-on-linux"><![CDATA[<p>On Windows and macOS, Stata can be configured to check for updates automatically with the <code class="language-plaintext highlighter-rouge">set update_query</code> command. However, this feature isn’t present on the Linux version of Stata. Also, it doesn’t actually update Stata – it just enables update notifications. Stata will still need to be manually updated by someone with the permission to do so.</p>

<p>If you’re running Stata on a standalone Linux server or an HPC cluster, you may be interested in having Stata update itself without any user interaction. This is especially useful if Stata users do not have permission to update the software themselves, as is often the case on shared Linux systems.</p>

<p>We can enable true automatic updates with a cron job and a Stata batch mode hack:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>0 0 * * 0 echo 'update all' | /usr/local/stata19/stata &gt; /dev/null
</code></pre></div></div>

<p>Adding this line to root’s crontab will cause the <code class="language-plaintext highlighter-rouge">update all</code> command to be run every Sunday at 12am. Standard output is piped to <code class="language-plaintext highlighter-rouge">/dev/null</code> to prevent cron from sending unnecessary emails.</p>

<p>As always, think carefully before enabling automatic updates for mission-critical pieces of software. However, StataCorp’s quality control has historically been pretty good.</p>]]></content><author><name>Arnon Erba</name></author><summary type="html"><![CDATA[On Windows and macOS, Stata can be configured to check for updates automatically with the set update_query command. However, this feature isn’t present on the Linux version of Stata. Also, it doesn’t actually update Stata – it just enables update notifications. Stata will still need to be manually updated by someone with the permission to do so.]]></summary></entry><entry><title type="html">Microsoft Gets in on the Browser Hijacking Game</title><link href="https://blog.arnonerba.com/2020/01/microsoft-gets-in-on-the-browser-hijacking-game" rel="alternate" type="text/html" title="Microsoft Gets in on the Browser Hijacking Game" /><published>2020-01-22T00:00:00+00:00</published><updated>2020-02-12T00:00:00+00:00</updated><id>https://blog.arnonerba.com/2020/01/microsoft-gets-in-on-the-browser-hijacking-game</id><content type="html" xml:base="https://blog.arnonerba.com/2020/01/microsoft-gets-in-on-the-browser-hijacking-game"><![CDATA[<p><strong>Update:</strong> <a href="https://techcommunity.microsoft.com/t5/office-365-blog/update-to-microsoft-search-in-bing-through-office-365-proplus/ba-p/1161030">Microsoft has reversed their decision</a> to automatically install the Microsoft Search in Bing extension. The extension will still be made available but will not be automatically deployed with Office 365 ProPlus. The original post continues below.</p>

<hr />

<p>Starting next month, Microsoft plans to use Office 365 ProPlus to push a browser extension for Google Chrome that will <a href="https://docs.microsoft.com/en-us/deployoffice/microsoft-search-bing">change users’ default search engines to Bing</a>. Version 2002 of Office 365 ProPlus will forcibly install the <a href="https://chrome.google.com/webstore/detail/microsoft-search-in-bing/obdappnhkfoejojnmcohppfnoeagadna">Microsoft Search in Bing</a> extension for all Chrome users who do not already use Bing as their default search engine.</p>

<p>Understandably, <a href="https://www.reddit.com/r/sysadmin/comments/es6xp5/office_365_proplus_to_change_chromes_default/">many system administrators are frustrated with the announcement</a>, as unwanted browser extensions that change end-user settings are usually considered malware and are blocked accordingly. In fact, Microsoft’s own security tools already block dozens of programs that exhibit similar behavior.</p>

<p>On GitHub, <a href="https://github.com/MicrosoftDocs/OfficeDocs-DeployOffice/issues">users are responding to the change</a> by opening issues in the <a href="https://github.com/MicrosoftDocs/OfficeDocs-DeployOffice">OfficeDocs-DeployOffice repository</a>. So far, it does not appear that Microsoft has responded to this influx of unsolicited feedback outside of publishing a <a href="https://techcommunity.microsoft.com/t5/office-365-blog/introducing-and-managing-microsoft-search-in-bing-through-office/ba-p/1110974">blog post extolling the virtues of Bing</a>.</p>

<h2 id="who-is-affected">Who Is Affected?</h2>

<p>At this point, only businesses that have deployed Office 365 ProPlus are affected. Depending on the organization’s Office 365 license, ProPlus is the version of Office delivered to end-users when they install Office from the <a href="https://www.office.com/">office.com</a> portal. According to Microsoft, not all Office 365 plans include the ProPlus version of Office:</p>
<blockquote>
  <p>This extension is included only with Office 365 ProPlus. It isn’t included with Office 365 Business, which is the version of Office that comes with certain business plans, such as the Microsoft 365 Business plan and the Office 365 Business Premium plan.</p>
</blockquote>

<h2 id="firefox-is-next">Firefox Is Next</h2>

<p>According to Microsoft, a similar extension for Firefox is also on the way:</p>
<blockquote>
  <p>Support for the Firefox web browser is planned for a later date. We will keep you informed about support for Firefox through the Microsoft 365 Admin Center and <a href="https://docs.microsoft.com/en-us/deployoffice/microsoft-search-bing">this article</a>.</p>
</blockquote>

<h2 id="removing-the-extension">Removing The Extension</h2>

<p>By making the extension an opt-out feature, Microsoft is putting the onus on system administrators to deploy a method for blocking its installation. While there are <a href="https://docs.microsoft.com/en-us/deployoffice/microsoft-search-bing#how-to-exclude-the-extension-for-microsoft-search-in-bing-from-being-installed">official ways to prevent the extension from being installed</a>, there is no easy Microsoft-supported method for removing the extension once it has already been deployed. Instead, Microsoft recommends running the following command as an administrator on each affected machine using a script:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>C:\Program Files (x86)\Microsoft\DefaultPackPC\MainBootStrap.exe uninstallAll
</code></pre></div></div>

<p>It should also be possible to blacklist the extension with the 3rd party Group Policy templates for Chrome and Firefox provided by Google and Mozilla.</p>

<p>Unfortunately, Group Policy and other enterprise management tools do not always apply to BYOD devices, leaving users who install Office on their personal machines with little recourse except to notice and remove the extension on their own if they find it undesirable.</p>

<hr />

<p><strong>References:</strong></p>
<ul>
  <li><a href="https://docs.microsoft.com/en-us/deployoffice/microsoft-search-bing">Microsoft Search in Bing and Office 365 ProPlus - Microsoft Docs</a></li>
  <li><a href="https://www.theverge.com/2020/1/22/21077280/microsoft-chrome-bing-extension-office-365-proplus-installer-default-search-engine">Microsoft to force Chrome default search to Bing using Office 365 installer - The Verge</a></li>
  <li><a href="https://www.zdnet.com/article/microsoft-to-forcibly-install-bing-search-extension-in-chrome-for-office-365-proplus-users/">Microsoft to forcibly install Bing search extension in Chrome for Office 365 ProPlus users - ZDNet</a></li>
  <li><a href="https://www.bleepingcomputer.com/news/microsoft/microsoft-to-force-bing-search-in-chrome-for-office-365-proplus-users/">Microsoft to Force Bing Search in Chrome for Office 365 ProPlus Users - BleepingComputer</a></li>
</ul>]]></content><author><name>Arnon Erba</name></author><summary type="html"><![CDATA[Update: Microsoft has reversed their decision to automatically install the Microsoft Search in Bing extension. The extension will still be made available but will not be automatically deployed with Office 365 ProPlus. The original post continues below.]]></summary></entry></feed>