Jonathon Reinhart//jonathonreinhart.com/2019-02-26T22:00:00-05:00Configuring Winbind on a Samba AD DC on Debian 92019-02-26T22:00:00-05:002019-02-26T22:00:00-05:00Jonathon Reinharttag:jonathonreinhart.com,2019-02-26:/posts/blog/2019/02/26/configuring-winbind-on-a-samba-ad-dc-on-debian-9/<p>In the <a href="//jonathonreinhart.com/posts/blog/2019/02/11/setting-up-a-samba-4-domain-controller-on-debian-9/">previous post</a>, we set up a
Samba 4 DC. In this post, we'll configure Winbind on that Linux machine so all
of the Samba-controlled UIDs/GIDs will resolve to their AD names. We'll also set
things up so we can SSH and sudo appropriately.</p>
<h1>Prerequisites</h1>
<p>We'll assume that …</p><p>In the <a href="//jonathonreinhart.com/posts/blog/2019/02/11/setting-up-a-samba-4-domain-controller-on-debian-9/">previous post</a>, we set up a
Samba 4 DC. In this post, we'll configure Winbind on that Linux machine so all
of the Samba-controlled UIDs/GIDs will resolve to their AD names. We'll also set
things up so we can SSH and sudo appropriately.</p>
<h1>Prerequisites</h1>
<p>We'll assume that you already have a working Samba 4 DC on Debian 9.</p>
<h1>Procedure</h1>
<h2>Package Installation</h2>
<p>We'll install the following packages:</p>
<ul>
<li><a href="https://packages.debian.org/stretch/libnss-winbind"><code>libnss-winbind</code></a></li>
<li><a href="https://packages.debian.org/stretch/libpam-winbind"><code>libpam-winbind</code></a></li>
</ul>
<div class="highlight"><pre><span></span>apt install libnss-winbind libpam-winbind
</pre></div>
<h2><code>Winbindd</code> Configuration</h2>
<p>First, we'll configure the way that <code>winbindd</code> presents the home directory and
shell for users, by adding the following to the <code>[global]</code> section of
<code>smb.conf</code>:</p>
<div class="highlight"><pre><span></span> template shell = /bin/bash
template homedir = /home/%D/%U
</pre></div>
<p>If you want, you could also use <code>/home/%U</code> to omit the domain part of home
directories.</p>
<p>Restart samba (<code>systemctl restart samba-ad-dc.service</code>).</p>
<h2>Name Service Switch Configuration</h2>
<p>Without updating NSS, you'll see UID/GID numbers that don't map to any known names:</p>
<div class="highlight"><pre><span></span># ls -l /var/lib/samba/sysvol
total 8
drwxrwx---+ 4 root 3000000 4096 Feb 10 22:38 ad.onthefive.com
</pre></div>
<p>Now we'll configure NSS to consult <code>winbind</code> about users and groups, by
appending <code>winbind</code> to the following database lines in <code>/etc/nsswitch.conf</code>:</p>
<div class="highlight"><pre><span></span><span class="n">passwd</span><span class="o">:</span> <span class="n">compat</span> <span class="n">winbind</span>
<span class="n">group</span><span class="o">:</span> <span class="n">compat</span> <span class="n">winbind</span>
</pre></div>
<p>NSS should become immediately aware of this change, and all consumers of the
<code>getpwnam</code>/<code>getgrnam</code> APIs from libc should be able to query names from
winbind.</p>
<p>The <a href="http://man7.org/linux/man-pages/man1/getent.1.html"><code>getent</code></a> command-line
tool looks up entries in <em>databases</em> like <code>passwd</code> or <code>group</code>. We can call it
with AD names and expect results that look like this:</p>
<div class="highlight"><pre><span></span># getent passwd Administrator
ONTHEFIVE\administrator:*:0:100::/home/ONTHEFIVE/administrator:/bin/bash
# getent group 'Domain Admins'
ONTHEFIVE\domain admins:x:3000008:
</pre></div>
<p>Typical linux command-line tools are also now enlightened:</p>
<div class="highlight"><pre><span></span># ls -l /var/lib/samba/sysvol
total 8
drwxrwx---+ 4 root BUILTIN\administrators 4096 Feb 10 22:38 ad.onthefive.com
</pre></div>
<h2>PAM Configuration</h2>
<p>On my system, I didn't have to do anything to enable Winbind login via PAM. To
confirm that it's enabled, run <code>pam-auth-update</code> and ensure "Winbind NT/Active
Directory authentication" is selected.</p>
<p>You should now be able to SSH to your DC using any domain user:</p>
<div class="highlight"><pre><span></span>ssh administrator@samba-dc
</pre></div>
<p>Note that <code>Administrator</code> actually maps to UID 0, which is also known as <code>root</code>:</p>
<div class="highlight"><pre><span></span>$ ssh administrator@samba-dc
administrator@samba-dc<span class="err">'</span>s password:
root@samba-dc:~# id
<span class="nv">uid</span><span class="o">=</span><span class="m">0</span><span class="o">(</span>root<span class="o">)</span> <span class="nv">gid</span><span class="o">=</span><span class="m">100</span><span class="o">(</span>users<span class="o">)</span> <span class="nv">groups</span><span class="o">=</span><span class="m">100</span><span class="o">(</span>users<span class="o">)</span>,3000000<span class="o">(</span>BUILTIN<span class="se">\a</span>dministrators<span class="o">)</span>,3000004<span class="o">(</span>ONTHEFIVE<span class="se">\g</span>roup policy creator owners<span class="o">)</span>,3000005<span class="o">(</span>ONTHEFIVE<span class="se">\d</span>enied rodc password replication group<span class="o">)</span>,3000006<span class="o">(</span>ONTHEFIVE<span class="se">\e</span>nterprise admins<span class="o">)</span>,3000007<span class="o">(</span>ONTHEFIVE<span class="se">\s</span>chema admins<span class="o">)</span>,3000008<span class="o">(</span>ONTHEFIVE<span class="se">\d</span>omain admins<span class="o">)</span>,3000009<span class="o">(</span>BUILTIN<span class="se">\u</span>sers<span class="o">)</span>
</pre></div>
<h2>Automatic Home Directory Creation</h2>
<p>If you log in as an AD user, you'll see an error from Bash that it <code>Could not
chdir to home directory ...</code>. To improve this, we can ask PAM to create local
home directories upon user login, via
<a href="http://man7.org/linux/man-pages/man8/pam_mkhomedir.8.html"><code>pam_mkhomedir</code></a>.</p>
<p>On Debian, the <a href="https://packages.debian.org/stretch/libpam-runtime"><code>libpam-runtime</code></a>
package provides a script called <code>pam-auth-update</code> which uses templates from
<code>/usr/share/pam-configs</code> to make enabling PAM modules very easy. The
<code>pam_mkhomedir.so</code> module is provided by
<a href="https://packages.debian.org/stretch/libpam-modules"><code>libpam-modules</code></a>.<br>
Unfortunately, (as of 1.1.8-3.6) there is no pam-config for <code>mkhomedir</code>.
(See <a href="https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=568577">Debian bug 568577</a>.)
However, we can simply download the file ourselves:</p>
<div class="highlight"><pre><span></span>wget -O /usr/share/pam-configs/mkhomedir https://browse.dgit.debian.org/pam.git/plain/debian/pam-configs/mkhomedir?h=debian/1.1.8-4
</pre></div>
<p>Now you can run <code>pam-auth-update</code> and select "Create home directory on login".</p>
<p><img alt="pam-auth-update screenshot" src="//jonathonreinhart.com/posts/blog/2019/02/26/configuring-winbind-on-a-samba-ad-dc-on-debian-9/20190226/pam-auth-update.png"></p>
<p>After logging in you should now have a valid home directory!</p>
<h2>Sudo</h2>
<p>The last piece of this puzzle we'll deal with here is <code>sudo</code>. As a common
example, we'll enable all members of the <code>Domain Admins</code> group to use <code>sudo</code>.</p>
<p>Rather than editing <code>/etc/sudoers</code>, we'll drop our custom sudo configuration
into to file in <code>/etc/sudoers.d</code>:</p>
<div class="highlight"><pre><span></span>visudo -f /etc/sudoers.d/domain-admins
</pre></div>
<p>Add this line, of course replacing <code>ONTHEFIVE</code> with your domain realm:</p>
<div class="highlight"><pre><span></span><span class="c">%ONTHEFIVE\\domain\ admins ALL=(ALL:ALL) NOPASSWD:ALL</span>
</pre></div>
<p>After logging in as a member of this group, you should be able to <code>sudo</code>!</p>
<h2>Kerberos + SSH</h2>
<p><em>Update:</em> Louis van Belle <a href="https://lists.samba.org/archive/samba/2019-March/221635.html">suggested</a>
also adding these packages:</p>
<ul>
<li><a href="https://packages.debian.org/stretch/ssh-krb5"><code>ssh-krb5</code></a></li>
<li>Updates <code>/etc/ssh/sshd_config</code> and sets <code>GSSAPIAuthentication</code> and
<code>GSSAPIKeyExchange</code> to <code>yes</code>.</li>
<li><a href="https://packages.debian.org/stretch/libpam-krb5"><code>libpam-krb5</code></a></li>
</ul>
<div class="highlight"><pre><span></span>cp sshd_config sshd_config.before-ssh-krb5
apt install ssh-krb5 libpam-krb5
</pre></div>
<p>With this, you can use Kerberos to authenticate when SSH-ing to the DC!</p>
<h1>References</h1>
<ul>
<li>SAMBA Wiki<ul>
<li><a href="https://wiki.samba.org/index.php/Configuring_Winbindd_on_a_Samba_AD_DC">Configuring Winbindd on a Samba AD DC</a></li>
<li><a href="https://wiki.samba.org/index.php/Setting_up_Samba_as_a_Domain_Member#Testing_the_Winbindd_Connectivity">Testing the Winbindd Connectivity</a></li>
</ul>
</li>
<li>SAMBA Docs<ul>
<li><a href="https://www.samba.org/samba/docs/current/man-html/smb.conf.5.html">smb.conf(5)</a></li>
<li><a href="https://www.samba.org/samba/docs/current/man-html/winbindd.8.html">wbindd(8)</a></li>
</ul>
</li>
<li><a href="https://wiki.debian.org/LDAP/PAM">LDAP/PAM - Debian Wiki</a></li>
</ul>Setting up a Samba 4 Domain Controller on Debian 92019-02-11T22:00:00-05:002019-02-11T22:00:00-05:00Jonathon Reinharttag:jonathonreinhart.com,2019-02-11:/posts/blog/2019/02/11/setting-up-a-samba-4-domain-controller-on-debian-9/<p>Let's set up Samba 4 to serve as an Active Directory (AD) Domain Controller
(DC) on Debian 9.</p>
<h1>Prerequisites</h1>
<p>We'll start with a headless install of Debian 9, selecting only "SSH server"
and "standard system utilities" during Software selection.</p>
<p>We'll also assume that your server is set up with the …</p><p>Let's set up Samba 4 to serve as an Active Directory (AD) Domain Controller
(DC) on Debian 9.</p>
<h1>Prerequisites</h1>
<p>We'll start with a headless install of Debian 9, selecting only "SSH server"
and "standard system utilities" during Software selection.</p>
<p>We'll also assume that your server is set up with the following:</p>
<ul>
<li>Static IP address (although a DHCP reservation also works)</li>
<li>Working DNS</li>
<li>Working NTP</li>
</ul>
<p>In this walkthrough, I'll be using the following configuration:</p>
<ul>
<li>NetBIOS domain (workgroup): <code>ONTHEFIVE</code></li>
<li>AD DNS domain: <code>ad.onthefive.com</code><ul>
<li>Kerberos realm is therefore <code>AD.ONTHEFIVE.COM</code></li>
<li>DNS for the AD domain will be delegated to the DC (main DNS provided by
another server)</li>
<li>Additional UPN Suffix: <code>onthefive.com</code></li>
</ul>
</li>
<li>DC hostname: <code>samba-dc</code></li>
</ul>
<p>Note that I've followed industry best practices by selecting a sub-domain of my
primary domain (<code>ad.onthefive.com</code>) to serve as the AD domain. I will also add
<code>onthefive.com</code> as an additional User Principal Name (UPN) Suffix so usernames
will match email addresses (and generally just look better).</p>
<h1>Procedure</h1>
<h2>Package Installation</h2>
<p>Simply installing the <code>samba</code> package includes almost everything we will need.
It does <em>not</em>, however, include <code>winbind</code> which is essential<sup>1</sup>. We'll also want
<code>smbclient</code> and <code>krb5-user</code> for local testing of AD services.</p>
<div class="highlight"><pre><span></span>apt install samba smbclient krb5-user winbind
</pre></div>
<p>When <code>krb5-user</code> is being set up, it will prompt you for the default Kerberos
realm. You can ignore this, as we will blow the configuration away later.</p>
<blockquote>
<p>Samba uses the MIT KDC provided by your operating system if you run Samba 4.7
or later and has been built using the <code>--with-system-mitkrb5</code> option. In
other cases Samba uses the Heimdal KDC included in Samba.</p>
</blockquote>
<p>Debian 9 ships with <code>Version 4.5.12-Debian</code>, so we'll be using the built-in
Heimdal KDC.</p>
<h2>Intermediate steps</h2>
<p>First, we need to remove the existing <code>smb.conf</code>:</p>
<div class="highlight"><pre><span></span>(cd /etc/samba && mv smb.conf smb.conf.orig)
</pre></div>
<p>Next, we need to adjust the Debian default settings for the samba services.
By default, systemd is set up to run <code>smbd</code>, <code>nmbd</code>, and <code>windbind</code> as separate
services, but we want to run the Samba AD DC service.</p>
<div class="highlight"><pre><span></span>systemctl stop smbd nmbd winbind
systemctl disable smbd nmbd winbind
systemctl mask smbd nmbd winbind
systemctl unmask samba-ad-dc
systemctl enable samba-ad-dc
</pre></div>
<h2>Provision</h2>
<p>Now that everything is ready, let's provision our Domain Controller.</p>
<div class="highlight"><pre><span></span><span class="ch">#!/bin/bash</span>
<span class="c1">################################################################################</span>
<span class="c1"># Config Options</span>
<span class="c1"># Kerberos realm -- also used (in lowercase) as AD DNS domain</span>
<span class="nv">REALM</span><span class="o">=</span><span class="s2">"AD.ONTHEFIVE.COM"</span>
<span class="c1"># NetBIOS domain name (Workgroup)</span>
<span class="nv">DOMAIN</span><span class="o">=</span><span class="s2">"onthefive"</span>
<span class="c1"># Initial Administrator password -- must meet complexity requirements</span>
<span class="nv">ADMINPASS</span><span class="o">=</span><span class="s2">"YourAdminPasswordGoesHere!1234"</span>
<span class="c1">################################################################################</span>
<span class="nb">set</span> -e
<span class="nv">smbconf</span><span class="o">=</span><span class="s2">"/etc/samba/smb.conf"</span>
<span class="k">if</span> <span class="o">[</span> -f <span class="nv">$smbconf</span> <span class="o">]</span><span class="p">;</span> <span class="k">then</span>
<span class="nb">echo</span> <span class="s2">"</span><span class="nv">$smbconf</span><span class="s2"> exists; remove and try again."</span>
<span class="nb">exit</span> <span class="m">1</span>
<span class="k">fi</span>
samba-tool domain provision <span class="se">\</span>
--use-rfc2307 <span class="se">\</span>
--server-role<span class="o">=</span>dc <span class="se">\</span>
--dns-backend<span class="o">=</span>SAMBA_INTERNAL <span class="se">\</span>
--realm<span class="o">=</span><span class="s2">"</span><span class="si">${</span><span class="nv">REALM</span><span class="si">}</span><span class="s2">"</span> <span class="se">\</span>
--domain<span class="o">=</span><span class="s2">"</span><span class="si">${</span><span class="nv">DOMAIN</span><span class="si">}</span><span class="s2">"</span> <span class="se">\</span>
--adminpass<span class="o">=</span><span class="s2">"</span><span class="si">${</span><span class="nv">ADMINPASS</span><span class="si">}</span><span class="s2">"</span>
</pre></div>
<p>Running that script, you should see output like this:</p>
<div class="highlight"><pre><span></span>...
A Kerberos configuration suitable for Samba 4 has been generated at /var/lib/samba/private/krb5.conf
Setting up fake yp server settings
Once the above files are installed, your Samba4 server will be ready to use
Server Role: active directory domain controller
Hostname: samba-dc
NetBIOS Domain: ONTHEFIVE
DNS Domain: ad.onthefive.com
DOMAIN SID: S-1-5-21-1234567890-987654321-123456789
</pre></div>
<p>Now we'll copy the <a href="https://linux.die.net/man/5/krb5.conf"><code>krb5.conf</code></a>
kerberos config file:</p>
<div class="highlight"><pre><span></span>mv /etc/krb5.conf /etc/krb5.conf.old
cp /var/lib/samba/private/krb5.conf /etc/krb5.conf
</pre></div>
<p>And finally, we'll start the Samba AD DC service:</p>
<div class="highlight"><pre><span></span>systemctl start samba-ad-dc
</pre></div>
<h2>Delegating DNS</h2>
<p>If you haven't done so yet, you'll now need to delegate your AD DNS zone.
In other words, configure your site's DNS server to refer requests for the
<code>ad.example.com</code> sub-domain to this domain controller.</p>
<p>In pfSense, these are called "Domain Overrides".</p>
<h2>Testing</h2>
<p>Now we need to test several services of AD. These tests are taken from the
Samba wiki.</p>
<h3>DNS</h3>
<p>We'll look up a few records in DNS to verify that the DNS server and delegation
are working. If any of these requests fail, we can append <code>localhost</code> to tell
<code>host</code> to try the local Samba DNS server, to narrow down the problem.</p>
<p>Look up the DC's AD DNS record:</p>
<div class="highlight"><pre><span></span># host -t A samba-dc.ad.onthefive.com
</pre></div>
<p>Now test the various SRV records used by AD:</p>
<div class="highlight"><pre><span></span># host -t SRV _ldap._tcp.ad.onthefive.com
# host -t SRV _kerberos._tcp.ad.onthefive.com
# host -t SRV _kerberos._udp.ad.onthefive.com
</pre></div>
<h3>Kerberos</h3>
<p>Request a Kerberos ticket for the domain admin account:</p>
<div class="highlight"><pre><span></span># kinit administrator
Password for administrator@AD.ONTHEFIVE.COM:
Warning: Your password will expire in 41 days on Sun 24 Mar 2019 11:38:22 PM EDT
</pre></div>
<p>List the cached Kerberos tickets:</p>
<div class="highlight"><pre><span></span># klist
Ticket cache: FILE:/tmp/krb5cc_0
Default principal: administrator@AD.ONTHEFIVE.COM
Valid starting Expires Service principal
02/10/2019 23:11:32 02/11/2019 09:11:32 krbtgt/AD.ONTHEFIVE.COM@AD.ONTHEFIVE.COM
renew until 02/11/2019 23:11:28
</pre></div>
<h3>File Server</h3>
<p>List all shares provided by the DC:</p>
<div class="highlight"><pre><span></span># smbclient -L localhost -U%
Domain=[ONTHEFIVE] OS=[Windows 6.1] Server=[Samba 4.5.12-Debian]
Sharename Type Comment
--------- ---- -------
netlogon Disk
sysvol Disk
IPC$ IPC IPC Service (Samba 4.5.12-Debian)
Domain=[ONTHEFIVE] OS=[Windows 6.1] Server=[Samba 4.5.12-Debian]
Server Comment
--------- -------
Workgroup Master
--------- -------
</pre></div>
<p>To verify authentication, connect to the <code>netlogon</code> share using the domain
administrator account:</p>
<div class="highlight"><pre><span></span># smbclient //localhost/netlogon -UAdministrator -c 'ls'
Enter Administrator's password:
Domain=[ONTHEFIVE] OS=[Windows 6.1] Server=[Samba 4.5.12-Debian]
. D 0 Sun Feb 10 22:38:11 2019
.. D 0 Sun Feb 10 22:38:22 2019
60631916 blocks of size 1024. 56430608 blocks available
</pre></div>
<h1>In the Domain</h1>
<h2>Join</h2>
<p>Now we're ready to join our first workstation to the domain! This process is
easy and readily-accessible elsewhere, so I won't repeat it here.</p>
<p>You'll also want a Windows workstation with the Active Directory tools installed:
<a href="https://www.itsupportguides.com/knowledge-base/windows-7/windows-7-how-to-install-the-active-directory-users-and-computers-tools/">Windows 7 – How to install the Active Directory Users and Computers tools</a></p>
<h2>Domain Configuration</h2>
<p>Now that we have a working domain, we need to take care of that UPN Suffix
before we go about adding users. This, too, is well-documented
<a href="https://www.petri.com/add-upn-suffixes-in-active-directory">elsewhere</a>, but
it's easy enough:</p>
<ul>
<li>Open <strong>Active Directory Domains and Trusts</strong>.</li>
<li>Right-click <strong>Active Directory Domains and Trusts</strong> in the left pane and select <strong>Properties</strong>.</li>
<li>On the <strong>UPN Suffixes</strong> tab, enter your UPN suffix and click <strong>Add</strong>:
<img alt="Adding an alternate UPN suffix" src="//jonathonreinhart.com/posts/blog/2019/02/11/setting-up-a-samba-4-domain-controller-on-debian-9/20190211/alt-upn-suffixes.png"></li>
</ul>
<p>Now when you add a new user in <strong>Active Directory Users and Computers</strong>, you'll
be able to select the new UPN suffix:
<img alt="New user UPN suffix" src="//jonathonreinhart.com/posts/blog/2019/02/11/setting-up-a-samba-4-domain-controller-on-debian-9/20190211/new-user-upn.png"></p>
<p>Unfortunately, <a href="https://serverfault.com/q/45576/55544">there is no way</a> to
change the default UPN Suffix used by this tool.</p>
<p>That's it for now!</p>
<h1>Footnotes</h1>
<h3>1 - <code>winbind</code></h3>
<p>I initially omitted <code>winbind</code> which was a big mistake. When trying to verify
the AD file server, I kept getting the error: <code>session setup failed: NT_STATUS_INTERNAL_ERROR</code>.</p>
<p>On the server I saw the following messages in <code>/var/log/samba/log.smbd</code>:</p>
<div class="highlight"><pre><span></span>[2019/02/11 21:10:02.679757, 1] ../source3/smbd/sesssetup.c:290(reply_sesssetup_and_X_spnego)
Failed to generate session_info (user and group token) for session setup: NT_STATUS_INTERNAL_ERROR
</pre></div>
<p>I finally found <a href="https://lists.samba.org/archive/samba/2017-November/212455.html">this message</a>
on the Samba mailing list which clued me in to the problem.</p>
<h1>References</h1>
<ul>
<li>SAMBA Wiki<ul>
<li><a href="https://wiki.samba.org/index.php/Distribution-specific_Package_Installation">Distribution-specific Package Installation</a></li>
<li><a href="https://wiki.samba.org/index.php/Setting_up_Samba_as_an_Active_Directory_Domain_Controller">Setting up Samba as an Active Directory Domain Controller</a></li>
<li><a href="https://wiki.samba.org/index.php/Managing_the_Samba_AD_DC_Service_Using_Systemd">Managing the Samba AD DC Service Using Systemd</a></li>
</ul>
</li>
<li><a href="https://www.tecmint.com/samba4-ad-dc-sysvol-replication/">Setup SysVol Replication Across Two Samba4 AD DC with Rsync – Part 6</a></li>
<li><a href="https://wiki.archlinux.org/index.php/Samba/Active_Directory_domain_controller">Samba/Active Directory domain controller - ArchWiki</a></li>
</ul>Windows-Python-PyInstaller GitLab CI Runner2016-11-16T20:33:00-05:002016-11-16T20:33:00-05:00Jonathon Reinharttag:jonathonreinhart.com,2016-11-16:/posts/blog/2016/11/16/windows-python-pyinstaller-gitlab-ci-runner/<p>Here I'll explain how to configure a Windows Server VM to act as a Python
(PyInstaller) build server, running as a GitLab CI runner.</p>
<h1>Procedure</h1>
<h2>Install Windows Server 2012 R2 "Server Core"</h2>
<p>This is left as an exercise to the reader :-)</p>
<h2>Enable Remote Desktop</h2>
<p>Simply follow this detailed guide:</p>
<p><a href="https://blogs.technet.microsoft.com/bruce_adamczak/2013/02/12/windows-2012-core-survival-guide-remote-desktop/">Windows …</a></p><p>Here I'll explain how to configure a Windows Server VM to act as a Python
(PyInstaller) build server, running as a GitLab CI runner.</p>
<h1>Procedure</h1>
<h2>Install Windows Server 2012 R2 "Server Core"</h2>
<p>This is left as an exercise to the reader :-)</p>
<h2>Enable Remote Desktop</h2>
<p>Simply follow this detailed guide:</p>
<p><a href="https://blogs.technet.microsoft.com/bruce_adamczak/2013/02/12/windows-2012-core-survival-guide-remote-desktop/">Windows 2012 Core Survival Guide – Remote Desktop</a></p>
<h2>Set up GitLab CI Runner</h2>
<ul>
<li>Create home directory<br>
<code>c:\users\gitlab-runner\</code></li>
<li>Create <code>gitlab-runner</code> account<br>
<code>net user gitlab-runner P@55w0rd</code></li>
<li>Grant permissions to the home directory<br>
<code>icacls c:\users\gitlab-runner gitlab-runner:(CI)(OI)(F)</code></li>
<li>Use <code>secedit</code> to add <code>SeServiceLogonRight</code> to user</li>
<li><code>gitlab-ci-multi-runner install --user .\gitlab-runner --password P@55w0rd</code></li>
<li><code>wmic useraccount GET Name,FullName,Status,Disabled,PasswordExpires /all</code></li>
<li><code>wmic useraccount WHERE "Name='gitlab-runner'" SET PasswordExpires=FALSE</code></li>
</ul>
<h2>Install Python</h2>
<ul>
<li>Install 32-bit MSI to <code>C:\Python27_32\</code> (Yes, add to <code>PATH</code>)</li>
<li>Install 64-bit MSI to <code>C:\Python27_64\</code></li>
<li>Install Pywin32 and Pypiwin32 (32 and 64)</li>
</ul>
<h2>Install PyInstaller</h2>
<ul>
<li><code>C:\Python27_32\python.exe setup.py install</code></li>
</ul>
<h2>Install Git</h2>
<p>You need to have Git installed for GitLab runner to fetch the code.</p>
<p>When installing, select <em>Use git commands in git bash and cmd</em>.</p>Fun experiences using Wine in Docker (part 2)2016-04-14T20:26:00-04:002016-04-14T20:26:00-04:00Jonathon Reinharttag:jonathonreinhart.com,2016-04-14:/posts/blog/2016/04/14/fun-experiences-using-wine-in-docker-part-2/<p>After the last post about running Wine in Docker, it was time to try and
actually use the image to perform a build.</p>
<p>The first time I tried, the build crashed due to some sort of exception. It
turns out the following sequence of events was to blame:</p>
<ul>
<li><code>NMAKE</code>, running …</li></ul><p>After the last post about running Wine in Docker, it was time to try and
actually use the image to perform a build.</p>
<p>The first time I tried, the build crashed due to some sort of exception. It
turns out the following sequence of events was to blame:</p>
<ul>
<li><code>NMAKE</code>, running under <code>wine</code>, loads <code>msvcrt80.dll</code></li>
<li>During its <code>DllMain</code>, this DLL calls <code>_wfindfirst64i32()</code>, passing it the
path to <code>Microsoft.VC80.CRT.mainfest</code></li>
<li>Internally, <code>_wfindfirst64i32</code> will:<ul>
<li>Call <code>FindFirstFileW</code> which returns a <code>WIN32_FIND_DATAW</code> structure, which
includes a <code>FILETIME</code> member for each of creation, last access, and last
write times.</li>
<li>Pass each of those timestamps to a function that:<ul>
<li>Calls <code>FileTimeToLocalFileTime</code> to convert it to local time</li>
<li>Calls <code>FileTimeToSystemTime</code> to convert it to a <code>SYSTEMTIME</code>
structure</li>
<li>Passes each member of the <code>SYSTEMTIME</code> structure as arguments to
another function, which raises an <code>INVALID_PARAMETER</code> exception
(<code>0xC000000D</code>) if the <code>Year</code> argument is not between 1970 and 3000,
inclusive</li>
</ul>
</li>
</ul>
</li>
</ul>
<p>When Docker, using its union filesystem, starts the container, the file access
times are zero, which is midnight, 1970-01-01. When this date is converted to
local time (in EST timezone, which is UTC-5), the timestamp is five hours
before midnight, 1970-01-01, which puts the year at 1969. This caused an
exception to be raised whenever <code>NMAKE</code> would run.</p>
<p>The solution was quite simple: Removing <code>/etc/localtime</code> made the system use
UTC time, which avoids the problem.</p>
<p><em>When I find my notes, I will explain how I leveraged WINE's debugging
facilities to track down this very elusive problem.</em></p>Fun experiences using Wine in Docker2016-04-13T21:21:00-04:002016-04-13T21:21:00-04:00Jonathon Reinharttag:jonathonreinhart.com,2016-04-13:/posts/blog/2016/04/13/fun-experiences-using-wine-in-docker/<h1>Background</h1>
<p>I sometimes work with a legacy codebase that targets both Windows and Linux;
the build system is GNU Make-based, and builds on Linux. For the Windows
components, the build system invokes <a href="https://msdn.microsoft.com/en-us/library/dd9y37ha.aspx%20target=">NMAKE</a>, using <a href="https://www.winehq.org/">Wine</a>. Yes,
it's messy; yes I want to replace it; but no there's no time budgeted …</p><h1>Background</h1>
<p>I sometimes work with a legacy codebase that targets both Windows and Linux;
the build system is GNU Make-based, and builds on Linux. For the Windows
components, the build system invokes <a href="https://msdn.microsoft.com/en-us/library/dd9y37ha.aspx%20target=">NMAKE</a>, using <a href="https://www.winehq.org/">Wine</a>. Yes,
it's messy; yes I want to replace it; but no there's no time budgeted right
now.</p>
<p>Lately, I've been moving more and more of our build infrastructure to
<a href="https://www.docker.com/">Docker</a>. It makes keeping the build environments up-to-date for
developers easier, and simplifies the setup for Continuous Integration. Check
out my tool, <a href="https://github.com/JonathonReinhart/scuba">Scuba</a> for using Docker to perform local builds, and
<a href="https://about.gitlab.com/gitlab-ci/">GitLab CI</a>.</p>
<p>You can see where this is going. I decided to convert our legacy build VM into
a Docker image; Wine and NMAKE included. I didn't know what I was getting
myself into.</p>
<h1>VM to Docker Image</h1>
<p>Of course, the right way to create a Docker image is to use a
<a href="https://docs.docker.com/engine/reference/builder/"><code>Dockerfile</code></a>. However, this current VM had experienced years of
tweaks, potentially relying on subtle toolchain-version-specific quirks. I
wasn't about to re-build it from scratch, so I decided to convert the VM
filesystem directly to a Docker image.</p>
<p>The initial conversion turned out to be straightforward. First, I cloned the
VM, so I could work destructively. Next, I uninstalled everything that wasn't
necessary for a Docker image (including KDE, X11, firewall, etc.) Then, I
powered down the cloned VM, and mounted its virtual disk under another VM,
running Docker. From there, it's as simple as using Tar to create the Docker
image:</p>
<div class="highlight"><pre><span></span><span class="c1"># cd /mnt/buildvm</span>
<span class="c1"># tar -c * | docker import --change='CMD /bin/bash' - buildsys:1</span>
</pre></div>
<p>This adds all of the directories from the mounted build VM disk, and creates a
tar stream which is piped into <code>docker import -</code> (where <code>-</code> means "from
standard input"). Note that I'm also setting the <code>CMD</code> to be <code>/bin/bash</code>; this
way, the image can be run by simply using <code>docker run -it buildsys:1</code>, without
having to specify <code>/bin/bash</code> every run.</p>
<p>After the initial conversion was done and I no longer needed to "boot" in the
conventional way, I continued to run the image, removing more stuff:</p>
<div class="highlight"><pre><span></span># You don't need a kernel when running under Docker,
# but don't want to remove other things that "depend" on it.
rpm -e --nodeps kernel-xxx
yum remove dracut grub plymouth
yum clean all && rm -rf /var/cache/yum
rm -rf /var/log/* /tmp/*
</pre></div>
<p>I definitely had to be careful not to remove things that Wine unexpectedly
relied upon. As I did this, I occasionally ran the image through a <code>docker
export</code> / <code>docker import</code> cycle to actually reduce the virtual size of the
image.</p>
<h1>Wine without X11</h1>
<p>The first time I tried to run <code>wine</code> in a Docker container, I was met with the
following warnings/errors:</p>
<div class="highlight"><pre><span></span>Application tried to create a window, but no driver could be loaded.
Make sure that your X server is running and that $DISPLAY is set correctly.
</pre></div>
<p>Googling for the error yielded some results from some other guys crazy enough
to try using Wine in Docker also, like <a href="https://superuser.com/q/902175/101823">this SuperUser post</a>
and <a href="https://github.com/monokrome/docker-wine">this GitHub project</a>. It seemed
that I would need some sort of X server after all, and that <a href="https://en.wikipedia.org/wiki/Xvfb">Xvfb</a>
(X Virtual FrameBuffer) was the solution.</p>
<p>You can simply run <code>xvfb-run wine whatever.exe</code>, and this will avoid the "no
$DISPLAY" problems. Great. However, I didn't want to change any of our build
scripts to have to run under Docker. Specifically, I didn't want to track down
every invocation of <code>wine</code> and prefix it with <code>xvfb-run</code>; what if we are
running on native X?</p>
<p>Instead, I came up with what I believe is a novel solution:
<strong>Specify the <a href="https://docs.docker.com/engine/reference/builder/#entrypoint"><code>ENTRYPOINT</code></a> in my <code>Dockerfile</code> to be <code>xvfb-run</code>.</strong>
This essentially prefixes the user's command with whatever is specified in
<code>ENTRYPOINT</code> - just what we want to do with <code>xvfb-run</code>. So the last time I
re-imported the tarball, I added <code>--change='ENTRYPOINT xvfb-run'</code>. There's
probably a way to do this after it's been imported, but this was the most
convenient at the time.</p>
<p>Now, when I run <code>docker run --rm -it buildsys:1 /bin/bash</code>, I can verify that
<code>$DISPLAY</code> is set, and Wine is happy. For now.</p>
<p>More to come...</p>Installing ESXi in a QEMU-KVM virtual machine2015-11-20T19:30:00-05:002015-11-20T19:30:00-05:00Jonathon Reinharttag:jonathonreinhart.com,2015-11-20:/posts/blog/2015/11/20/installing-esxi-in-a-qemu-kvm-virtual-machine/<p>For a test setup, it may be useful to install <a href="https://en.wikipedia.org/wiki/VMware_ESXi">VMware ESXi</a> in a
<a href="http://www.innervoice.in/blogs/2014/03/10/kvm-and-qemu/">QEMU-KVM</a> guest. If, like me, you're using <a href="https://libvirt.org/">libvirt</a>
(using <a href="https://virt-manager.org/"><code>virt-manager</code></a>) to manage your VMs, here's some
information to get this set up. I'm using Fedora 22, and ESXi 5.5.0.</p>
<p>There are other posts explaining …</p><p>For a test setup, it may be useful to install <a href="https://en.wikipedia.org/wiki/VMware_ESXi">VMware ESXi</a> in a
<a href="http://www.innervoice.in/blogs/2014/03/10/kvm-and-qemu/">QEMU-KVM</a> guest. If, like me, you're using <a href="https://libvirt.org/">libvirt</a>
(using <a href="https://virt-manager.org/"><code>virt-manager</code></a>) to manage your VMs, here's some
information to get this set up. I'm using Fedora 22, and ESXi 5.5.0.</p>
<p>There are other posts explaining how to set this up, but I wanted to share my
experience, which is specific to [<code>virt-manager</code>], and the newer QEMU.</p>
<h1>Procedure</h1>
<p>Here's a step-by-step procedure for getting this working.</p>
<h2>Add required KVM kernel module parameters</h2>
<ol>
<li>Edit (or create) <code>/etc/modprobe.d/kvm-intel.conf</code> to look like this:</li>
</ol>
<div class="highlight"><pre><span></span>options kvm ignore_msrs=1
options kvm-intel nested=y ept=y
</pre></div>
<ol>
<li>Remove the KVM module and re-load it with the new parameters:</li>
</ol>
<div class="highlight"><pre><span></span># modprobe -r kvm-intel kvm; modprobe kvm kvm-intel
</pre></div>
<h2>Setup ESXi VM guest configuration</h2>
<ol>
<li>Create your ESXi VM using virt-manager.</li>
<li>Change the NIC to vmxnet3. You'll have to manually type this in; it won't be
in the drop-down.</li>
<li>You'll need at least 2 GiB of RAM. (During install it actually came back
with:<br>
<code><MEMORY_SIZE ERROR: This host has 2.00 GiB of RAM. 3.97 GiB are needed></code></li>
<li>Edit the config for this VM (named <code>esxi-test</code> here):<br>
<code># virsh -c 'qemu:///system' edit esxi-test</code></li>
<li>Edit the first line of the XML file to be:<br>
<code><domain type='kvm' xmlns:qemu='http://libvirt.org/schemas/domain/qemu/1.0'></code></li>
<li>Change the CPU type:<br>
<code><cpu mode='host-passthrough'/></code></li>
<li>Add this block anywhere inside of <code><domain>...</domain></code>:</li>
</ol>
<div class="highlight"><pre><span></span> <span class="nt"><qemu:commandline></span>
<span class="nt"><qemu:arg</span> <span class="na">value=</span><span class="s">'-machine'</span><span class="nt">/></span>
<span class="nt"><qemu:arg</span> <span class="na">value=</span><span class="s">'vmport=off'</span><span class="nt">/></span>
<span class="nt"></qemu:commandline></span>
</pre></div>
<p>Save and quit.</p>
<h2>Go!</h2>
<p>Boot into the ESXi installer, and enjoy!</p>
<p>In <code>dmesg</code>, I see <code>kvm</code> spewing these messages, which probably have to do with
<code>ignore_msrs</code>:</p>
<div class="highlight"><pre><span></span>kvm [3864]: vcpu0 ignored rdmsr: 0x34
kvm [3864]: vcpu0 ignored rdmsr: 0x34
</pre></div>
<h2>ESXi 6.0.0 Notes</h2>
<p>I tried to use ESXi 6.0.0, but it didn't seem to find a network card, even
though I specified <code>vmnet3</code>. These notes apply to 6.0.0:
- The installer appears to hang at "user loaded successfully." for about 110
seconds. <code>Running nfcd start</code> also takes a while. I have no idea why.</p>
<h1>Resources</h1>
<ul>
<li><a href="https://rwmj.wordpress.com/2014/05/19/notes-on-getting-vmware-esxi-to-run-under-kvm/">Notes on getting VMware ESXi to run under KVM</a> (<em>rwmj.wordpress.com</em>)<ul>
<li>The patch to QEMU is no longer necessary; as of at least 2.3.1, QEMU
accepts the option: <code>-machine vmport=off</code> to accomplish the same.
(Here's the <a href="https://lists.gnu.org/archive/html/qemu-devel/2014-05/msg03806.html">patch adding the option</a>).</li>
</ul>
</li>
<li><a href="https://communities.vmware.com/thread/451412">ESXi inside KVM</a> (<em>communities.vmware.com</em>)<ul>
<li>This is the original thread where people managed to figure this out.</li>
</ul>
</li>
<li><a href="http://mattinaction.blogspot.com/2014/05/install-and-run-full-functional-vmware.html">Install and run a full functional VMware ESX Hypervisor within a KVM virtual
machine</a> (<em>mattinaction.blogspot.com</em>)<ul>
<li>Another blog post explaining the same</li>
</ul>
</li>
<li><a href="http://blog.vmsplice.net/2011/04/how-to-pass-qemu-command-line-options.html">How to pass QEMU command-line options through libvirt</a> (<em>blog.vmsplice.net</em>)</li>
<li><a href="https://software.intel.com/en-us/blogs/2014/12/12/enabling-virtual-machine-control-structure-shadowing-on-a-nested-virtual-machine">Enabling Virtual Machine Control Structure Shadowing On A Nested Virtual Machine</a>
(<em>software.intel.com</em>)<ul>
<li>Even though my CPU doesn't support nested VMCS, this was still useful,
and provided the clue to use <code>cpu mode='host-passthrough'</code></li>
</ul>
</li>
</ul>Common C programming mistakes2015-09-27T13:33:00-04:002015-09-27T13:33:00-04:00Jonathon Reinharttag:jonathonreinhart.com,2015-09-27:/posts/blog/2015/09/27/common-c-programming-mistakes/<p>I've decided to compile a list of common programming mistakes when using C.</p>
<h2>Random numbers</h2>
<p><strong>Q:</strong> Why is my program generating the same random numbers?<br>
<strong>A:</strong> You're probably re-seeding the PRNG. You should call <code>srand()</code> just
once, at the beginning of your program. From then on, just avoid concurrent
accesses …</p><p>I've decided to compile a list of common programming mistakes when using C.</p>
<h2>Random numbers</h2>
<p><strong>Q:</strong> Why is my program generating the same random numbers?<br>
<strong>A:</strong> You're probably re-seeding the PRNG. You should call <code>srand()</code> just
once, at the beginning of your program. From then on, just avoid concurrent
accesses to <code>rand()</code>.</p>Tools2015-07-09T16:27:00-04:002015-07-09T16:27:00-04:00Jonathon Reinharttag:jonathonreinhart.com,2015-07-09:/posts/blog/2015/07/09/tools/<p>Every geek has his/her favorite set of tools for accomplishing various tasks.
Here are mine.</p>
<p>I tend to split my time between Linux and Windows so where possible there will
be solutions for both. Preference is of course given to cross-platform <a href="https://en.wikipedia.org/wiki/Free_and_open-source_software">FOSS</a>
projects.</p>
<p>This will be updated as I …</p><p>Every geek has his/her favorite set of tools for accomplishing various tasks.
Here are mine.</p>
<p>I tend to split my time between Linux and Windows so where possible there will
be solutions for both. Preference is of course given to cross-platform <a href="https://en.wikipedia.org/wiki/Free_and_open-source_software">FOSS</a>
projects.</p>
<p>This will be updated as I run across new tools or inventory the ones I use.</p>
<ul>
<li>Markdown editing:<ul>
<li>Windows: <a href="https://cloose.github.io/CuteMarkEd/">CuteMarkEd</a></li>
<li>Linux: <a href="http://sourceforge.net/projects/retext/">ReText</a></li>
</ul>
</li>
</ul>Installing Zotero on Linux2015-01-28T03:42:00-05:002015-01-28T03:42:00-05:00Jonathon Reinharttag:jonathonreinhart.com,2015-01-28:/posts/blog/2015/01/28/installing-zotero-on-linux/<p>I've been playing with a new research tool called <a href="https://www.zotero.org/">Zotero</a>, which helps
you keep track of research papers, etc. as you come across them.</p>
<p>I'm using their <a href="https://www.zotero.org/support/installation">standalone version</a>, which Chrome can push
to via an extension. So far it seems <em>really</em> nice.</p>
<p>Zotero doesn't come with an installer on …</p><p>I've been playing with a new research tool called <a href="https://www.zotero.org/">Zotero</a>, which helps
you keep track of research papers, etc. as you come across them.</p>
<p>I'm using their <a href="https://www.zotero.org/support/installation">standalone version</a>, which Chrome can push
to via an extension. So far it seems <em>really</em> nice.</p>
<p>Zotero doesn't come with an installer on Linux, and I wanted to put it
somewhere more permanent than my <code>Downloads</code> directory. So I did the following
which makes Zotero feel very at home on my Centos 7 machine.</p>
<ol>
<li>
<p>Download the <a href="https://www.zotero.org/download/">Linux tar.bz2</a> file</p>
</li>
<li>
<p>Switch to root, and move the <code>tar.bz2</code> file to <code>/opt</code> and extract it. Then
rename the output directory:</p>
</li>
</ol>
<div class="highlight"><pre><span></span>$ sudo su -
<span class="c1"># mv Zotero-4.0.25.2_linux-x86_64.tar.bz2 /opt</span>
<span class="c1"># cd /opt</span>
<span class="c1"># tar xf Zotero-4.0.25.2_linux-x86_64.tar.bz2</span>
<span class="c1"># rm Zotero-4.0.25.2_linux-x86_64.tar.bz2</span>
<span class="c1"># mv Zotero_linux-x86_64 zotero</span>
</pre></div>
<ol>
<li>Retrieve the Zotero icon and add it to the <code>icons/</code> directory:</li>
</ol>
<div class="highlight"><pre><span></span># wget -O zotero/icons/zotero-new-z-48px.png https://raw.githubusercontent.com/zotero/zotero/4.0/chrome/skin/default/zotero/zotero-new-z-48px.png
</pre></div>
<ol>
<li>Now as your user, create the desktop shortcut, using this
<a href="https://gist.githubusercontent.com/JonathonReinhart/10cca56a5b6174c87018/raw/86459bc7f6c92029f9b536c3fedf903b907fef84/zotero.desktop"><code>.desktop</code></a> file I put together:</li>
</ol>
<div class="highlight"><pre><span></span># exit
$ wget -O ~/.local/share/applications/zotero.desktop http://goo.gl/BAJhYu
</pre></div>
<p>Note that the standalone version of Zotero keeps its local data in
<a href="https://www.zotero.org/support/zotero_data"><code>~/.zotero</code></a>. That's it! Enjoy!</p>My favorite Windows tweaks2015-01-26T01:59:00-05:002015-01-26T01:59:00-05:00Jonathon Reinharttag:jonathonreinhart.com,2015-01-26:/posts/blog/2015/01/26/my-favorite-windows-tweaks/<p>Here are some of my favorite Windows "tweaks":</p>
<ul>
<li><a href="http://www.sevenforums.com/tutorials/156518-show-hide-hidden-files-add-context-menu.html">Show - Hide Hidden Files - Add to Context Menu</a></li>
</ul><p>Here are some of my favorite Windows "tweaks":</p>
<ul>
<li><a href="http://www.sevenforums.com/tutorials/156518-show-hide-hidden-files-add-context-menu.html">Show - Hide Hidden Files - Add to Context Menu</a></li>
</ul>Installing rdesktop on Centos 72015-01-25T21:56:00-05:002015-01-25T21:56:00-05:00Jonathon Reinharttag:jonathonreinhart.com,2015-01-25:/posts/blog/2015/01/25/installing-rdesktop-on-centos-7/<p>I'll briefly summarize <a href="http://hasis053341.blogspot.com/2014/07/Rdesktop-on-centos-7.html">this blog post</a>
on installing <code>rdesktop</code> on Centos 7.</p>
<p>First, we'll set up the RPM build environment (as your local user):</p>
<div class="highlight"><pre><span></span>$ sudo yum install rpm-build make gcc
$ mkdir -p ~/rpmbuild/<span class="o">{</span>BUILD,RPMS,SOURCES,SPECS,SRPMS<span class="o">}</span>
$ <span class="nb">echo</span> <span class="s1">'%_topdir %(echo $HOME)/rpmbuild'</span> > ~/.rpmmacros
</pre></div>
<p>Now, fetch and install the source …</p><p>I'll briefly summarize <a href="http://hasis053341.blogspot.com/2014/07/Rdesktop-on-centos-7.html">this blog post</a>
on installing <code>rdesktop</code> on Centos 7.</p>
<p>First, we'll set up the RPM build environment (as your local user):</p>
<div class="highlight"><pre><span></span>$ sudo yum install rpm-build make gcc
$ mkdir -p ~/rpmbuild/<span class="o">{</span>BUILD,RPMS,SOURCES,SPECS,SRPMS<span class="o">}</span>
$ <span class="nb">echo</span> <span class="s1">'%_topdir %(echo $HOME)/rpmbuild'</span> > ~/.rpmmacros
</pre></div>
<p>Now, fetch and install the source package:</p>
<div class="highlight"><pre><span></span>$ wget http://pkgs.repoforge.org/rdesktop/rdesktop-1.8.2-0.1.rfx.src.rpm
$ rpm -i rdesktop-1.8.2-0.1.rfx.src.rpm
</pre></div>
<p>Install devel dependencies and build:</p>
<div class="highlight"><pre><span></span>$ sudo yum install openssl-devel libXt-devel libsamplerate-devel pcsc-lite-devel
$ rpmbuild -ba ~/rpmbuild/SPECS/rdesktop.spec
$ sudo yum localinstall ~rpmbuild/RPMS/x86_64/rdesktop-1.8.2-0.1.el7.centos.x86_64.rpm
</pre></div>Connecting to a Cisco ASA VPN with DoD CAC on CentOS 72015-01-24T18:28:00-05:002015-01-24T18:28:00-05:00Jonathon Reinharttag:jonathonreinhart.com,2015-01-24:/posts/blog/2015/01/24/connecting-to-a-cisco-asa-vpn-with-dod-cac-on-centos-7/<p><strong>Update:</strong> <em>I've created scripts to automate much of this process. You can find
them on <a href="https://github.com/JonathonReinhart/linux-cac-setup">GitHub</a></em>.</p>
<hr>
<p>I often need to connect to a <a href="https://en.wikipedia.org/wiki/Virtual_private_network">VPN</a> with a <a href="http://www.cisco.com/c/en/us/products/security/adaptive-security-appliance-asa-software/index.html">Cisco ASA</a> box at the
head-end, using a DoD <a href="https://en.wikipedia.org/wiki/Common_Access_Card">CAC</a> (<a href="https://en.wikipedia.org/wiki/Smart_card">smart card</a>) for authentication.</p>
<p>On Windows, this is often accomplished using Cisco's AnyConnect VPN …</p><p><strong>Update:</strong> <em>I've created scripts to automate much of this process. You can find
them on <a href="https://github.com/JonathonReinhart/linux-cac-setup">GitHub</a></em>.</p>
<hr>
<p>I often need to connect to a <a href="https://en.wikipedia.org/wiki/Virtual_private_network">VPN</a> with a <a href="http://www.cisco.com/c/en/us/products/security/adaptive-security-appliance-asa-software/index.html">Cisco ASA</a> box at the
head-end, using a DoD <a href="https://en.wikipedia.org/wiki/Common_Access_Card">CAC</a> (<a href="https://en.wikipedia.org/wiki/Smart_card">smart card</a>) for authentication.</p>
<p>On Windows, this is often accomplished using Cisco's AnyConnect VPN client
software. On Linux however, that option would never work for me. I tried to
download it from the VPN https site, but it wouldn't load.</p>
<p>On Linux, we have an open-source alternative, called <a href="http://www.infradead.org/openconnect/index.html"><code>openconnect</code></a>.
The difficult part is getting it to use our smart card, and present the correct
certificate to the VPN.</p>
<h2>Installation</h2>
<p>Several packages needed to be installed on my Fedora machine to get started.
Unfortunately, I don't remember all of them, but you should probably start with
this:</p>
<div class="highlight"><pre><span></span># yum install coolkey
# service pcscd start
</pre></div>
<h2>Configure <code>p11-kit</code></h2>
<p><code>openconnect</code> uses <a href="http://p11-glue.freedesktop.org/p11-kit.html"><code>p11-kit</code></a> to interact with PKCS #11 modules.
(<a href="https://en.wikipedia.org/wiki/PKCS_11">PKCS #11</a> is the standard for interfacing with cryptographic tokens,
like smart cards.) The first thing we need to do is tell <code>p11-kit</code> to use the
<code>libcoolkey</code> pkcs11 module. Do this by creating a new file named
<code>/etc/pkcs11/modules/libcoolkey.module</code>, and adding the following line to it:</p>
<div class="highlight"><pre><span></span><span class="n">module:</span>/<span class="n">usr</span><span class="o">/</span><span class="n">lib64</span><span class="o">/</span><span class="n">pkcs11</span><span class="o">/</span><span class="n">libcoolkeypk11</span>.<span class="o">so</span>
</pre></div>
<h2>Identify token and cert</h2>
<p>Next, we'll use <code>p11tool --list-tokens</code> to list all of the tokens on our
system. You should see your smart card in this list. Mine showed up like this
(along with others):</p>
<div class="highlight"><pre><span></span>$ p11tool --list-tokens
...
Token <span class="m">6</span>:
URL: pkcs11:model<span class="o">=</span><span class="p">;</span><span class="nv">manufacturer</span><span class="o">=</span><span class="p">;</span><span class="nv">serial</span><span class="o">=</span><span class="p">;</span><span class="nv">token</span><span class="o">=</span>REINHART.JONATHON.RICHARD.xxxxxxxx
Label: REINHART.JONATHON.RICHARD.xxxxxxxx
Manufacturer:
Model:
Serial:
</pre></div>
<p>Now, we want to look at all of the certificates available on our smart card.
We'll use <code>p11tool --list-all-certs <url></code>, where <code><url></code> is the URL of our
smart card token from the previous step:</p>
<div class="highlight"><pre><span></span>$ p11tool --list-all-certs pkcs11:model<span class="o">=</span><span class="p">;</span><span class="nv">manufacturer</span><span class="o">=</span><span class="p">;</span><span class="nv">serial</span><span class="o">=</span><span class="p">;</span><span class="nv">token</span><span class="o">=</span>REINHART.JONATHON.RICHARD.xxxx
Object <span class="m">0</span>:
URL: pkcs11:model<span class="o">=</span><span class="p">;</span><span class="nv">manufacturer</span><span class="o">=</span><span class="p">;</span><span class="nv">serial</span><span class="o">=</span><span class="p">;</span><span class="nv">token</span><span class="o">=</span>REINHART.JONATHON.RICHARD.xxxxxx<span class="p">;</span><span class="nv">id</span><span class="o">=</span>%01<span class="p">;</span><span class="nv">object</span><span class="o">=</span>CAC%20ID%20Certificate<span class="p">;</span>object-type<span class="o">=</span>cert
Type: X.509 Certificate
Label: CAC ID Certificate
ID: <span class="m">00</span>:01
Object <span class="m">1</span>:
URL: pkcs11:model<span class="o">=</span><span class="p">;</span><span class="nv">manufacturer</span><span class="o">=</span><span class="p">;</span><span class="nv">serial</span><span class="o">=</span><span class="p">;</span><span class="nv">token</span><span class="o">=</span>REINHART.JONATHON.RICHARD.xxxxxx<span class="p">;</span><span class="nv">id</span><span class="o">=</span>%02<span class="p">;</span><span class="nv">object</span><span class="o">=</span>CAC%20Email%20Signature%20Certificate<span class="p">;</span>object-type<span class="o">=</span>cert
Type: X.509 Certificate
Label: CAC Email Signature Certificate
ID: <span class="m">00</span>:02
Object <span class="m">2</span>:
URL: pkcs11:model<span class="o">=</span><span class="p">;</span><span class="nv">manufacturer</span><span class="o">=</span><span class="p">;</span><span class="nv">serial</span><span class="o">=</span><span class="p">;</span><span class="nv">token</span><span class="o">=</span>REINHART.JONATHON.RICHARD.xxxxxx<span class="p">;</span><span class="nv">id</span><span class="o">=</span>%03<span class="p">;</span><span class="nv">object</span><span class="o">=</span>CAC%20Email%20Encryption%20Certificate<span class="p">;</span>object-type<span class="o">=</span>cert
Type: X.509 Certificate
Label: CAC Email Encryption Certificate
ID: <span class="m">00</span>:03
</pre></div>
<p>So we can see the three certificates available on our smart card.</p>
<h2>Connect with certificate</h2>
<p>The Windows AnyConnect software will pop-up a dialog asking you to select the
certificate for authentication when the server asks for a client certificate.
<code>openconnect</code> currently has no such functionality, so we need to explicitly
tell it which certificate to use. In my case, I already knew it was the
certificate with <code>ID: 00:02</code>, the "CAC Email Signature Certificate". So I pass
the <code>-c</code> option, with the minimal URL to unambiguously refer to that
certificate:</p>
<div class="highlight"><pre><span></span>$ sudo openconnect -c <span class="s1">'pkcs11:token=REINHART.JONATHON.RICHARD.xxxxxx;id=%02'</span> vpn.example.com
</pre></div>
<p>Note that I had to use sudo because openconnect will invoke some scripts to set
up the <code>tun</code> device and routing.</p>
<p>At this point, <code>openconnect</code> should ask for your PIN, and then successfully
connect to the VPN! If not, you may need to try the other certificates, by
changing the <code>id=</code> part of the certificate URL.</p>
<h2>Notes</h2>
<p>There are still a few outstanding warnings that occur during this process:</p>
<ul>
<li><code>Certificate from VPN server "vpn.example.com" failed verification. Reason:
signer not found</code> - I need to determine which certificate this is exactly, and
how to add it to my trusted certificate store.</li>
</ul>
<p><em>Note: I've had to install various packages and make various changes in
playing with my smart card, so if something isn't working for you, or I've
skipped a step, please leave a comment so I can make this post more accurate.
Thanks!</em></p>
<p>Update: Additional steps - I'll work these in above at some point:</p>
<h1>Resources</h1>
<ul>
<li><a href="http://www.gooze.eu/forums/support/howto-connect-to-cisco-anyconnect-vpn-using-openconnect-and-pki-token">Howto: Connect to Cisco AnyConnect VPN using OpenConnect and PKI Token</a></li>
<li><a href="http://lists.infradead.org/pipermail/openconnect-devel/2012-July/000643.html">CAC modules</a> - <code>openconnect-devel</code> mailing list</li>
<li><a href="http://www.gnutls.org/manual/html_node/p11tool-Invocation.html"><code>p11tool</code> Invocation</a></li>
</ul>Adding storage to Proxmox VE2015-01-24T00:31:00-05:002015-01-24T00:31:00-05:00Jonathon Reinharttag:jonathonreinhart.com,2015-01-24:/posts/blog/2015/01/24/adding-storage-to-proxmox-ve/<p>The <a href="http://www.amazon.com/dp/B006G0V12O/?smid=AAXJV48TYCF6G">1 TB drives</a> for my HP server came today. Scott at
<a href="https://www.amazon.com/sp?seller=AAXJV48TYCF6G">All Computer Parts</a> was very helpful and quick to reply.
I quickly went to hot-plugging them into my server running <a href="https://pve.proxmox.com/wiki/Main_Page">Proxmox VE</a>.</p>
<h3>Create RAID</h3>
<p>After the drives spun-up, I logged into the <a href="http://www8.hp.com/us/en/products/server-software/product-detail.html?oid=344313">HP System Management Homepage</a>
(<a href="http://h20564.www2.hp.com/hpsc/swd/public/detail?swItemId=MTX_5154ce407f49401881413b0fa8">download</a>) and …</p><p>The <a href="http://www.amazon.com/dp/B006G0V12O/?smid=AAXJV48TYCF6G">1 TB drives</a> for my HP server came today. Scott at
<a href="https://www.amazon.com/sp?seller=AAXJV48TYCF6G">All Computer Parts</a> was very helpful and quick to reply.
I quickly went to hot-plugging them into my server running <a href="https://pve.proxmox.com/wiki/Main_Page">Proxmox VE</a>.</p>
<h3>Create RAID</h3>
<p>After the drives spun-up, I logged into the <a href="http://www8.hp.com/us/en/products/server-software/product-detail.html?oid=344313">HP System Management Homepage</a>
(<a href="http://h20564.www2.hp.com/hpsc/swd/public/detail?swItemId=MTX_5154ce407f49401881413b0fa8">download</a>) and opened the HP Array Configuration Utility.
From there, I selected 3 of the unassigned drives and created an array. I then
crated a RAID 5 logical drive using all of the space available on the array
(1.8 TB). Finally, I added the remaining drive as a hot-spare, by selecting
the array, and clicking "Spare Management". This way, if one drive goes
offline, the hot-spare will immediate take its place, and the array will be
rebuilt.</p>
<p><img alt="HP RAID" src="//jonathonreinhart.com/posts/blog/2015/01/24/adding-storage-to-proxmox-ve/20150124/raid.png"></p>
<p>The logical disk is immediately detected by the Linux kernel, evidenced by
<code>/var/log/messages</code>:</p>
<div class="highlight"><pre><span></span>Jan 23 22:38:40 dragster kernel: hpsa 0000:04:00.0: Direct-Access device c0b0t0l1 added.
Jan 23 22:38:40 dragster kernel: scsi 0:0:0:1: Direct-Access HP LOGICAL VOLUME 6.40 PQ: 0 ANSI: 5
Jan 23 22:38:40 dragster kernel: sd 0:0:0:1: Attached scsi generic sg3 type 0
Jan 23 22:38:40 dragster kernel: sd 0:0:0:1: [sdb] 3906918832 512-byte logical blocks: (2.00 TB/1.81 TiB)
Jan 23 22:38:40 dragster kernel: sd 0:0:0:1: [sdb] Write Protect is off
Jan 23 22:38:40 dragster kernel: sd 0:0:0:1: [sdb] Write cache: disabled, read cache: enabled, doesn't support DPO or FUA
Jan 23 22:38:40 dragster kernel: sdb: unknown partition table
Jan 23 22:38:40 dragster kernel: sd 0:0:0:1: [sdb] Attached SCSI disk
</pre></div>
<p>Proxmox <a href="http://pve.proxmox.com/wiki/Storage_Model#LVM_Groups_with_Local_Backing">works well with LVM</a>. It actually works directly with <a href="https://www.centos.org/docs/5/html/Cluster_Logical_Volume_Manager/LVM_definition.html">LVM</a>
volume groups, creating logical volumes on-the-fly for new VMs, etc. You can
find detailed information on the Proxmox wiki, but the procedure was quite
simple:</p>
<h3>Create LVM PV</h3>
<p>First, create the LVM physical volume on the physical disk: (In this case, the
"physical disk" was a RAID logical disk)</p>
<div class="highlight"><pre><span></span># pvcreate /dev/sdb
Physical volume "/dev/sdb" successfully created
</pre></div>
<p>Note that I created the physical volume directly on the block device, without
partitioning the drive. LVM <a href="http://serverfault.com/questions/439022/does-lvm-need-a-partition-table">does not require a partition table</a>,
and I'm not booting to the disk, so there was no need.</p>
<h3>Create LVM VG</h3>
<p>Next, create a LVM volume group from that single physical volume:</p>
<div class="highlight"><pre><span></span># vgcreate raid5vg /dev/sdb
Volume group "raid5vg" successfully created
</pre></div>
<p>And we're ready to go! List the LVM volume groups with the vgs command:</p>
<div class="highlight"><pre><span></span># vgs
VG #PV #LV #SN Attr VSize VFree
pve 1 3 0 wz--n- 67.83g 8.50g
raid5vg 1 1 0 wz--n- 1.82t 1.80t
</pre></div>
<h3>Add VG to Proxmox</h3>
<p>Now it's time to tell Proxmox about the new storage. Log into the Proxmox web
UI, and select the "Datacenter" node in the tree. On the <strong>Storage</strong> tab, select
<code>Add</code> > <code>LVM</code>. On that dialog, we select the new volume group and given it a name
(I made it the same as the vg).</p>
<p><img alt="Proxmox: Add LVM" src="//jonathonreinhart.com/posts/blog/2015/01/24/adding-storage-to-proxmox-ve/20150124/add-lvm.png"></p>
<p>And your storage is made available to Proxmox!</p>
<p>I went ahead and moved the couple VMs I had from the old main storage to the
new array. You can do this by highlighting the Hard Disk on the VM's <strong>Hardware</strong>
tab, and clicking <code>Move disk</code>.</p>Add Suspend and Hibernate to GNOME 3 shell status menu in CentOS 72015-01-10T07:15:00-05:002015-01-10T07:15:00-05:00Jonathon Reinharttag:jonathonreinhart.com,2015-01-10:/posts/blog/2015/01/10/add-suspend-and-hibernate-to-gnome-3-shell-status-menu-in-centos-7/<p>I spent days searching for the <em>Suspend</em> option in my new CentOS 7
installation.</p>
<p>Well, I finally found it, but it wasn't as easy as you'd expect.</p>
<p><img alt="GNOME suspend menu option" src="//jonathonreinhart.com/posts/blog/2015/01/10/add-suspend-and-hibernate-to-gnome-3-shell-status-menu-in-centos-7/20150110/suspend-menu.png"></p>
<p>First you need to install a couple things:</p>
<div class="highlight"><pre><span></span>$ sudo yum install gnome-shell-extension-alternative-status-menu gnome-tweak-tool
</pre></div>
<p>Next, log-out and log back in.</p>
<p>Then, use <code>gnome-tweak-tool</code> to …</p><p>I spent days searching for the <em>Suspend</em> option in my new CentOS 7
installation.</p>
<p>Well, I finally found it, but it wasn't as easy as you'd expect.</p>
<p><img alt="GNOME suspend menu option" src="//jonathonreinhart.com/posts/blog/2015/01/10/add-suspend-and-hibernate-to-gnome-3-shell-status-menu-in-centos-7/20150110/suspend-menu.png"></p>
<p>First you need to install a couple things:</p>
<div class="highlight"><pre><span></span>$ sudo yum install gnome-shell-extension-alternative-status-menu gnome-tweak-tool
</pre></div>
<p>Next, log-out and log back in.</p>
<p>Then, use <code>gnome-tweak-tool</code> to enable the fancy new extension:</p>
<p><img alt="GNOME tweak tool: Shell Extensions" src="//jonathonreinhart.com/posts/blog/2015/01/10/add-suspend-and-hibernate-to-gnome-3-shell-status-menu-in-centos-7/20150110/tweak-tool.png"></p>
<p>And there you have it; a menu that Windows has had by default for a decade.</p>Dual Booting with GRUB2 (CentOS 7) and Windows 72015-01-03T02:17:00-05:002015-01-03T02:17:00-05:00Jonathon Reinharttag:jonathonreinhart.com,2015-01-03:/posts/blog/2015/01/03/dual-booting-with-grub2-centos-7-and-windows-7/<p><strong>TL;DR:</strong> You need to install the <code>ntfs-3g</code> package, in order for <code>os-prober</code>
to detect Windows installations. This allows <code>grub2-mkconfig</code> to automatically
generate an entry for dual-booting into Windows.</p>
<hr>
<p>Doing a lot more hardware hacking these days, I've felt constrained running
Linux in a VM all the time. I was …</p><p><strong>TL;DR:</strong> You need to install the <code>ntfs-3g</code> package, in order for <code>os-prober</code>
to detect Windows installations. This allows <code>grub2-mkconfig</code> to automatically
generate an entry for dual-booting into Windows.</p>
<hr>
<p>Doing a lot more hardware hacking these days, I've felt constrained running
Linux in a VM all the time. I was especially disappointed that <a href="https://www.virtualbox.org/ticket/4032">VirtualBox
doesn't expose nested Intel VT-x</a> features to its guests. So
I've decided to try dual-booting again, going with the very stable <a href="http://www.centos.org/download/">CentOS 7</a>.</p>
<p>Not willing to sacrifice any space on my Windows SSD, I put another Crucial SSD
in my machine - this time the <a href="https://www.google.com/shopping/product/18358276604549477971">256 GB version of their newer MX100
series</a>. Downloading the NetInstall ISO and pointing at a relatively
close mirror gave a very satisfying install experience. Having the whole drive
made things quite easy as well - except for the actual Dual-Booting part.</p>
<p>I wasn't terribly surprised that the setup process didn't automatically add a
<a href="https://fedoraproject.org/wiki/GRUB_2?rd=Grub2">GRUB 2</a> entry for booting to my Windows 7 drive. Everything I read
indicated that simply running <code>grub2-mkconfig</code> should set up the GRUB config
script to include Windows. Yet, it wasn't working for me. Supposedly GRUB 2
uses <code>os-prober</code> to automatically detect other OSes and generate boot entries
for them. However, running <code>os-prober</code> showed no Windows install, even though
my drive was clearly visible.</p>
<p>After stumbling across <a href="http://www.linuxquestions.org/questions/linux-newbie-8/centos-7-dual-boot-with-windows-4175514202/page2.html#post5224749">this post on LinuxQustions.org</a>, it turns out
that the <a href="http://en.wikipedia.org/wiki/NTFS-3G">NTFS-3g</a> package (for mounting NTFS volumes) isn't installed
by default, and <code>os-prober</code> needs this the mount the drive and detect the
installed OS. After installing <code>ntfs-3g</code> (from the EPEL repository), I was able
to run <code>grub2-mkconfig -o /boot/grub2/grub.cfg</code> and successfully add an entry
for Windows 7.</p>Installing Nemiver on Centos 72014-12-30T06:59:00-05:002014-12-30T06:59:00-05:00Jonathon Reinharttag:jonathonreinhart.com,2014-12-30:/posts/blog/2014/12/30/installing-nemiver-on-centos-7/<p>I recently heard about <a href="https://wiki.gnome.org/Apps/Nemiver">Nemiver</a>,
a standalone C/C++ debugger for GNOME, and wanted to give it a try. </p>
<p>My current Linux development box is running CentOS 7. While <a href="http://pkgs.org/centos-6/epel-x86_64/nemiver-0.8.2el6-1.el6.x86_64.rpm.html">Nemiver packages
exist for CentOS 6</a>,
the same cannot be said for CentOS 7. So I proceeded to build it from …</p><p>I recently heard about <a href="https://wiki.gnome.org/Apps/Nemiver">Nemiver</a>,
a standalone C/C++ debugger for GNOME, and wanted to give it a try. </p>
<p>My current Linux development box is running CentOS 7. While <a href="http://pkgs.org/centos-6/epel-x86_64/nemiver-0.8.2el6-1.el6.x86_64.rpm.html">Nemiver packages
exist for CentOS 6</a>,
the same cannot be said for CentOS 7. So I proceeded to build it from source.</p>
<p>First, I went ahead and cloned the Git repository: <code>git clone git://git.gnome.org/nemiver</code></p>
<p>After running the <code>./autogen.sh script</code>, it was clear that I was in for several
iterations of dependency installation. I'll save you the trouble:</p>
<p><code>sudo yum install gnome-common intltool yelp-devel yelp-tools boost-devel
sqlite-devel GConf2-devel libgtop2-devel glibmm24-devel gtkmm30-devel
gtk3-devel gtksourceview3-devel vte3 vte3-devel</code></p>
<p>Note that I do have the EPEL repository enabled, so I'm not sure if some of
those packages came from EPEL or not.</p>
<p>Unfortunately, there seems to be no <code>gtksourceviewmm-3.0</code> package for CentOS 7
either! Sure, why not install that one from source, too?</p>
<p>First, download <a href="http://pkgs.fedoraproject.org/repo/pkgs/gtksourceviewmm3/"><code>gtksourceviewmm-3.2.0.tar.xz</code></a>
(or later). By default, <code>configure</code> defaults to <code>PREFIX=/usr/local</code>. If you don't
change this, <code>pkg-config</code> won't know where do find it. So
<code>./configure --prefix=/usr --libdir=/usr/lib64</code> seems to be what we want.
Then <code>make</code>, <code>sudo make install</code> as usual.</p>
<p>Now, you should be able to finish configuring and making Nemiver!</p>
<p>Note that there also seemed to be a build issue in
<code>src/confmgr/nmv-gconf-mgr.cc</code>. The following patch took care of it for me -
not sure how this went unnoticed.</p>
<div class="highlight"><pre><span></span><span class="gd">--- a/src/confmgr/nmv-gconf-mgr.cc</span>
<span class="gi">+++ b/src/confmgr/nmv-gconf-mgr.cc</span>
<span class="gu">@@ -32,6 +32,7 @@</span>
NEMIVER_BEGIN_NAMESPACE (nemiver)
using nemiver::common::GCharSafePtr;
<span class="gi">+using nemiver::common::GErrorSafePtr;</span>
class GConfMgr : public IConfMgr {
GConfMgr (const GConfMgr &);
</pre></div>GitLab time zone issues2014-10-23T18:13:00-04:002014-10-23T18:13:00-04:00Jonathon Reinharttag:jonathonreinhart.com,2014-10-23:/posts/blog/2014/10/23/gitlab-time-zone-issues/<p><a href="https://about.gitlab.com/">GitLab</a> is a great open source GitHub clone, which
I've started using for tracking my personal Git repos.</p>
<p>One frustrating thing I've found with GitLab however, is its handling of time zones.</p>
<p>Read:</p>
<ul>
<li><a href="https://github.com/gitlabhq/gitlabhq/issues/7049">Wrong time on gitlab events #7049</a></li>
<li><a href="http://feedback.gitlab.com/forums/176466-general/suggestions/5742594-allow-user-to-select-their-timezone-in-profile">Allow user to select their timezone in profile</a></li>
<li><a href="http://feedback.gitlab.com/forums/176466-general/suggestions/5890076-add-timezone-configuration-to-gitlab-yml">Add timezone configuration …</a></li></ul><p><a href="https://about.gitlab.com/">GitLab</a> is a great open source GitHub clone, which
I've started using for tracking my personal Git repos.</p>
<p>One frustrating thing I've found with GitLab however, is its handling of time zones.</p>
<p>Read:</p>
<ul>
<li><a href="https://github.com/gitlabhq/gitlabhq/issues/7049">Wrong time on gitlab events #7049</a></li>
<li><a href="http://feedback.gitlab.com/forums/176466-general/suggestions/5742594-allow-user-to-select-their-timezone-in-profile">Allow user to select their timezone in profile</a></li>
<li><a href="http://feedback.gitlab.com/forums/176466-general/suggestions/5890076-add-timezone-configuration-to-gitlab-yml">Add timezone configuration to gitlab.yml</a></li>
</ul>
<p>Apparently GitLab doesn't detect the user's timezone (or store it in their
profile) and display times accordingly. Everything outside of the Git
timestamps appears to be tracked in UTC.</p>
<p>To fix this for my local server, I edited <code>/opt/gitlab/embedded/service/gitlab-rails/config/application.rb</code>
and specified <code>config.time_zone = 'Eastern Time (US & Canada)'</code>.</p>
<h2>Update:</h2>
<p>In <a href="https://gitlab.com/gitlab-org/gitlab-ce/blob/7-7-stable/CHANGELOG">version 7.5.0</a>,
this configuration option was moved to <code>gitlab.yml</code>. Now you don't have to re-set
this option after every upgrade. Instructions for how to set it for an Omnibus
install (in <code>/etc/gitlab/gitlab.rb</code>) are <a href="https://github.com/gitlabhq/gitlabhq/pull/8015#issuecomment-72840835">here</a>.</p>TrueCrypt-end2014-05-28T11:31:00-04:002014-05-28T11:31:00-04:00Jonathon Reinharttag:jonathonreinhart.com,2014-05-28:/posts/blog/2014/05/28/truecrypt-end/<p>Today, the TrueCrypt website and SourceForge project page suddenly changed,
indicating the end of TrueCrypt development. <code>truecrypt.org</code> now redirects to
their <a href="http://truecrypt.sourceforge.net/">SourceForge project page</a>, and the content has been
replaced with a surprising message: </p>
<p><img alt="TrueCrypt End" src="//jonathonreinhart.com/posts/blog/2014/05/28/truecrypt-end/truecrypt-end.png"></p>
<p>Not only has development officially ceased, but TrueCrypt is being declared
"not secure", and the …</p><p>Today, the TrueCrypt website and SourceForge project page suddenly changed,
indicating the end of TrueCrypt development. <code>truecrypt.org</code> now redirects to
their <a href="http://truecrypt.sourceforge.net/">SourceForge project page</a>, and the content has been
replaced with a surprising message: </p>
<p><img alt="TrueCrypt End" src="//jonathonreinhart.com/posts/blog/2014/05/28/truecrypt-end/truecrypt-end.png"></p>
<p>Not only has development officially ceased, but TrueCrypt is being declared
"not secure", and the official webpage is suggesting that people <em>migrate to
BitLocker!</em> (<a href="http://windows.microsoft.com/en-us/windows7/products/features/bitlocker">BitLocker</a> is the drive encryption solution built in
to some versions of Windows Vista and later.) Furthermore, a new version 7.2
had been released, which warns users that TrueCrypt is insecure. The repository
had been scrubbed, and all previous binaries had been deleted.</p>
<p>I'm sure you could almost hear the collective <strong>WTF?!</strong> from everyone in the
InfoSec community.</p>
<p>A series of edits indicating that the software had been discontinued were even
posted to the [TrueCrypt Wikipedia][trucrypt-wiki] page by a user with the
handle <a href="http://en.wikipedia.org/wiki/Special:Contributions/Truecrypt-end">Truecrypt-end</a>.</p>
<p>At first, it seemed like some pranksters had managed to take over the TrueCrypt
website, and poke fun by suggesting users migrate to their inferior commercial
competitor, BitLocker. Well, the <a href="http://dnshistory.org/dns-records/truecrypt.org">DNS records had not changed</a>,
so everything was good there. And <a href="https://news.ycombinator.com/item?id=7813121">SourceForge indicated</a> that there
was no suspicious behavior on the account (ya know, aside from closing
everything down!)</p>
<p>Of course there are rumors abound at all of the tech watering holes, from
<a href="http://it-beta.slashdot.org/story/14/05/28/2126249/truecrypt-website-says-to-switch-to-bitlocker">Slashdot</a> to the <a href="http://www.reddit.com/r/sysadmin/comments/26pxol/truecrypt_is_dead/"><code>/r/sysadmin</code> subreddit</a> to the
<a href="http://security.stackexchange.com/q/58940/35748">InfoSec Stack Exchange</a> site and of course <a href="https://twitter.com/hashtag/TrueCrypt?src=hash">Twitter</a>.
While many still believe that the project was hacked, others are pondering the
possibility that the devs were asked to insert a back-door, and subject to a
gag-order preventing them from disclosing the requirement. The TrueCrypt
development team has remained behind the big black curtain for most of its
development which makes the situation even more curious. Perhaps a
vulnerability had been discovered and the developers simply didn't want to be
involved with the product any more. There is certainly no <a href="https://news.ycombinator.com/item?id=7812133">shortage of
opinions</a> on the matter. The most interesting theory I've heard is that
this is a sort of <a href="http://www.reddit.com/r/netsec/comments/26pz9b/truecrypt_development_has_ended_052814/">warrant canary</a>.</p>
<h3>So what about this new version 7.2?</h3>
<p>The binaries were <a href="http://www.reddit.com/r/netsec/comments/26pz9b/truecrypt_development_has_ended_052814/chtl7jb">signed with the same GPG key</a> as all previous
releases, indicating that this release was "official", or at least produced by
someone with access to the private key.</p>
<p>Internally, the <code>TrueCrypt.exe</code> executable and the <code>truecrypt(-x64).sys</code>
drivers were signed (a la Microsoft Authenticode) with a different certificate
than 7.1.1, but that previous certificate expired shortly after the last
release. This new certificate was issued (to the same named entity) shortly
before the previous certificate expired. It's very unlikely that someone was
able to spoof a new certificate in this manner, and had planned it two years
ago. [Screenshots tomorrow.]</p>
<p>The <a href="https://github.com/warewolf/truecrypt/compare/master...7.2">changes to the latest</a> version's source code were posted to
GitHub. This paints probably the most confusing picture of all. </p>
<p>First, the code has been littered with warning messages and error codes
indicating that <a href="https://github.com/warewolf/truecrypt/compare/master...7.2#diff-ab89cf3b379504f57d3f2655ad8c60a1R79">"Using TrueCrypt is not secure"</a>.</p>
<p>Next, we see that pretty much all of the code related to creating encrypted
volumes has been removed, and replaced with <code>AbortProcess("INSECURE_APP");</code>.
We also notice that all code related to updates, <a href="https://github.com/warewolf/truecrypt/compare/master...7.2#diff-9fc90217decda8d7d16d55ffaf7401c0L1657">error reporting</a>,
<a href="https://github.com/warewolf/truecrypt/compare/master...7.2#diff-9fc90217decda8d7d16d55ffaf7401c0L7987">user's guide/help</a>, or <a href="https://github.com/warewolf/truecrypt/compare/master...7.2#diff-d588c1a136d84cbb36c875bee73e0925L782">anything pointing back to the TrueCrypt website</a>
has been removed. Clearly, the developers consciously made the decision to
burn all bridges, and carefully executed a plan to do so.</p>
<p>What's very bizarre however, is that while there were 4112 deletions, there
were also 1760 additions to the code. Along with other minor bugfixes, it
appears that <a href="https://github.com/warewolf/truecrypt/compare/master...7.2#diff-21d38496be9ec14e4db3819ba7f36835R6989">in-place decryption</a> was newly implemented. It
looks as if this was code that was part of an upcoming release that brought
some improvements after a two-year break. Unfortunately, it also came with mass
deletions that rendered the software useless for anyone seeking to create
encrypted content.</p>
<p><em>What are you thoughts?</em></p>Gotta catch 'em all: Last-chance exception handling in .NET with WinForms2013-03-07T01:31:00-05:002013-03-07T01:31:00-05:00Jonathon Reinharttag:jonathonreinhart.com,2013-03-07:/posts/blog/2013/03/07/gotta-catch-em-all-last-chance-exception-handling-in-net-with-winforms/<p>Recently, I went through the exercise of hooking up a crash-reporting component
to a large .NET application using Windows Forms. The goal, of course, is to
catch all unhandled exceptions so they can be reported to the developer.</p>
<p>Throughout this post I'll be referring to this <code>Program.cs</code>:</p>
<script src="https://gist.github.com/JonathonReinhart/9e4cb8c545bd59e96761635bc25dabd8.js"></script>
<p>The code …</p><p>Recently, I went through the exercise of hooking up a crash-reporting component
to a large .NET application using Windows Forms. The goal, of course, is to
catch all unhandled exceptions so they can be reported to the developer.</p>
<p>Throughout this post I'll be referring to this <code>Program.cs</code>:</p>
<script src="https://gist.github.com/JonathonReinhart/9e4cb8c545bd59e96761635bc25dabd8.js"></script>
<p>The code will be incrementally un-commented for each of the examples. I'll
also link to compiled example executables. If you don't trust my binaries, you
can <a href="http://jonathon.onthefive.com/public/WinFormExceptions/WinformsExceptionsTest.zip">compile them yourself</a>.</p>
<hr>
<h1>Exception-handling progression</h1>
<h2>0. No exception handling</h2>
<p>First we see an application that throws exceptions in the UI thread and a
background thread, with no handling. Try out <a href="http://jonathon.onthefive.com/public/WinFormExceptions/0_Nothing.exe"><code>0_Nothing.exe</code></a>.</p>
<p>With no exception handling, background thread exceptions crash hard. UI thread
exceptions are handled by the built-in .NET WinForms handler:</p>
<p><img alt="Unhandled exception message" src="//jonathonreinhart.com/posts/blog/2013/03/07/gotta-catch-em-all-last-chance-exception-handling-in-net-with-winforms/unhandled-exception.png"></p>
<p>This dialog has a <strong>Continue</strong> option which allows the user to ignore the
exception and go on. This method is absolutely unacceptable. No exceptions
should ever be allowed to be ignored, as the program is in an indeterminate
state.</p>
<h2>1. try / catch</h2>
<p>The naive approach would be to set up a <code>try</code>/<code>catch</code> block in <code>Main()</code> around
the <code>Application.Run()</code> call. See <a href="http://jonathon.onthefive.com/public/WinFormExceptions/1_TryCatch.exe"><code>1_TryCatch.exe</code></a>.</p>
<div class="highlight"><pre><span></span><span class="k">try</span> <span class="p">{</span>
<span class="n">Application</span><span class="p">.</span><span class="n">Run</span><span class="p">(</span><span class="k">new</span> <span class="n">Form1</span><span class="p">());</span>
<span class="p">}</span>
<span class="k">catch</span> <span class="p">(</span><span class="n">Exception</span> <span class="n">ex</span><span class="p">)</span> <span class="p">{</span>
<span class="c1">// ...</span>
<span class="p">}</span>
</pre></div>
<p>We see here that there is no difference between this and the version with no
<code>try</code>/<code>catch</code>. This is because the UI thread exceptions are still being handled
inside of <code>Application.Run()</code> by the default handler. The <code>try</code>/<code>catch</code> is
never used, and background thread exceptions are unaffected.</p>
<h2>2. <code>Application.ThreadException</code></h2>
<p>Next, we utilize WinForms' <a href="http://msdn.microsoft.com/en-us/library/system.windows.forms.application.threadexception.aspx"><code>Application.ThreadException</code></a>
event to handle UI thread exceptions. See
<a href="http://jonathon.onthefive.com/public/WinFormExceptions/2_Application_ThreadException.exe"><code>2_Application_ThreadException.exe</code></a>.</p>
<div class="highlight"><pre><span></span><span class="n">Application</span><span class="p">.</span><span class="n">ThreadException</span> <span class="p">+=</span> <span class="p">(</span><span class="n">sender</span><span class="p">,</span> <span class="n">args</span><span class="p">)</span> <span class="p">=></span>
<span class="n">HandleException</span><span class="p">(</span><span class="s">"Application.ThreadException"</span><span class="p">,</span> <span class="n">args</span><span class="p">.</span><span class="n">Exception</span><span class="p">);</span>
</pre></div>
<p>Here, we see that instead of the unacceptable WinForms handler, our handler was
called (for UI thread exceptions). However, as MSDN points out:</p>
<blockquote>
<p>This event allows your Windows Forms application to handle otherwise
unhandled exceptions that occur in Windows Forms threads.<br>
...<br>
To catch exceptions that occur in threads not created and owned by Windows
Forms, use the <a href="http://msdn.microsoft.com/en-us/library/system.appdomain.unhandledexception.aspx"><code>UnhandledException</code></a> event handler.</p>
</blockquote>
<p>So background thread exceptions still crash hard in this example.</p>
<h2>3. <code>AppDomain.UnhandledException</code></h2>
<p>Now we follow the documentation and hook up the
<a href="http://msdn.microsoft.com/en-us/library/system.appdomain.unhandledexception.aspx"><code>AppDomain.UnhandledException</code></a> handler. See
<a href="http://jonathon.onthefive.com/public/WinFormExceptions/3_AppDomain_UnhandledException_NoUhandledMode.exe"><code>3_AppDomain_UnhandledException_NoUhandledMode.exe</code></a>.</p>
<div class="highlight"><pre><span></span><span class="n">AppDomain</span><span class="p">.</span><span class="n">CurrentDomain</span><span class="p">.</span><span class="n">UnhandledException</span> <span class="p">+=</span> <span class="p">(</span><span class="n">sender</span><span class="p">,</span> <span class="n">args</span><span class="p">)</span> <span class="p">=></span>
<span class="n">HandleException</span><span class="p">(</span><span class="s">"AppDomain.UnhandledException"</span><span class="p">,</span> <span class="p">(</span><span class="n">Exception</span><span class="p">)</span><span class="n">args</span><span class="p">.</span><span class="n">ExceptionObject</span><span class="p">);</span>
</pre></div>
<p>Now finally, we are able to catch exceptions on background threads with this
handler. UI thread exceptions, however, are still handled by our
<code>Application.ThreadException</code> handler.</p>
<h2>4. <code>Application.SetUnhandledExceptionMode</code></h2>
<p>As mentioned in the MSDN documentation, a call to
<a href="http://msdn.microsoft.com/en-us/library/system.windows.forms.application.setunhandledexceptionmode.aspx"><code>Application.SetUnhandledExceptionMode</code></a> and passing
<a href="http://msdn.microsoft.com/en-us/library/system.windows.forms.unhandledexceptionmode.aspx"><code>UnhandledExceptionMode.ThrowException</code></a>
tells Winforms to not use the <code>Application.ThreadException</code> handler.
Instead, it lets exceptions bubble out of <code>Application.Run</code>.
See this in <a href="http://jonathon.onthefive.com/public/WinFormExceptions/4_Everything.exe"><code>4_Everything.exe</code></a>.</p>
<div class="highlight"><pre><span></span><span class="n">Application</span><span class="p">.</span><span class="n">SetUnhandledExceptionMode</span><span class="p">(</span><span class="n">UnhandledExceptionMode</span><span class="p">.</span><span class="n">ThrowException</span><span class="p">);</span>
</pre></div>
<p>The result is that the try/catch around Application.Run actually works now: UI thread exceptions are now caught by that handler.</p>
<h2>5. No more try / catch</h2>
<p>Finally, removing the <code>try</code>/<code>catch</code> around <code>Application.Run</code> allows for all
unhandled exceptions to be handled via <code>AppDomain.UnhandledException</code>. See
<a href="http://jonathon.onthefive.com/public/WinFormExceptions/5_Final.exe"><code>5_Final.exe</code></a>. This is how we ended up handling everything in our
application; we found it ideal to have one route for <em>all</em>
unhandled exceptions...</p>
<p>In fact it gets even more complicated. There are certain scenarios where
exceptions that need to cross Kernel or COM boundaries can be swallowed. For
example, the <code>Form.OnLoad</code> method is actually a user-mode kernel callback.
These are <a href="http://blog.paulbetts.org/index.php/2010/07/20/the-case-of-the-disappearing-onload-exception-user-mode-callback-exceptions-in-x64/">notorious</a> for swallowing exceptions. In cases where we
are sufficiently suspect of exceptions, we set up a <code>try</code>/<code>catch</code> and manually
hand off the exception to the common handler.</p>
<hr>
<h1>Summary</h1>
<p>It is important to note that all exceptions are handled on the thread that they
occurred on. If you're in the same boat I was in, you're stuck with a
third-party crash handler component that had to be run on the UI thread.
Because of this, I marshal the calls to the UI thread with a call to
<code>Control.Invoke()</code>, as usual for cross-thread UI stuff.</p>
<p>The full source code for my example binaries can be <a href="http://jonathon.onthefive.com/public/WinFormExceptions/WinformsExceptionsTest.zip">downloaded here</a>.</p>goto: The Forbidden Fruit2013-02-25T00:49:00-05:002013-02-25T00:49:00-05:00Jonathon Reinharttag:jonathonreinhart.com,2013-02-25:/posts/blog/2013/02/25/goto-the-forbidden-fruit/<p>Nowdays, it's not hard to find tons of arguments against the use of <code>goto</code> in C
(and C-like languages). Post anything to <a href="http://stackoverflow.com/">StackOverflow</a>,
about/including <code>goto</code> and you're almost guaranteed to get flamed.</p>
<p><img alt="XKCD comic: goto" src="http://imgs.xkcd.com/comics/goto.png"></p>
<p>Just like many good and useful things in our lives (pocketknives, guns, kegs,
etc.) it only takes …</p><p>Nowdays, it's not hard to find tons of arguments against the use of <code>goto</code> in C
(and C-like languages). Post anything to <a href="http://stackoverflow.com/">StackOverflow</a>,
about/including <code>goto</code> and you're almost guaranteed to get flamed.</p>
<p><img alt="XKCD comic: goto" src="http://imgs.xkcd.com/comics/goto.png"></p>
<p>Just like many good and useful things in our lives (pocketknives, guns, kegs,
etc.) it only takes a few people to abuse something before everyone else
categorizes it as "bad". But the truth is, <code>goto</code> is a simple tool that, when
used correctly, can make a program much easier to write (and even understand!)</p>
<p>First, let's take a look at how <em>not</em> to use <code>goto</code> (this is just a little
example, nothing meaningful):</p>
<div class="highlight"><pre><span></span><span class="kt">int</span> <span class="nf">foo</span><span class="p">(</span><span class="kt">int</span> <span class="n">a</span><span class="p">)</span>
<span class="p">{</span>
<span class="kt">int</span> <span class="n">bar</span><span class="p">;</span>
<span class="k">while</span> <span class="p">(</span><span class="n">bar</span> <span class="o"><</span> <span class="n">spam</span><span class="p">())</span>
<span class="p">{</span>
<span class="nl">loop</span><span class="p">:</span>
<span class="n">bar</span> <span class="o">=</span> <span class="n">a</span> <span class="o">*</span> <span class="n">scale</span><span class="p">;</span>
<span class="k">if</span> <span class="p">(</span><span class="n">bar</span> <span class="o">></span> <span class="mi">100</span><span class="p">)</span> <span class="k">goto</span> <span class="n">toobig</span><span class="p">;</span>
<span class="n">bla</span><span class="p">(</span><span class="n">bar</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">return</span> <span class="n">bar</span><span class="p">;</span>
<span class="nl">toobig</span><span class="p">:</span>
<span class="k">if</span> <span class="p">(</span><span class="n">bar</span><span class="o">-</span><span class="n">tar</span> <span class="o">></span> <span class="mi">0</span><span class="p">)</span>
<span class="k">return</span> <span class="n">bar</span><span class="p">;</span>
<span class="n">bar</span> <span class="o">-=</span> <span class="mi">5</span><span class="p">;</span> <span class="k">goto</span> <span class="n">loop</span><span class="p">;</span>
<span class="k">return</span> <span class="n">bar</span> <span class="o">*</span> <span class="mi">2</span><span class="p">;</span>
<span class="p">}</span>
</pre></div>
<p>Wow, that was even hard to come up with, and cetrainly isn't the way to do
things. Jumping in and out of control structures is bound to confuse the next
guy, and possibly the compiler when it is trying to optimize. </p>
<p>But in the right places, goto can be extremely useful. Luckily, my opinion here
is not alone. In fact, the Linux Kernel (3.8) uses goto over 100,000 times!</p>
<div class="highlight"><pre><span></span>$ find linux-3.8 -iname <span class="s1">'*.c'</span> -exec grep <span class="s1">'goto'</span> <span class="o">{}</span> <span class="se">\;</span> <span class="p">|</span> wc -l
<span class="m">104299</span>
</pre></div>
<p>Here is a good example of this programming style in use, from the
<a href="http://lxr.linux.no/linux+v3.8/fs/ext4/extents.c#L411">ext4 driver</a>.</p>
<hr>
<p>First, let's look at some bad code. The author does two things that I really
dislike:</p>
<ol>
<li>
<p>They return all over the place. This is okay, unless (like in this example)
you have to deal with resource de-allocation. Here, this leads to a fragile
situation with lots of calls to <code>free()</code>.</p>
</li>
<li>
<p>They check first for success, which leads to ridiculous amounts of nesting.
And, the error-handling code is a long ways away from the code that detected
the error situation, leading to lots of scrolling up/down.</p>
</li>
</ol>
<div class="highlight"><pre><span></span><span class="kt">bool</span> <span class="nf">baz</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span>
<span class="p">{</span>
<span class="kt">bool</span> <span class="n">result</span> <span class="o">=</span> <span class="nb">false</span><span class="p">;</span>
<span class="kt">uint8_t</span> <span class="o">*</span><span class="n">buf1</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span>
<span class="kt">uint8_t</span> <span class="o">*</span><span class="n">buf2</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span>
<span class="kt">uint8_t</span> <span class="o">*</span><span class="n">buf3</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span>
<span class="c1">// Allocate buffers.</span>
<span class="n">buf1</span> <span class="o">=</span> <span class="n">malloc</span><span class="p">(</span><span class="n">BUF1_SIZE</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="n">buf1</span><span class="p">)</span> <span class="p">{</span>
<span class="n">buf2</span> <span class="o">=</span> <span class="n">malloc</span><span class="p">(</span><span class="n">BUF2_SIZE</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="n">buf2</span><span class="p">)</span> <span class="p">{</span>
<span class="n">buf3</span> <span class="o">=</span> <span class="n">malloc</span><span class="p">(</span><span class="n">BUF3_SIZE</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="n">buf3</span><span class="p">)</span> <span class="p">{</span>
<span class="n">result</span> <span class="o">=</span> <span class="n">use_buffers</span><span class="p">(</span><span class="n">buf1</span><span class="p">,</span> <span class="n">buf2</span><span class="p">,</span> <span class="n">buf3</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="n">result</span><span class="p">)</span>
<span class="n">printf</span><span class="p">(</span><span class="s">"Success!</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
<span class="k">else</span>
<span class="n">fprintf</span><span class="p">(</span><span class="n">stderr</span><span class="p">,</span> <span class="s">"Operation failed.</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
<span class="n">free</span><span class="p">(</span><span class="n">buf3</span><span class="p">);</span>
<span class="n">free</span><span class="p">(</span><span class="n">buf2</span><span class="p">);</span>
<span class="n">free</span><span class="p">(</span><span class="n">buf1</span><span class="p">);</span>
<span class="k">return</span> <span class="n">result</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">else</span> <span class="p">{</span>
<span class="n">fprintf</span><span class="p">(</span><span class="n">stderr</span><span class="p">,</span> <span class="s">"Error allocating %d bytes.</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">BUF3_SIZE</span><span class="p">);</span>
<span class="n">free</span><span class="p">(</span><span class="n">buf2</span><span class="p">);</span>
<span class="n">free</span><span class="p">(</span><span class="n">buf1</span><span class="p">);</span>
<span class="k">return</span> <span class="nb">false</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="k">else</span> <span class="p">{</span>
<span class="n">fprintf</span><span class="p">(</span><span class="n">stderr</span><span class="p">,</span> <span class="s">"Error allocating %d bytes.</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">BUF2_SIZE</span><span class="p">);</span>
<span class="n">free</span><span class="p">(</span><span class="n">buf1</span><span class="p">);</span>
<span class="k">return</span> <span class="nb">false</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="k">else</span> <span class="p">{</span>
<span class="n">fprintf</span><span class="p">(</span><span class="n">stderr</span><span class="p">,</span> <span class="s">"Error allocating %d bytes.</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">BUF1_SIZE</span><span class="p">);</span>
<span class="k">return</span> <span class="nb">false</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span>
</pre></div>
<hr>
<p>Using goto and a single exit point clean this mess up very nicely:</p>
<div class="highlight"><pre><span></span><span class="kt">bool</span> <span class="nf">baz</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span>
<span class="p">{</span>
<span class="kt">bool</span> <span class="n">result</span> <span class="o">=</span> <span class="nb">false</span><span class="p">;</span> <span class="c1">// Assume failure until proven successful</span>
<span class="kt">uint8_t</span> <span class="o">*</span><span class="n">buf1</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span>
<span class="kt">uint8_t</span> <span class="o">*</span><span class="n">buf2</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span>
<span class="kt">uint8_t</span> <span class="o">*</span><span class="n">buf3</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span>
<span class="c1">// Allocate buffers.</span>
<span class="n">buf1</span> <span class="o">=</span> <span class="n">malloc</span><span class="p">(</span><span class="n">BUF1_SIZE</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">buf1</span><span class="p">)</span> <span class="p">{</span>
<span class="n">fprintf</span><span class="p">(</span><span class="n">stderr</span><span class="p">,</span> <span class="s">"Error allocating %d bytes.</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">BUF1_SIZE</span><span class="p">);</span>
<span class="k">goto</span> <span class="n">exit</span><span class="p">;</span>
<span class="p">}</span>
<span class="n">buf2</span> <span class="o">=</span> <span class="n">malloc</span><span class="p">(</span><span class="n">BUF2_SIZE</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">buf2</span><span class="p">)</span> <span class="p">{</span>
<span class="n">fprintf</span><span class="p">(</span><span class="n">stderr</span><span class="p">,</span> <span class="s">"Error allocating %d bytes.</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">BUF2_SIZE</span><span class="p">);</span>
<span class="k">goto</span> <span class="n">exit</span><span class="p">;</span>
<span class="p">}</span>
<span class="n">buf3</span> <span class="o">=</span> <span class="n">malloc</span><span class="p">(</span><span class="n">BUF3_SIZE</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">buf3</span><span class="p">)</span> <span class="p">{</span>
<span class="n">fprintf</span><span class="p">(</span><span class="n">stderr</span><span class="p">,</span> <span class="s">"Error allocating %d bytes.</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">BUF3_SIZE</span><span class="p">);</span>
<span class="k">goto</span> <span class="n">exit</span><span class="p">;</span>
<span class="p">}</span>
<span class="c1">// Do something useful</span>
<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">use_buffers</span><span class="p">(</span><span class="n">buf1</span><span class="p">,</span> <span class="n">buf2</span><span class="p">,</span> <span class="n">buf3</span><span class="p">))</span> <span class="p">{</span>
<span class="n">fprintf</span><span class="p">(</span><span class="n">stderr</span><span class="p">,</span> <span class="s">"Operation failed.</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
<span class="k">goto</span> <span class="n">exit</span><span class="p">;</span>
<span class="p">}</span>
<span class="n">result</span> <span class="o">=</span> <span class="nb">true</span><span class="p">;</span>
<span class="n">printf</span><span class="p">(</span><span class="s">"Success!</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
<span class="nl">exit</span><span class="p">:</span>
<span class="k">if</span> <span class="p">(</span><span class="n">buf1</span><span class="p">)</span> <span class="n">free</span><span class="p">(</span><span class="n">buf1</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="n">buf2</span><span class="p">)</span> <span class="n">free</span><span class="p">(</span><span class="n">buf2</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="n">buf3</span><span class="p">)</span> <span class="n">free</span><span class="p">(</span><span class="n">buf3</span><span class="p">);</span>
<span class="k">return</span> <span class="n">result</span><span class="p">;</span>
<span class="p">}</span>
</pre></div>
<p>This allows for a very straight-forward approach to handling resource
allocation/freeing and a clean exit path. It's much easier to maintain as well
(imagine having to remove <code>buf2</code> in the first example!)</p>
<hr>
<p>An alternative to goto I often see is the dummy <code>do</code>-<code>while</code> loop: </p>
<div class="highlight"><pre><span></span><span class="kt">bool</span> <span class="nf">baz</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span>
<span class="p">{</span>
<span class="kt">bool</span> <span class="n">result</span> <span class="o">=</span> <span class="nb">false</span><span class="p">;</span>
<span class="kt">uint8_t</span> <span class="o">*</span><span class="n">buf1</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span>
<span class="kt">uint8_t</span> <span class="o">*</span><span class="n">buf2</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span>
<span class="kt">uint8_t</span> <span class="o">*</span><span class="n">buf3</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span>
<span class="k">do</span> <span class="p">{</span>
<span class="c1">// Allocate buffers.</span>
<span class="n">buf1</span> <span class="o">=</span> <span class="n">malloc</span><span class="p">(</span><span class="n">BUF1_SIZE</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">buf1</span><span class="p">)</span> <span class="p">{</span>
<span class="n">fprintf</span><span class="p">(</span><span class="n">stderr</span><span class="p">,</span> <span class="s">"Error allocating %d bytes.</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">BUF1_SIZE</span><span class="p">);</span>
<span class="k">break</span><span class="p">;</span>
<span class="p">}</span>
<span class="n">buf2</span> <span class="o">=</span> <span class="n">malloc</span><span class="p">(</span><span class="n">BUF2_SIZE</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">buf2</span><span class="p">)</span> <span class="p">{</span>
<span class="n">fprintf</span><span class="p">(</span><span class="n">stderr</span><span class="p">,</span> <span class="s">"Error allocating %d bytes.</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">BUF2_SIZE</span><span class="p">);</span>
<span class="k">break</span><span class="p">;</span>
<span class="p">}</span>
<span class="n">buf3</span> <span class="o">=</span> <span class="n">malloc</span><span class="p">(</span><span class="n">BUF3_SIZE</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">buf3</span><span class="p">)</span> <span class="p">{</span>
<span class="n">fprintf</span><span class="p">(</span><span class="n">stderr</span><span class="p">,</span> <span class="s">"Error allocating %d bytes.</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">BUF3_SIZE</span><span class="p">);</span>
<span class="k">break</span><span class="p">;</span>
<span class="p">}</span>
<span class="c1">// Do something useful</span>
<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">use_buffers</span><span class="p">(</span><span class="n">buf1</span><span class="p">,</span> <span class="n">buf2</span><span class="p">,</span> <span class="n">buf3</span><span class="p">))</span> <span class="p">{</span>
<span class="n">fprintf</span><span class="p">(</span><span class="n">stderr</span><span class="p">,</span> <span class="s">"Operation failed.</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
<span class="k">break</span><span class="p">;</span>
<span class="p">}</span>
<span class="n">result</span> <span class="o">=</span> <span class="nb">true</span><span class="p">;</span>
<span class="n">printf</span><span class="p">(</span><span class="s">"Success!</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
<span class="p">}</span> <span class="k">while</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="n">buf1</span><span class="p">)</span> <span class="n">free</span><span class="p">(</span><span class="n">buf1</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="n">buf2</span><span class="p">)</span> <span class="n">free</span><span class="p">(</span><span class="n">buf2</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="n">buf3</span><span class="p">)</span> <span class="n">free</span><span class="p">(</span><span class="n">buf3</span><span class="p">);</span>
<span class="k">return</span> <span class="n">result</span><span class="p">;</span>
<span class="p">}</span>
</pre></div>
<p>This isn't terrible, but what about when you want to use an actual loop inside
that dummy do-while, and break out of it? PHP includes a <strike>nice</strike>
disgusting feature to <a href="http://php.net/manual/en/control-structures.break.php">break out of multiple levels</a>. In other
languages you're screwed, unless you follow the loop with some additional code
to check for completion of the loop:</p>
<div class="highlight"><pre><span></span><span class="kt">bool</span> <span class="nf">baz</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span>
<span class="p">{</span>
<span class="kt">bool</span> <span class="n">result</span> <span class="o">=</span> <span class="nb">false</span><span class="p">;</span>
<span class="kt">uint8_t</span> <span class="o">*</span><span class="n">buf1</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span>
<span class="kt">uint8_t</span> <span class="o">*</span><span class="n">buf2</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span>
<span class="kt">int</span> <span class="n">i</span><span class="p">;</span>
<span class="k">do</span> <span class="p">{</span>
<span class="c1">// Allocate buffers.</span>
<span class="n">buf1</span> <span class="o">=</span> <span class="n">malloc</span><span class="p">(</span><span class="n">BUF1_SIZE</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">buf1</span><span class="p">)</span> <span class="p">{</span>
<span class="n">fprintf</span><span class="p">(</span><span class="n">stderr</span><span class="p">,</span> <span class="s">"Error allocating %d bytes.</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">BUF1_SIZE</span><span class="p">);</span>
<span class="k">break</span><span class="p">;</span>
<span class="p">}</span>
<span class="n">buf2</span> <span class="o">=</span> <span class="n">malloc</span><span class="p">(</span><span class="n">BUF2_SIZE</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">buf2</span><span class="p">)</span> <span class="p">{</span>
<span class="n">fprintf</span><span class="p">(</span><span class="n">stderr</span><span class="p">,</span> <span class="s">"Error allocating %d bytes.</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">BUF2_SIZE</span><span class="p">);</span>
<span class="k">break</span><span class="p">;</span>
<span class="p">}</span>
<span class="c1">// Do something in a loop</span>
<span class="k">for</span> <span class="p">(</span><span class="n">i</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span> <span class="n">i</span><span class="o"><</span><span class="n">CONSTANT</span><span class="p">;</span> <span class="o">++</span><span class="n">i</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">use_buffers</span><span class="p">(</span><span class="n">buf1</span><span class="p">,</span> <span class="n">buf2</span><span class="p">))</span> <span class="p">{</span>
<span class="n">fprintf</span><span class="p">(</span><span class="n">stderr</span><span class="p">,</span> <span class="s">"Operation #%d failed.</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">i</span><span class="p">);</span>
<span class="k">break</span><span class="p">;</span> <span class="c1">// Can't get out of the do-while from here!</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="c1">// Have to add this ridiculous check, because we could have exited</span>
<span class="c1">// the loop early...</span>
<span class="k">if</span> <span class="p">(</span><span class="n">i</span><span class="o">==</span><span class="n">CONSTANT</span><span class="p">)</span> <span class="p">{</span>
<span class="n">result</span> <span class="o">=</span> <span class="nb">true</span><span class="p">;</span>
<span class="n">printf</span><span class="p">(</span><span class="s">"Success!</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span> <span class="k">while</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="n">buf1</span><span class="p">)</span> <span class="n">free</span><span class="p">(</span><span class="n">buf1</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="n">buf2</span><span class="p">)</span> <span class="n">free</span><span class="p">(</span><span class="n">buf2</span><span class="p">);</span>
<span class="k">return</span> <span class="n">result</span><span class="p">;</span>
<span class="p">}</span>
</pre></div>
<p>In this case, a goto exit; would have worked just fine. </p>Deftones - You've Seen the Butcher - Timing2013-02-24T11:24:00-05:002013-02-24T11:24:00-05:00Jonathon Reinharttag:jonathonreinhart.com,2013-02-24:/posts/blog/2013/02/24/deftones-youve-seen-the-butcher-timing/<p>Maybe the name of this blog should include something about ADD or OCD. Either
way, enough time was spent perfecting this, I figure I might as well share it
with the <a href="http://xkcd.com/181/">Interwebs</a>.</p>
<p>I'm a big fan of <a href="http://www.deftones.com/">Deftones</a> and their 2010 album <a href="http://en.wikipedia.org/wiki/Diamond_Eyes">Diamond Eyes</a>
was unsurprisingly awesome. <a href="http://www.youtube.com/watch?v=woAcXSMyCEw"><em>You've Seen the …</em></a></p><p>Maybe the name of this blog should include something about ADD or OCD. Either
way, enough time was spent perfecting this, I figure I might as well share it
with the <a href="http://xkcd.com/181/">Interwebs</a>.</p>
<p>I'm a big fan of <a href="http://www.deftones.com/">Deftones</a> and their 2010 album <a href="http://en.wikipedia.org/wiki/Diamond_Eyes">Diamond Eyes</a>
was unsurprisingly awesome. <a href="http://www.youtube.com/watch?v=woAcXSMyCEw"><em>You've Seen the Butcher</em></a> is an awesome
track. The timing is subtly complicated, so I decided to chart it out. Hope
this helps someone.</p>
<p>All time signatures are <code>x/4</code>, and the number of beats in each measure are
shown. For many parts of the song, the final measure's number of beats is the
same as the part that follows. These are noted.</p>
<h3>Intro</h3>
<ul>
<li>Lead-in: 1</li>
<li>Guitar-only: alt. 3 and 4<ul>
<li>last measure: 5</li>
</ul>
</li>
<li>Heavy riff (no vox): alt. 3 and 5<ul>
<li>last measure: 4</li>
</ul>
</li>
</ul>
<h3>Verse 1</h3>
<ul>
<li>Verse: alt. 3 and 4<ul>
<li>last measure: 5</li>
</ul>
</li>
<li>Pre-Chorus: alt. 3 and 5</li>
<li>Chorus: 4<ul>
<li>last measure: 3</li>
</ul>
</li>
</ul>
<h3>Verse 2</h3>
<ul>
<li>Verse: alt. 3 and 4<ul>
<li>last measure: 5</li>
</ul>
</li>
<li>Pre-Chorus: alt. 3 and 5</li>
<li>Chorus: 4</li>
</ul>
<h3>Bridge</h3>
<p><em>Note the two 6/4 measures</em></p>
<ul>
<li>Heavy riff (no vox): 3 5 3 6 3 5 3 5</li>
<li>Pre-Chorus: 3 5 3 6 3 5 3 5</li>
</ul>
<h3>Outro</h3>
<ul>
<li>Chorus 4<ul>
<li>last measure: 5</li>
</ul>
</li>
<li>Ending 3 (free-time)</li>
</ul>Named Pipes between C# and Python2012-12-13T11:56:00-05:002012-12-13T11:56:00-05:00Jonathon Reinharttag:jonathonreinhart.com,2012-12-13:/posts/blog/2012/12/13/named-pipes-between-c-and-python/<p>There's a lot of over-complicated information on the internet for communicating
between a C# process and a Python process using named pipes on Windows. I'll
start with the code:</p>
<script src="https://gist.github.com/JonathonReinhart/bbfa618f9ad19e2ca48d5fd10914b069.js"></script>
<p>In this example, I implement a very simple protocol, where every "message" is a
4-byte integer (<code>UInt32</code> in C#, <code>I</code> (un …</p><p>There's a lot of over-complicated information on the internet for communicating
between a C# process and a Python process using named pipes on Windows. I'll
start with the code:</p>
<script src="https://gist.github.com/JonathonReinhart/bbfa618f9ad19e2ca48d5fd10914b069.js"></script>
<p>In this example, I implement a very simple protocol, where every "message" is a
4-byte integer (<code>UInt32</code> in C#, <code>I</code> (un)pack format in Python), which indicates
the length of the string that follows. The string is ASCII. Important things to
note here: </p>
<ul>
<li>Python<ul>
<li>The third parameter to <code>open()</code> means "unbuffered". Otherwise, it will
default to line-buffered, which means it will wait for a newline
character before actually sending it through the pipe.</li>
<li>I'm not sure why, but omitting the <code>seek(0)</code> will cause an IOError #0. I
was clued to this by a StackOverflow question.</li>
</ul>
</li>
</ul>
<h3>References</h3>
<ul>
<li>.NET <a href="http://msdn.microsoft.com/en-us/library/bb347348.aspx"><code>NamedPipeServerStream</code></a> class on MSDN</li>
<li>Python <a href="http://docs.python.org/2/library/functions.html#open"><code>open()</code></a> method on Python.org</li>
</ul>Rename SVN Repository2012-11-14T22:39:00-05:002012-11-14T22:39:00-05:00Jonathon Reinharttag:jonathonreinhart.com,2012-11-14:/posts/blog/2012/11/14/rename-svn-repository/<p>It happens sometimes: You'd like to rename your SVN repository. Well simply
renaming the directory on the server won't do the trick.</p>
<p>Thanks to <a href="http://mdinescu.com/software-development/2-how-to-rename-a-svn-repository">Miky Dinescu's post</a>,
we find that the best way to do this is use <code>svnadmin dump</code> and <code>svnadmin load</code>
to export, and import the old repository …</p><p>It happens sometimes: You'd like to rename your SVN repository. Well simply
renaming the directory on the server won't do the trick.</p>
<p>Thanks to <a href="http://mdinescu.com/software-development/2-how-to-rename-a-svn-repository">Miky Dinescu's post</a>,
we find that the best way to do this is use <code>svnadmin dump</code> and <code>svnadmin load</code>
to export, and import the old repository into a new one, without losing
anything.</p>
<p>I wrapped this process up in a nice, foolproof script. Hopefully it makes your life easier.</p>
<script src="https://gist.github.com/JonathonReinhart/84398cf8532ae3902f83119922ed4e69.js"></script>Cyanogenmod 9 Nightly!2012-06-09T12:31:00-04:002012-06-09T12:31:00-04:00Jonathon Reinharttag:jonathonreinhart.com,2012-06-09:/posts/blog/2012/06/09/cyanogenmod-9-nightly/<p>I am happy to say that I am running <a href="http://www.cyanogenmod.com/">Cyanogenmod</a> 9
(<a href="http://get.cm/?device=toro">nightly</a>, dated 20120608) on my Galaxy Nexus!</p>
<p><img alt="CM9 Screenshot" src="//jonathonreinhart.com/posts/blog/2012/06/09/cyanogenmod-9-nightly/cm9.png"></p>
<p>I am very happy with it, and have noticed no problems, which is pretty
impressive because this is a nightly build, not even a Beta / RC. The CM9 team
has done a …</p><p>I am happy to say that I am running <a href="http://www.cyanogenmod.com/">Cyanogenmod</a> 9
(<a href="http://get.cm/?device=toro">nightly</a>, dated 20120608) on my Galaxy Nexus!</p>
<p><img alt="CM9 Screenshot" src="//jonathonreinhart.com/posts/blog/2012/06/09/cyanogenmod-9-nightly/cm9.png"></p>
<p>I am very happy with it, and have noticed no problems, which is pretty
impressive because this is a nightly build, not even a Beta / RC. The CM9 team
has done a fantastic job with this version, and stuck very close to the
original ICS look and feel. </p>
<p>Things I am happy about:</p>
<ul>
<li>
<p>The settings menu. The stock build just seems so crippled to me now, after
seeing the CM9 settings. It is too expansive to screenshot, but still quite
organized. You can tweak everything from display gamma settings, to the lock
screen, to individual volumes, to kernel performance, to (my favorite!) the
notification LED. Coming from the Incredible, which just had the orange and
green notification LED, having an RGB LED that I can play with is great. I have
a green blink for texts, slow red for Gmail, and fast light blue for missed
calls.</p>
</li>
<li>
<p>The notification drawer. (I couldn't get a screenshot, because the drawer
retracts before it is taken.) I really missed these widgets, and now have
quick access buttons to toggle Wi-Fi, LTE (So happy about this one!), GPS,
Silent/Vibrate/Loud, and Auto-Rotate. There are other buttons you can add, but
these are the ones I wanted. Also, I tweaked the battery icon.</p>
</li>
<li>
<p>Customizable navigation buttons. I re-ordered the buttons at the bottom (to
more closely match my Incredible, actually) and added the search button,
which behaves the same way.</p>
</li>
<li>
<p>All of the familar 'root stuff' built right in. Superuser (of course), Wi-fi
tethering, screenshot, etc.</p>
</li>
</ul>
<p>Over I am quite pleased, and will probably keep using this on a day-to-day
basis. This is the way Android was meant to be. Can't wait for an RC!</p>
<p>Additional note: Of course, this comes without the Google Apps, so you'll want
to download that zip from <a href="http://goo.im/gapps">goo.im/gapps</a>.</p>Android 4.0.4 OTA update2012-06-04T12:12:00-04:002012-06-04T12:12:00-04:00Jonathon Reinharttag:jonathonreinhart.com,2012-06-04:/posts/blog/2012/06/04/android-404-ota-update/<p>A couple days ago, I started getting notifications that a system update was
ready for install. This was the
<a href="http://www.anandtech.com/show/5882/galaxy-nexus-cdmalte-404-imm76k-update-rolling-out">IMM76K (Android 4.0.4)</a>
OTA update that people had been impatiently waiting on for a while. After
making a nandroid backup (via CWM), I decided to give it a try …</p><p>A couple days ago, I started getting notifications that a system update was
ready for install. This was the
<a href="http://www.anandtech.com/show/5882/galaxy-nexus-cdmalte-404-imm76k-update-rolling-out">IMM76K (Android 4.0.4)</a>
OTA update that people had been impatiently waiting on for a while. After
making a nandroid backup (via CWM), I decided to give it a try.</p>
<p>The system rebooted, and went to the screen with the android's belly open and
the blue spinny thing. Then he was on his back, with the dreaded red triangle.
I wasn't surprised that the OTA update wasn't going to work with my modified
phone.</p>
<p>This excellent post on xda-developers gave links to the official
<a href="http://forum.xda-developers.com/showpost.php?p=20843237">OTA updates</a>
for the different versions of the G-Nex. So I downloaded the
<a href="http://android.clients.google.com/packages/ota/verizon_prime/12f767e7a5d0.signed-mysid-IMM76K-from-ICL53F.12f767e7.zip"><code>mysid IMM76K from ICL53F update.zip</code></a>,
and <code>adb push</code>d it to <code>/sdcard</code>. Rebooting into CWM recovery, I tried to
install the update, but it failed with:</p>
<div class="highlight"><pre><span></span>assert failed: apply_patch_check("/system/app/VZWBackupAssistant.apk".....
</pre></div>
<p>I knew why it was failing. I had removed some of the VZW garbage apps that cam
pre-installed. Luckily, I didn't actually delete them, I had just renamed them
to <code>.apk.REMOVED</code>. After putting them back1 the update installed successfully.</p>
<p><strong>Another thing to note</strong> - I didn't realize it, but the xda post pointed out this
important detail: Verizon OTA updates include a script that runs every boot,
whose purpose is to restore the recovery image if it is not the expected stock
image. The script is at <code>/system/etc/install-recovery.sh</code> and the recovery image
(for flashing) is <code>/system/recovery-from-boot.p</code>. Thus, if you don't wan't to
lose CWM (or other custom recovery), you need to rename these files.</p>
<h3>Notes:</h3>
<p>I didn't realize it, but ADB is supported in CWM. When I looked in device
manager while my phone was connected and in CWM, I saw one device just named
"Full". I manually specified the same Samsung drivers (already installed) from
before, and bingo, my phone showed up in <code>adb devices</code>.</p>Galaxy Nexus (CDMA)2012-05-12T03:12:00-04:002012-05-12T03:12:00-04:00Jonathon Reinharttag:jonathonreinhart.com,2012-05-12:/posts/blog/2012/05/12/galaxy-nexus-cdma/<p>Well after several months of putting up with my rebooting (sometimes looping)
when I used any substantial amount of 3G data, I decided to upgrade. I was
looking at the HTC Rezound and the Samsung Galaxy Nexus, and found this really
good comparison <a href="http://www.phonearena.com/reviews/Verizon-Galaxy-Nexus-vs-HTC-Rezound_id2938/">article on phoneArena</a>. Ultimately, after
many recommendations …</p><p>Well after several months of putting up with my rebooting (sometimes looping)
when I used any substantial amount of 3G data, I decided to upgrade. I was
looking at the HTC Rezound and the Samsung Galaxy Nexus, and found this really
good comparison <a href="http://www.phonearena.com/reviews/Verizon-Galaxy-Nexus-vs-HTC-Rezound_id2938/">article on phoneArena</a>. Ultimately, after
many recommendations by friends, I went with the Nexus.</p>
<p>It arrived, running Android 4.0.2. This time, I lasted about 2 days before
rooting it. Everybody has their own half-assed write ups of this, but I wanted
to mainly include my sources for some of these files:</p>
<ul>
<li>ADB / Fastboot Drivers - Samsung <a href="http://www.samsung.com/us/support/owners/product/SCH-I515MSAVZW">SCH-I515 download page</a></li>
<li>ClockworkMod Recovery<ul>
<li><a href="http://www.clockworkmod.com/rommanager">ClockworkMod ROM Manager page</a></li>
<li><a href="http://download.clockworkmod.com/recoveries/recovery-clockwork-touch-5.8.0.2-toro.img"><code>recovery-clockwork-touch-5.8.0.2-toro.img</code></a></li>
</ul>
</li>
<li>Superuser - <a href="http://download.clockworkmod.com/test/su.zip">From clockwork site</a></li>
</ul>
<h2>ADB / Fastboot Drivers</h2>
<p>I downloaded the USB drivers directly from Samsung's site on their <a href="http://www.samsung.com/us/support/owners/product/SCH-I515MSAVZW">SCH-I515
download page</a>. It's a 23MB download which is a bit ridiculous, but I
wan unable to isolate exactly which driver was required from the compressed
exe.</p>
<p>After installing them, I was able to plug in my phone, turn on USB debugging,
execute <code>adb devices</code> and see my device. Next, I rebooted into fastboot mode
(hold all three buttons to turn it on). At this point, the device showed up as
"Android 1.0". However, I was able to fix that by:</p>
<p><img alt="Driver update 1" src="//jonathonreinhart.com/posts/blog/2012/05/12/galaxy-nexus-cdma/20120512/driver-update1.png"><br>
<img alt="Driver update 2" src="//jonathonreinhart.com/posts/blog/2012/05/12/galaxy-nexus-cdma/20120512/driver-update2.png"><br>
<img alt="Driver update 3" src="//jonathonreinhart.com/posts/blog/2012/05/12/galaxy-nexus-cdma/20120512/driver-update3.png"> </p>
<p>Then, there should be just one "SAMSUNG Android ADB Interface" listed.</p>
<p>After correcting the driver issue, I was able to execute <code>fastboot devices</code> and
see my device. </p>
<h2>Unlock Bootloader</h2>
<p>The next step is <code>fastboot oem unlock</code>!
<img alt="Unlock bootloader 1" src="//jonathonreinhart.com/posts/blog/2012/05/12/galaxy-nexus-cdma/20120512/unlock-bootloader1.jpg"> </p>
<p>After unlocking, I rebooted, and the Google screen now has an unlocked icon!
<img alt="Unlock bootloader 2" src="//jonathonreinhart.com/posts/blog/2012/05/12/galaxy-nexus-cdma/20120512/unlock-bootloader2.jpg"> </p>
<h2>ClockworkMod Recovery</h2>
<p>After making sure the phone booted OK, I flashed the latest (touch) version of
CWM from the <a href="http://www.clockworkmod.com/rommanager">ClockworkMod ROM Manager page</a>. At this time, that
version was <a href="http://download.clockworkmod.com/recoveries/recovery-clockwork-touch-5.8.0.2-toro.img"><code>recovery-clockwork-touch-5.8.0.2-toro.img</code></a>.
Simply download and run <code>fastboot flash recovery recovery-clockwork-touch-5.8.0.2-toro.img</code>.</p>
<h2>Root</h2>
<p>Next, I rebooted, and went through the initial setup. Now it's time to
actually get root! The page that I had been following included some version of
SuperSU. I didn't really want to just use what they gave me, and went on the
hunt for the latest su.</p>
<p>Note for root newbies: "Root" essentially means having access to the <a href="http://dictionary.die.net/su"><code>su</code></a>
("superuser") binary, which allows a process to run as the root user. On
android, "root" is two components: The <code>su</code> binary (linux executable), and
<code>Superuser.apk</code>, which is the accompanying Android app, which manages requests
for root, logs, etc.</p>
<p>It appears that <a href="http://androidsu.com/superuser/">androidsu.com</a> is the true "home" of superuser for
Android. So I downloaded the latest, <code>Superuser-3.0.7-efghi-signed.zip</code>, and used
<code>adb push Superuser-3.0.7-efghi-signed.zip /sdcard/</code> to push it to my phone.</p>
<p>Then I rebooted into recovery again (<code>adb reboot recovery</code>), and tried to
install it, with the <strong>Install zip from sdcard</strong> option. However, I got the
following error:</p>
<div class="highlight"><pre><span></span><span class="n">E</span><span class="o">:</span><span class="n">Error</span> <span class="k">in</span> <span class="sr">/sdcard/</span><span class="n">Superuser</span><span class="o">-</span><span class="mf">3.0</span><span class="o">.</span><span class="mi">7</span><span class="o">-</span><span class="n">efghi</span><span class="o">-</span><span class="n">signed</span><span class="o">.</span><span class="na">zip</span> <span class="o">(</span><span class="n">Status</span> <span class="mi">0</span><span class="o">)</span>
</pre></div>
<p>Doing a little research, I found the following posts:</p>
<ul>
<li>http://androidsu.com/superuser/#comment-6120</li>
<li>http://www.theandroidsoul.com/root-ice-cream-sandwich-on-att-galaxy-s2-skyrocket/#comment-478881789</li>
</ul>
<p>I tried everything, but could not get it to install. Instead, I found myself on
download.clockworkmod.com. In <a href="http://download.clockworkmod.com/su/"><code>/su/</code></a>,
I found seven different <code>-test</code> versions, and in <code>/test/</code> there is one
<code>su.zip</code>. (I can't for the life of me find the site that linked to that one.)
It turns out that that is the one that worked for me. I don't quite understand,
but whatever, it successfully installed via CWM. After rebooting, Superuser
was installed, and showed the correct version of the binary (and updated it
too!).</p>
<h2>What's Next</h2>
<p>Next, I'm probably going to upgrade to the stock Android 4.0.4 ROM, as it
supposedly makes some <a href="http://www.xda-developers.com/android/galaxy-nexus-gets-ics-4-0-4-update/">big improvements</a>.
That page links to <a href="http://forum.xda-developers.com/showthread.php?t=1481044">this thread</a>.
Also in my sights for a new ROM are this <a href="http://forum.xda-developers.com/showthread.php?t=1631796">IMM76K 4.0.4</a>
mod, and of course <a href="http://forum.xda-developers.com/showthread.php?t=1514333">CyanogenMod 9</a>,
which is currently available only in nightlies.</p>
<h2>Other Resources</h2>
<ul>
<li>http://galaxynexusroot.com/galaxy-nexus-root/how-to-root-galaxy-nexus-universal-guidegsmverizonsprintwindowslinuxmac/</li>
</ul>Never knew Downloader.Agent2.BBLD was so simple2012-04-29T13:57:00-04:002012-04-29T13:57:00-04:00Jonathon Reinharttag:jonathonreinhart.com,2012-04-29:/posts/blog/2012/04/29/never-knew-downloaderagent2bbld-was-so-simple/<p>I had just started writing a new C++ console app (under Visual Studio 2010
10.0.40219.1 SP1Rel) to test something out, and had just this:</p>
<div class="highlight"><pre><span></span><span class="cp">#include</span> <span class="cpf"><stdio.h></span><span class="cp"></span>
<span class="cp">#include</span> <span class="cpf"><Windows.h></span><span class="cp"></span>
<span class="kt">int</span> <span class="nf">main</span><span class="p">(</span><span class="kt">int</span> <span class="n">argc</span><span class="p">,</span> <span class="kt">char</span><span class="o">**</span> <span class="n">argv</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</pre></div>
<p>I unintentionally clicked Start Debugging, and much to my …</p><p>I had just started writing a new C++ console app (under Visual Studio 2010
10.0.40219.1 SP1Rel) to test something out, and had just this:</p>
<div class="highlight"><pre><span></span><span class="cp">#include</span> <span class="cpf"><stdio.h></span><span class="cp"></span>
<span class="cp">#include</span> <span class="cpf"><Windows.h></span><span class="cp"></span>
<span class="kt">int</span> <span class="nf">main</span><span class="p">(</span><span class="kt">int</span> <span class="n">argc</span><span class="p">,</span> <span class="kt">char</span><span class="o">**</span> <span class="n">argv</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</pre></div>
<p>I unintentionally clicked Start Debugging, and much to my surprise, the build
had failed:</p>
<p><img alt="Build errors" src="//jonathonreinhart.com/posts/blog/2012/04/29/never-knew-downloaderagent2bbld-was-so-simple/20120429/build-errors.png">
<img alt="Link error" src="//jonathonreinhart.com/posts/blog/2012/04/29/never-knew-downloaderagent2bbld-was-so-simple/20120429/link-error.png"></p>
<p><em>Really?</em> How did I screw up something so simple? Several seconds later AVG
popped up this "Resident Shield Alert":</p>
<p><img alt="AVG Resident Shield Alert" src="//jonathonreinhart.com/posts/blog/2012/04/29/never-knew-downloaderagent2bbld-was-so-simple/20120429/avg-threat.png"></p>
<p>Are you kidding me? So I added a <code>printf</code>...</p>
<div class="highlight"><pre><span></span><span class="kt">int</span> <span class="nf">main</span><span class="p">(</span><span class="kt">int</span> <span class="n">argc</span><span class="p">,</span> <span class="kt">char</span><span class="o">**</span> <span class="n">argv</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">printf</span><span class="p">(</span><span class="s">"WTF is going on</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
<span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</pre></div>
<p>Again, threat detected! This time, <code>Downloader.Agent2.BAZE</code>. I disabled AVG,
built it again (successfully!) and threw the EXE into IDA, worried that I had
some impressive virus injecting a trojan into EXEs I build. Nothing out of the
ordinary found, just the typical complicated CRT startup code, and my simple
<code>main()</code>.</p>
<p>I uploaded it to <a href="https://www.virustotal.com/file/ec48b28216e65ba2a4d7d35872810d346e0135c759fa7cb29c7f9a128f802393/analysis/1335719858/">VirusTotal</a> to see if this was just AVG being
retarded or what. It had a detection ratio of 8 / 42. Check out that link to
see each AV and what they detected it as. <em>It is important to note that AVG
picked up the file before it had even finished building (hence the link error)
with Resident Shield, but also the finished EXE with a manual scan.</em></p>
<p>"This is absurd!" I'm thinking. One more try....</p>
<div class="highlight"><pre><span></span><span class="kt">int</span> <span class="nf">main</span><span class="p">(</span><span class="kt">int</span> <span class="n">argc</span><span class="p">,</span> <span class="kt">char</span><span class="o">**</span> <span class="n">argv</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">printf</span><span class="p">(</span><span class="s">"WTF is going on</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
<span class="n">getchar</span><span class="p">();</span>
<span class="n">printf</span><span class="p">(</span><span class="s">"This is ridiculous</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
<span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</pre></div>
<p>Finally, this one built okay and AVG let it alone. Curious, I uploaded this
one to <a href="https://www.virustotal.com/file/3358f50d7378862e2c717c1a1e31f6a051b76b06470272619af333c49442f676/analysis/1335721772/">VirusTotal</a> too. It was picked up by only 1 / 42 AVs: <strong>McAfee-GW-Edition</strong>
identified it as <code>Heuristic.BehavesLike.Win32.Suspicious.H</code>.</p>
<p>Sounds more like <code>Heuristic.WeHaveNoIdea.FlagEverything.H</code></p>SSDs and Windows 'Users' Directory2011-10-27T22:58:00-04:002011-10-27T22:58:00-04:00Jonathon Reinharttag:jonathonreinhart.com,2011-10-27:/posts/blog/2011/10/27/ssds-and-windows-users-directory/<p>After getting my new SSD installed, I really wanted to get everything setup so
that my data was safe on the 1 TB RAID 1 array. This meant somehow moving the
Users directory from <code>C:\</code> (the SSD) to <code>D:\</code> (the RAID). </p>
<p>The two main approaches are:</p>
<ol>
<li>
<p>Use an <code>unattend.xml …</code></p></li></ol><p>After getting my new SSD installed, I really wanted to get everything setup so
that my data was safe on the 1 TB RAID 1 array. This meant somehow moving the
Users directory from <code>C:\</code> (the SSD) to <code>D:\</code> (the RAID). </p>
<p>The two main approaches are:</p>
<ol>
<li>
<p>Use an <code>unattend.xml</code> file during Windows installation to specify the Users
directory.</p>
</li>
<li>
<p>Move the Users directory after installation, and create a <a href="http://en.wikipedia.org/wiki/NTFS_junction_point">junction point</a>
at the original location to point to the newly located directory. Here, the
junction essentially acts as a symbolic link (although symlinks are a different
thing in NTFS.)</p>
</li>
</ol>
<p>After reading a ton of forum and blog posts, I decided to follow Marilyn O's
advice on <a href="http://answers.microsoft.com/en-us/windows/forum/windows_7-security/move-user-folders-off-system-drive-want-all/c8d2aaad-0672-4361-9853-b3f863416483">this question</a> and decided to go with #2, because it is a
single point of change, and should be easily reversible.</p>
<p>Here's how I got it working. <code>C:</code> is my SSD where Windows is installed, and
<code>D:</code> is the RAID array to which I'm moving my <code>Users</code> directory. Your
drives/paths may be different. </p>
<ol>
<li>
<p>Install windows as usual. Go ahead and get the OS in a working state.</p>
</li>
<li>
<p>Boot to a command line from the install media. Follow <a href="http://forum.bkis.com/showthread.php?361-OG12-Guide-for-using-Windows-7-s-Startup-Repair-tool">these directions</a>,
but on the <strong>System Recovery Options</strong> dialog, click the last one, <strong>Command Prompt</strong>.</p>
</li>
<li>
<p>Use <a href="http://technet.microsoft.com/en-us/library/cc733145(WS.10).aspx">robocopy</a> to make an exact copy of <code>Users</code> to the new location:<br>
<strong><code>robocopy /mir /xj C:\Users D:\Users</code></strong><br>
Note that <code>/mir</code> makes an exact mirror, and <code>/xj</code> ignores junction points.
Make sure to include these options!</p>
</li>
<li>
<p>Verify that all the data has been successfully copied. Then, remove the original <code>Users</code> directory:<br>
<strong><code>rmdir /s /q C:\Users</code></strong><br>
You really have to do this. See comment at the end for why.</p>
</li>
<li>
<p>There is a junction named <code>Documents and Settings</code> (remember him from XP?)
that currently points to <code>C:\Users</code> for compatibility purposes. We need to
first remove him:<br>
<strong><code>rd "Documents and Settings"</code></strong></p>
</li>
<li>
<p>Now, make the new junctions pointing to the new <code>Users</code> folder on <code>D:</code> using <code>mklink</code>:<br>
<strong><code>mklink /j C:\Users D:\Users</code></strong><br>
<strong><code>mklink /j "C:\Documents and Settings" D:\Users</code></strong><br>
(Yes, Linux users, those arguments are in the opposite order.)</p>
</li>
<li>
<p>Reboot and log in to Windows. If you look in <code>C:</code> in Windows Explorer, you
should see that the <code>Users</code> icon now has a shortcut overlay, indicating that
it is a junction point:</p>
</li>
</ol>
<p><img alt="Users shortcut overlay" src="//jonathonreinhart.com/posts/blog/2011/10/27/ssds-and-windows-users-directory/users-shortcut-overlay.png"></p>
<p>Go ahead and play with it; files you make in <code>C:\Users</code> will be there in
<code>D:\Users</code>. Now granted, this may be a slight performance hit, because we have
moved some important user files (<code>ntuser.dat</code> for example) onto the slower HDD.
In my opinion though, this is worth it, considering all of my user data is
safe. Additionally, I can back up the entire <code>D:</code> drive, and not worry about
wasting space backing up Windows too.</p>
<h3>Notes:</h3>
<ul>
<li>I originally just renamed <code>C:\Users</code> to <code>old_users</code> but this caused me to have
<em>another</em> <code>Users</code> directory in <code>C:</code> when I looked in Windows explorer! And
<code>old_users</code> was nowhere to be found. But, everything looked okay from the
command line. I even copied it, and had the same results. So there must be
some trickery going on that causes windows explorer to show it as <code>Users</code>.
Deleting the directory made everything hunky-dory.</li>
</ul>New PC!2011-10-27T22:13:00-04:002011-10-27T22:13:00-04:00Jonathon Reinharttag:jonathonreinhart.com,2011-10-27:/posts/blog/2011/10/27/new-pc/<p>I finally built a new computer. My previous one was a Pentium D machine I built
my sophomore year of college, in 2007. I had seen evidence of <a href="https://en.wikipedia.org/wiki/Capacitor_plague">bad capacitors</a>
over a year ago, but hadn't had any problems until recently. Since June, my
system's stability had been getting worse …</p><p>I finally built a new computer. My previous one was a Pentium D machine I built
my sophomore year of college, in 2007. I had seen evidence of <a href="https://en.wikipedia.org/wiki/Capacitor_plague">bad capacitors</a>
over a year ago, but hadn't had any problems until recently. Since June, my
system's stability had been getting worse as time went on. More and more
frequent blue screens were happening, and I was getting quite tired of it. I
knew that <code>MACHINE_CHECK_EXCEPTION</code> was not a good sign, and almost certainly
pointed to a hardware issue.</p>
<p>So I did it. Tired of my crappy VIA chipset, I made sure to go with an Intel
system this time (not that there are really any other options these days, if
you have an Intel CPU).</p>
<table>
<thead>
<tr>
<th></th>
<th></th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>Motherboard</strong></td>
<td>Asus <a href="http://www.asus.com/Motherboards/Intel_Socket_1155/P8P67_LE/">P8P67 LE</a> (Part of this <a href="http://www.tigerdirect.com/applications/SearchTools/item-details.asp?EdpNo=667756&CatId=6982">Bundle</a>)</td>
</tr>
<tr>
<td><strong>CPU</strong></td>
<td>Intel <a href="http://ark.intel.com/products/52210">Core i5-2500K</a></td>
</tr>
<tr>
<td><strong>RAM</strong></td>
<td>8 GB (2 x 4GB) Corsair <a href="http://www.tigerdirect.com/applications/SearchTools/item-details.asp?EdpNo=40739">DDR3 1600MHz</a></td>
</tr>
<tr>
<td><strong>GPU</strong></td>
<td>XFX <a href="http://www.tigerdirect.com/applications/SearchTools/item-details.asp?EdpNo=604817">Radeon HD 5570</a> - 1GB DDR3</td>
</tr>
<tr>
<td><strong>PSU</strong></td>
<td>Thermaltake <a href="http://www.tigerdirect.com/applications/SearchTools/item-details.asp?EdpNo=6624656">TRX-650M</a> 650-Watt Modular</td>
</tr>
<tr>
<td><strong>Case</strong></td>
<td>Cooler Master <a href="http://www.tigerdirect.com/applications/SearchTools/item-details.asp?EdpNo=4950634">Elite 310</a></td>
</tr>
</tbody>
</table>
<p>You'll notice there are no hard drives on that list. I (somewhat recently) put
two 1TB Hatachi HDs in RAID 1 so I decided to move those drives to the new box
as well.</p>
<p>Overall, I am quite happy with the build. The case obviously isn't worth a
million bucks, but it is sturdy and does the job. The power supply is very
nice for the price; I love the modular cords (I hate a messy case!) and it runs
quiet and cool. The one thing I'm not particularly thrilled about is that
there are no mounting holes on the right side of the motherboard, so you have
about 3" of overhanging PCB, right on the edge where the big connections (24
pin ATX!) are made.</p>
<p>This ASUS board has plenty of bells and whistles that you can read all about.
Fancy graphical EFI BIOS, and EPU/TPU chips which are supposed to dynamically
auto-tune the system for performance/energy. I have TPU switched off right
now, and will play with overclocking a little bit later (especially since my
RAM is 1600MHz and the board defaults to 1333.)</p>
<p>After getting the system built, I got to thinking about <a href="http://en.wikipedia.org/wiki/Solid-state_drive">SSDs</a>. A quick look at
the numbers was enough to sell me right away. Modern SSDs are pushing over
400MB/s and some claim read speeds of up to 500MB/s. At 3.9Gbps, I'm glad my
board has several 6Gbps SATA ports!</p>
<p>So I went with the <a href="http://www.crucial.com/store/partspecs.aspx?IMODULE=CT128M4SSD2">128GB Crucial m4</a>. It showed up today and I could not wait to
get windows installed on it. Let me just say WOW. If you are for one second
considering making the switch to an SSD, go for it. I have yet to run any
benchmarks on it vs my RAID array, but it is blazing fast. Windows boots up
noticeably much quicker, and everything is just very snappy. (And yes this is
compared to a HDD install on this board/CPU I did before the SSD arrived).</p>A real Python parse integer function2011-09-21T14:04:00-04:002011-09-21T14:04:00-04:00Jonathon Reinharttag:jonathonreinhart.com,2011-09-21:/posts/blog/2011/09/21/a-real-python-parse-integer-function/<p>Is anyone else annoyed by the fact that <code>int()</code> in python is retarded and can't
tell the difference between decimal, hex, and octal?</p>
<p>Your solution:</p>
<div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">parseint</span><span class="p">(</span><span class="n">val</span><span class="p">):</span>
<span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">val</span><span class="p">,</span> <span class="nb">int</span><span class="p">):</span>
<span class="k">return</span> <span class="n">val</span>
<span class="k">if</span> <span class="ow">not</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">val</span><span class="p">,</span> <span class="p">(</span><span class="nb">unicode</span><span class="p">,</span><span class="nb">str</span><span class="p">)):</span>
<span class="k">return</span> <span class="bp">None</span>
<span class="k">try</span><span class="p">:</span>
<span class="k">if</span> <span class="n">val</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="s1">'0x'</span><span class="p">):</span>
<span class="k">return</span> <span class="nb">int</span><span class="p">(</span><span class="n">val …</span></pre></div><p>Is anyone else annoyed by the fact that <code>int()</code> in python is retarded and can't
tell the difference between decimal, hex, and octal?</p>
<p>Your solution:</p>
<div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">parseint</span><span class="p">(</span><span class="n">val</span><span class="p">):</span>
<span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">val</span><span class="p">,</span> <span class="nb">int</span><span class="p">):</span>
<span class="k">return</span> <span class="n">val</span>
<span class="k">if</span> <span class="ow">not</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">val</span><span class="p">,</span> <span class="p">(</span><span class="nb">unicode</span><span class="p">,</span><span class="nb">str</span><span class="p">)):</span>
<span class="k">return</span> <span class="bp">None</span>
<span class="k">try</span><span class="p">:</span>
<span class="k">if</span> <span class="n">val</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="s1">'0x'</span><span class="p">):</span>
<span class="k">return</span> <span class="nb">int</span><span class="p">(</span><span class="n">val</span><span class="p">,</span> <span class="mi">16</span><span class="p">)</span>
<span class="k">if</span> <span class="n">val</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="s1">'0'</span><span class="p">):</span>
<span class="k">return</span> <span class="nb">int</span><span class="p">(</span><span class="n">val</span><span class="p">,</span> <span class="mi">8</span><span class="p">)</span>
<span class="k">return</span> <span class="nb">int</span><span class="p">(</span><span class="n">val</span><span class="p">)</span>
<span class="k">except</span> <span class="ne">ValueError</span><span class="p">:</span>
<span class="k">return</span> <span class="bp">None</span>
</pre></div>
<p>Hope this helps someone.</p>phpRandDotOrg client updated to 1.0.32011-08-29T21:34:00-04:002011-08-29T21:34:00-04:00Jonathon Reinharttag:jonathonreinhart.com,2011-08-29:/posts/blog/2011/08/29/phpranddotorg-client-updated-to-103/<p>Just a quick note, that my random.org PHP <a href="http://www.random.org/clients/http/archive/">client library</a>
has been updated to <a href="https://github.com/JonathonReinhart/phpRandDotOrg">version 1.0.3</a>,
thanks to bugfixes reported to me recently.</p><p>Just a quick note, that my random.org PHP <a href="http://www.random.org/clients/http/archive/">client library</a>
has been updated to <a href="https://github.com/JonathonReinhart/phpRandDotOrg">version 1.0.3</a>,
thanks to bugfixes reported to me recently.</p>Time-Warner RoadRunner speeds2011-08-22T21:34:00-04:002011-08-22T21:34:00-04:00Jonathon Reinharttag:jonathonreinhart.com,2011-08-22:/posts/blog/2011/08/22/time-warner-roadrunner-speeds/<p>Overall, I'm pleased with the internet service I get from <a href="http://www.timewarnercable.com/east/learn/hso/roadrunner/">RoadRunner</a>.
My connection can definitely top out well over the 15Mbps it's rated at:</p>
<p><img alt="Speedtest showing 31 ms ping, 26 Mbps download, 0.97 Mbps upload" src="http://www.speedtest.net/result/1445529942.png"></p>
<p>I could stand a little faster than 1.0Mbps upload, but that's pretty typical,
as <strong>normal</strong> residential connections see very asynchronous traffic (download
usage much higher …</p><p>Overall, I'm pleased with the internet service I get from <a href="http://www.timewarnercable.com/east/learn/hso/roadrunner/">RoadRunner</a>.
My connection can definitely top out well over the 15Mbps it's rated at:</p>
<p><img alt="Speedtest showing 31 ms ping, 26 Mbps download, 0.97 Mbps upload" src="http://www.speedtest.net/result/1445529942.png"></p>
<p>I could stand a little faster than 1.0Mbps upload, but that's pretty typical,
as <strong>normal</strong> residential connections see very asynchronous traffic (download
usage much higher than upload).</p>
<p>However, today I came home to find that my router had no WAN IP, and I was
unable to view the modem status page at
<a href="http://192.168.100.1/"><code>192.168.100.1</code></a> (give that a click if you have a
Scientific Atlanta cable modem), so I power-cycled the modem. Now usually, when
I access that address, the only page I can view is the Status page. All other
ones are locked, and say "this feature is not enabled" - because we as users
are "dumb" and don't "want" to see that information. But - they are available
while the modem's connection is not Locked, meaning if the cable is unplugged
or the modem is still connecting.</p>
<p>I managed to snag a screenshot right before it locked me out again:</p>
<p><img alt="Scientific Atlanta modem screenshot" src="//jonathonreinhart.com/posts/blog/2011/08/22/time-warner-roadrunner-speeds/RR_modem.png"></p>
<p>Truly amazing how fast the actual connection is. And truly saddening to know
how much throttling is being done on their end. C'mon TW - would it really kill
you to let me have 2 or 3 of that 30MBps upload?</p>Update to root on HTC Incredible2011-08-22T21:19:00-04:002011-08-22T21:19:00-04:00Jonathon Reinharttag:jonathonreinhart.com,2011-08-22:/posts/blog/2011/08/22/update-to-root-on-htc-incredible/<p>So I've been enjoying my rooted Incredible for a little over a week now. After
my last post, I decided to install the <a href="http://www.cyanogenmod.com/devices/htc-incredible">CyanogenMod</a>
7.0.3 ROM. First let me say, "wow" at just how simple it was to download the
<code>.zip</code> file, transfer it via USB (mass storage …</p><p>So I've been enjoying my rooted Incredible for a little over a week now. After
my last post, I decided to install the <a href="http://www.cyanogenmod.com/devices/htc-incredible">CyanogenMod</a>
7.0.3 ROM. First let me say, "wow" at just how simple it was to download the
<code>.zip</code> file, transfer it via USB (mass storage) to my flash card, and use
<a href="http://www.addictivetips.com/mobile/what-is-clockworkmod-recovery-and-how-to-use-it-on-android-complete-guide/">ClockworkMod Recovery</a>
to install the new ROM (after backing up of course!!) Take that link with a
grain of salt, as UnrEVOked3 installs it by default now.</p>
<p>I had installed ClockworkMod <a href="http://www.clockworkmod.com/">ROM Manager</a> (free)
from the Market, but decided I wanted to do this first one from the recovery
image. The ROM Manager uses the recovery image anyway, so it shouldn't really
matter how I do the next one. On to the results!</p>
<p>Holy. Battery. Life.</p>
<p><img alt="Battery life screenshot" src="//jonathonreinhart.com/posts/blog/2011/08/22/update-to-root-on-htc-incredible/snap20110819_012513.png"></p>
<p>Not only is the (built-in) battery usage screen <strong>awesome</strong>, (and the ability
to screenshot), but that is 16 hours with a discharge of a little less than 50
percent! Granted, this was over a work day, so it wasn't seeing a ton of usage,
but you can see that the phone was waking up and syncing. This is possibly
twice as good as I was seeing with the stock HTC <em>Sense</em> ROM.</p>
<p>I can't show this in a screenshot, but the overall response of the phone is
like night and day compared to <em>Sense</em> (in my opinion). Screens and menus load
almost instantly. Apps load many times faster, and it feels like a real 1GHz
device! Granted, this is a fresh install, so I haven't gotten it bogged down,
but it is definitely faster than Sense ever was.</p>
<p>I strongly recommend that if you have an Android phone, that you root it, or
give it to someone to do it for you. You won't be disappointed.</p>Root on HTC Incredible2011-08-14T01:15:00-04:002011-08-14T01:15:00-04:00Jonathon Reinharttag:jonathonreinhart.com,2011-08-14:/posts/blog/2011/08/14/root-on-htc-incredible/<p>So I decided today that it was finally time to root my HTC Incredible. And as
I was told by several friends, it was pretty much a piece in the cake. Anyone
wishing to do so, I recommend following this
<a href="http://www.jonamerica.com/technology/updated-root-the-htc-droid-incredible/">walk-through by Jonathan Eggers</a></p>
<p>The basic run-down:</p>
<ul>
<li>
<p>Install the <a href="http://developer.android.com/sdk/index.html">Android …</a></p></li></ul><p>So I decided today that it was finally time to root my HTC Incredible. And as
I was told by several friends, it was pretty much a piece in the cake. Anyone
wishing to do so, I recommend following this
<a href="http://www.jonamerica.com/technology/updated-root-the-htc-droid-incredible/">walk-through by Jonathan Eggers</a></p>
<p>The basic run-down:</p>
<ul>
<li>
<p>Install the <a href="http://developer.android.com/sdk/index.html">Android SDK</a> - you
really just need this for adb, the Android Debug Bridge. This provides you
with an interactive shell, as well as the ability to push / pull files, and
install <code>.apk</code> packages. If you download the <code>.zip</code> instead of the <code>.exe</code>, you
don't have to worry about installing the JDK.</p>
</li>
<li>
<p>Run <a href="http://unrevoked.com/recovery/">unrevoked3</a> to perform the root process,
as well as install the <a href="http://www.addictivetips.com/mobile/what-is-clockworkmod-recovery-and-how-to-use-it-on-android-complete-guide/">ClockworkMod Recovery</a>,
which allows you to do some cool things pre-OS boot.</p>
</li>
<li>
<p>Use clockworkmod to make a full NAND backup.</p>
</li>
<li>
<p>Install <a href="http://matrixrewriter.com/android/">Titanium Backup</a> to make/restore
backups while booted into the UI. Also allows you to uninstall a bunch of the
junk Verizon forces you into having (Skype mobile, VZ navigator, etc)</p>
</li>
<li>
<p>Install <a href="http://code.google.com/p/android-wifi-tether/">WiFi Tether</a>.</p>
</li>
</ul>
<p>I also installed a new <a href="http://forum.xda-developers.com/showthread.php?t=648555">boot splash-screen</a>
because I was tired of the stock one. For 2.2, you need to rename the
<code>bootanmiation.zip</code> inside that zip file to <code>VZW_bootanimation.zip</code> and send it
down. You can also replace the <code>VZW_Droid.mp3</code> with a sound of your choice.</p>
<p>Finally (for now!) I installed <a href="http://teslacoilsw.com/quicksshd">QuickSSHd</a> by
TeslaCoil Software. It's pretty much just <a href="http://teslacoilsw.com/quicksshd">dropbear</a>
with a nice UI, but it was everything I was looking for and only $1.75 in the
Market. If you already have shared keys set up for other SSH servers, you can
simply copy your public key to <code>~/.ssh/authorized_keys</code>, just like OpenSSH (the
same format works).</p>
<p>Next up is to check out some of the top root apps on <a href="http://androidsu.com/2011/06/top-9-root-apps/">androidsu.com</a>.</p>
<p>Looking forward to playing with some kernels and ROMs in the future, but for now I am quite happy!</p>Windows 7 won't boot!2011-08-01T23:33:00-04:002011-08-01T23:33:00-04:00Jonathon Reinharttag:jonathonreinhart.com,2011-08-01:/posts/blog/2011/08/01/windows-7-wont-boot/<p>Well in a nutshell, here's how this problem unfolded, and came to be corrected.</p>
<h3>New Install</h3>
<p>I bought a pair of 1TB drives, and set them up in a RAID 1 array, using the
VT8237A southbridge's built-in RAID feature. I left my old 200GB PATA drive
in place, so I …</p><p>Well in a nutshell, here's how this problem unfolded, and came to be corrected.</p>
<h3>New Install</h3>
<p>I bought a pair of 1TB drives, and set them up in a RAID 1 array, using the
VT8237A southbridge's built-in RAID feature. I left my old 200GB PATA drive
in place, so I could copy my files to the array. Then, I installed Windows 7 on
the array, and everything was great. Until I happened to notice (while cleaning
up) a new file: <code>bootmgr</code> on the old drive. A quick Google search told me that
this was the Vista/7 bootloader. Crap! The brilliant installer decided to put
the Win7 install on the new RAID array, where I specified, but put the
bootloader on the old drive!</p>
<p>Steps:</p>
<ul>
<li>Unhook old drive, which renders system unbootable.</li>
<li>Boot up Win 7 setup DVD, and select Repair (not install).</li>
<li>Choose command prompt.</li>
</ul>
<p>From Command prompt:</p>
<ul>
<li>diskpart</li>
<li>list disk</li>
<li>select disk 0</li>
<li>list partition</li>
<li>select partition 1</li>
<li>active</li>
<li>exit</li>
</ul>
<p>(This marks the partition as active, which it was not before. This is required
for the BIOS to see it as bootable.)</p>
<p>Next, need to fix boot sector:</p>
<ul>
<li><code>bootrec /FixMbr</code></li>
<li><code>bootrec /FixBoot</code></li>
<li><code>bootrec /RebuildBcd</code></li>
</ul>
<p>Then, close command prompt, and choose startup repair. It may take once
through for it to say fixed an error, then reboot. Then go back to startup
repair. Here you should be able to run the automatic startup repair, and it
will tell you that <code>BOOTMGR</code> was missing, which it will correct.</p>MySQL Service won't start on Windows 72011-07-12T20:20:00-04:002011-07-12T20:20:00-04:00Jonathon Reinharttag:jonathonreinhart.com,2011-07-12:/posts/blog/2011/07/12/mysql-service-wont-start-on-windows-7/<p>So today, I attempted to install MySQL on Windows 7. From the <a href="http://dev.mysql.com/downloads/installer/">MySQL Download
site</a>, I grabbed the latest version
of their <code>.msi</code> installer, <code>mysql-installer-5.5.13.2.msi</code>. I went through the
installer, and found that the last step, starting the MySQL services (<code>mysqld</code>)
was failing. The service existed …</p><p>So today, I attempted to install MySQL on Windows 7. From the <a href="http://dev.mysql.com/downloads/installer/">MySQL Download
site</a>, I grabbed the latest version
of their <code>.msi</code> installer, <code>mysql-installer-5.5.13.2.msi</code>. I went through the
installer, and found that the last step, starting the MySQL services (<code>mysqld</code>)
was failing. The service existed in <code>services.msc</code>, and in the registry, but
it refused to start. Attempting to start it from the command line (<code>NET START
MySQL</code>) failed, giving the following output:</p>
<div class="highlight"><pre><span></span>The MySQL service is starting...
The MySQL service could not be started.
A system error has occurred.
System error 1067 has occurred.
The process terminated unexpectedly.
</pre></div>
<p>Very descriptive. Thanks. I tried checking for a log file from MySQL, but
could't find it. Strange. Well, it turns out, MySQL on windows has its data
directory at <code>C:\ProgramData\MySQL\MySQL Server 5.5\data</code>. You can verify this
in your installation by looking at the <code>my.ini</code> file, in your MySQL
installation directory (probably <code>C:\Program Files (x86)\MySQL\MySQL Server
5.5\</code>), and finding the line that says <code>datadir=</code></p>
<p>I didn't even know ProgramData existed! It's hidden, so either unhide it
(Control Panel -> Folder Options -> Show hidden...) or simply enter
<code>c:\ProgramData</code> into your explorer title bar. In this data directory, there
should exist the log file <code>[hostname].err</code>. Taking a glance at that, I found:</p>
<div class="highlight"><pre><span></span><span class="n">InnoDB</span><span class="o">:</span> <span class="n">Error</span><span class="o">:</span> <span class="n">log</span> <span class="n">file</span> <span class="o">.\</span><span class="n">ib_logfile0</span> <span class="k">is</span> <span class="n">of</span> <span class="n">different</span> <span class="n">size</span> <span class="mi">0</span> <span class="mi">33554432</span> <span class="n">bytes</span>
<span class="n">InnoDB</span><span class="o">:</span> <span class="n">than</span> <span class="n">specified</span> <span class="k">in</span> <span class="n">the</span> <span class="o">.</span><span class="na">cnf</span> <span class="n">file</span> <span class="mi">0</span> <span class="mi">56623104</span> <span class="n">bytes</span><span class="o">!</span>
</pre></div>
<p>Thanks to <a href="http://forums.mysql.com/read.php?11,425620,425620">this post on forums.mysql.com</a>,
I found that simply deleting <code>ib_logfile0</code> and <code>ib_logfile1</code> solved the problem.
Seems like a dumb installer mistake to me! A <a href="http://bugs.mysql.com/bug.php?id=28324">bug report</a>
already exists, so I'll just keep quiet until the next install :-) Hope this
helps!</p>Windows 7 "Unidentified Network" woes2011-06-21T17:51:00-04:002011-06-21T17:51:00-04:00Jonathon Reinharttag:jonathonreinhart.com,2011-06-21:/posts/blog/2011/06/21/windows-7-unidentified-network-woes/<p>There are hundreds of posts in forums and in blogs with people complaining
about not being able to click the "Public Network" link and change an
"Unidentified Network" to the Private profile:</p>
<p><img alt="Unidentified network - Public network" src="//jonathonreinhart.com/posts/blog/2011/06/21/windows-7-unidentified-network-woes/20110621/nopub.png"></p>
<p>In this case, it was my VirtualBox Host-Only connection, but this could really
apply to any private network …</p><p>There are hundreds of posts in forums and in blogs with people complaining
about not being able to click the "Public Network" link and change an
"Unidentified Network" to the Private profile:</p>
<p><img alt="Unidentified network - Public network" src="//jonathonreinhart.com/posts/blog/2011/06/21/windows-7-unidentified-network-woes/20110621/nopub.png"></p>
<p>In this case, it was my VirtualBox Host-Only connection, but this could really
apply to any private network with static IP addresses and no DHCP server (and
usually no Default Gateway - I think this is what makes Windows decide it is
"unidentified").</p>
<p>In my situation, I was unable to ping the windows host from my VM, and
subsequently couldn't access any Samba shares on my host. After hours of
digging, I gave up on trying to "identify" this network, and instead went after
the windows firewall settings. Since windows insists on making this a public
network, I chose to disregard windows firewall, for this interface only:</p>
<p><img alt="Firewall config 1" src="//jonathonreinhart.com/posts/blog/2011/06/21/windows-7-unidentified-network-woes/20110621/firewall1.png"></p>
<p><img alt="Firewall config 2" src="//jonathonreinhart.com/posts/blog/2011/06/21/windows-7-unidentified-network-woes/20110621/firewall2.png"></p>
<p><img alt="Firewall config 3" src="//jonathonreinhart.com/posts/blog/2011/06/21/windows-7-unidentified-network-woes/20110621/firewall3.png"></p>
<p>After this, I was able to ping the windows host, and view its Samba shares.
Hope this helps.</p>(x % 2), What's all this and-ing and or-ing?2011-02-24T01:38:00-05:002011-02-24T01:38:00-05:00Jonathon Reinharttag:jonathonreinhart.com,2011-02-24:/posts/blog/2011/02/24/x-2-whats-all-this-and-ing-and-or-ing/<p>While trying to understand some x86 disassembly, I came across one particularly
confusing bit of code (modified for this example):</p>
<div class="highlight"><pre><span></span>mov eax, edx
L0:
and eax, -2147483647 ; 80000001H
L1:
jns SHORT L4
dec eax
L2:
or eax, -2 ; fffffffeH
L3:
inc eax
L4:
mov DWORD PTR _r$[ebp], eax
</pre></div>
<p>I …</p><p>While trying to understand some x86 disassembly, I came across one particularly
confusing bit of code (modified for this example):</p>
<div class="highlight"><pre><span></span>mov eax, edx
L0:
and eax, -2147483647 ; 80000001H
L1:
jns SHORT L4
dec eax
L2:
or eax, -2 ; fffffffeH
L3:
inc eax
L4:
mov DWORD PTR _r$[ebp], eax
</pre></div>
<p>I couldn't intuitively look at this one and understand what it meant. I could
tell that it was primarily looking at only the highest (sign) and the lowest
bits. I ended up putting together a table, showing eax at each line (ie. after
the result of the previous line)</p>
<div class="highlight"><pre><span></span>L0 L1 L2 L3 L4 result
----------------------------------------------------
-ODD 10..01 10..00 11..10 11..11 -1
-EVEN 10..00 01..11 11..11 00..00 0
+ODD 00..01 00..01 1
+EVEN 00..00 00..00 0
</pre></div>
<p>Oh, now it's painfully obvious; it's just a modulo-2 (<code>% 2</code>) operation. But why
was that so complicated? After some searching, it appears that one could just
use <code>IDIV</code> (Signed Divide) instruction, which places the quotient in <code>(E)AX</code>
and the remainder in <code>(E)DX</code>. One instruction, and there's your result, what
was so hard about that?</p>
<p>Turns out that <code>IDIV</code> is really slow. <code>IDIV</code> on a Pentium processor takes a
whopping 46 clock cycles! Let's compare that to the worst case of this other
funky algorithm:</p>
<div class="highlight"><pre><span></span>and (r,i) = 1
jns (short) = 1 (4 if mispredicted)
dec (r) = 1
or (r,i) = 1
inc (r) = 1
</pre></div>
<p>Wow, only 5 clock cycles, (8 if the <code>jns</code> was mispredicted). No wonder they go
through all that hassle!</p>
<p>So next time you see this bizarre x86 assembly, hopefully you can identify it
as just a <code>%2</code> !</p>
<p>References:
- siyobik.info
- agner.org</p>