- Calendar -

November 2008
Su Mo Tu We Th Fr Sa
1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30

- Archive -

- Browse By Random Tag -

- Most Commented -

- Random Favourites -

- Blogs I Like -

- Email Viruses Received -

- My Geek Code -

-BEGIN GEEK CODE BLOCK-
Version: 3.12
GIT d-- s: a- C++ UL++ P+++ L+++ E--- W+++ N+ o-- K- w--- O- M-- V- PS+++ PE-- Y++ PGP t++ 5+++ X R tv b+ DI+ D++ G e h r+ y+
--END GEEK CODE BLOCK--
Get The Encoder
Get The Decoder

- My Blog Code -

-BEGIN BLOG CODE BLOCK-
B6 d+ t++ k+ s++ u-- f i++ o+ x+ e l c-- --END BLOG CODE BLOCK--
Blog Code Encoder
Blog Code Decoder

- The Internet is Cool -

- Nifty Blog Toys -

RSS Feed

- Content License -

Blog

How to Keep ssh-agent from Sticking its Nose Where it Doesn't Belong

For the longest time, I've been fighting with this problem:

$ ssh someserver.ca
Received disconnect from 123.123.123.123: 2: Too many authentication failures for username

It never asked for my password, it just flat-out failed. After some digging, I realised that the force behind this was my use of ssh-agent, a daemon that holds onto the myriad of keys (and their respective passwords) that I use to access all of my servers. It turns out that by default ssh-agent attempts to use every key you've got to access a server. However, because the destination server usually rejects login attempts > 6, the whole thing blows up before it ever gets to the "enter your password" step.

The solution is this handy one-liner in your ssh client config (~/.ssh/config or /etc/ssh/ssh_config):

  Host *
    IdentitiesOnly yes

Contrary to what you might think this means, IdentitiesOnly doesn't force the use of identities, rather it tells the client to only use identities explicitly defined for this host. This way my client uses identities assigned to a host via the config, and if one isn't set, it isn't used.

Why this isn't the default is beyond me.

s/Gentoo/Arch/g

I think that it's been more than 12 hours. More like 14... it's all a blur really.

I started today with a lofty goal: do a complete system wipe of Moulinrouge, my file/web/mail server that hosts pretty much all of my life... including this site. I decided to take the last step in my abandonment of Gentoo Linux in favour of my new love, Arch Linux, the process of which only added to the difficulty. I also moved my DNS and DHCP servers to Serenity my firewall machine as I'd gotten tired of the various exceptions I had to make to host those services with Moulinrouge.

Strictly speaking though, the whole thing went rather well. I had rsync'd my entire filesystem over to the 1TB USB2 drive, and the Arch install ran with no problems at all. The biggest hiccup came when I realised that Exim isn't packaged with MySQL support in Arch, so I had to do a manual compile for that one using ABS. A pretty cool experience I might add, though frustrating when you condiser how common such a setup may be. For those interested, I followed a helpful forum post on what needed to be changed and created a simple patch file for PKGBUILD so I can use it again later:

# pacman -S abs
# abs
$ mkdir -p $HOME/abs
$ cp -r /var/abs/extra/exim $HOME/abs/
$ patch $HOME/abs/exim/PKGBUILD PKGBUILD.patch
$ cd $HOME/abs/exim
$ makepkg
$ pacman -S exim-4.68-5-i686.pkg.tar.gz

The other fun bit I discovered was SSH's ability to not only run its own version of secure-ftp (sftp), but also run it in a chroot environment with ChrootDirectory. This required a lot of experimentation so I thought that I'd post a few notes here:

  • In a chroot environment, logging is not possible until OpenSSH 5.2. Don't try, it'll only cause you pain.
  • You cannot chroot a user into her or his home directory as the "new root" must be owned by the root user. Instead, what i found worked well was setting up a series of user directories owned by root under /srv/http/untrusted/username which then had the user's websites inside.

Here's my sshd_config snippet:

Subsystem  sftp  internal-sftp

Match Group untrusted
  X11Forwarding no
  AllowTcpForwarding no
  # Won't work 'till 5.2
  #ForceCommand internal-sftp -l VERBOSE
  ForceCommand internal-sftp
  ChrootDirectory /srv/http/untrusted/%u

Lastly, PHP in Arch is very different from my experiences in Gentoo, Unbuntu, Debian, Suse and Redhat. Even FreeBSD was more intuitive. For starters, Arch uses some less-than-common defaults in php.ini:

  • error_reporting = E_ALL
  • magic_quotes_gpc = Off
  • short_open_tag = Off

Then, when you try to start up Apache, you find that it's not loading PHP. To make that happen, you have to add the following to httpd.conf and reload your webserver:

LoadModule php5_module modules/libphp5.so
Include conf/extra/php5_module.conf

After all that though, you'll notice that MySQL and a suite of other extensions you're used to seeing as part of PHP aren't there. If you stopped by this site earlier for example, you would have seen the glaring errors complaining that mysql_connect() didn't exist. To make all of that work, you have to go back into php.ini, scroll down to the bottom and un-comment the various extension lines... among them:

extension=mysqli.so

There were other fun problems, but this post is already quite long and it's almost 5am now. Must get some sleep so I can finish it all up tomorrow!

What To Backup

In a recent rash of system re-installs, I've learnt the hard way what not to do. I'm keeping this list here for my own future reference in the hopes that I might save myself future headaches.

Before doing any wipe and re-install, the following should always be done:

  • Export bookmarks
  • Export kwallet
  • Export contacts
  • Commit all subversion sandboxes
  • Backup /home/*
  • Backup /usr/local
  • Backup /etc
  • Backup subversion repositories
  • Dump databases

On a personal note, I apologise for my lack of blogging lately. I have a lot about which I want to post and I've been having trouble finding the time. I shall endevour to do better.

On My Plate

I'm struck suddenly by the number of things to which I've committed myself in my "off" hours:

  1. My Municipal Collective idea
  2. Stephen's girlfriend's site (just HTML layout etc.)
  3. Wordpress fix for Stephen's Civics Education Network site
  4. Mapping project for the VPSN
  5. A complete rewrite of this site (it's been 2years)
  6. A ticket selling project with my brother

Aside from #1, all of the above are technical in nature and require a serious amount of attention. Looks like I had better put a dent in these this weekend.

The Five Stages of Refactoring

Big thanks to Corey for brightening my day with this one:

  1. Disbelief
    • "Who wrote this!?
  2. Anger
    • "I'm not cleaning this up!"
  3. Bargaining
    • "Okay, we'll fix up this module if you promise we'll just rewrite everything else."
  4. Depression
    • "This is never going to get any better."
  5. Acceptance
    • "I'll just create a wrapper..."
Stylesheets in Facebook

I wrote a fun bit of code for doing Facebook apps and thought that I would share.

One of the big problems with Facebook's app system is styleising text. You can't include an external file because they won't let you. This leads a lot of designers to write their code directly into the style="" attribute in the HTML. This can get ugly fast, and is the reason external .css files exist in the first place.

To remedy this, you can create the usual .css file externally and then call this helper function to get the job done for you. If you have to use paths etc in it, you can even pass a key/value pair dictionary to it to swap out keywords so that a strings like this:

	background-image: url('http://domain.tld/path/to/some/image.png');

Can look like this:

	background-image: url('[[images]]/image.png');

The call for this type of thing would be just:

	print '
		<style type="text/css">
			'. Helper::css('myStyle', array('images' => 'http://domain.tld/path/to/some')) .'
		</style>
	';

Here's the soruce if you're interested:

<?



    /**
    *
    * Helper functions for the view
    *
    * \author Daniel Quinn (corporate at danielquinn.org)
    *
    */

    class Helper
    {

        /**
        *
        * Simple templating engine for cascading style sheets since
        * Facebook doesn't like the idea of including external .css
        * files.  Instead, we keep the files separate then call this
        * method with a series of key/value replacers if need be.
        *
        * \param  file  Full path for the css to include
        * \param  vars  A dictionary lookup of key value pairs to be
        *               replaced in \a file.
        *
        */
        public static function css($file, $vars = array())
        {

            $in = file_get_contents("$file.css");

            $src = array();
            $dst = array();

            foreach ($vars as $k => $v)
            {
                $src[] = '[['. $k .']]';
                $dst[] = $v;
            }

            return str_replace($src, $dst, $in);

        }

    }



?>

Not revolutionary, I know. But maybe it'll help somebody out there.

Hug a Developer

Found via The Blomsa Code, Margaret sent me this little gem. I should mention that the embed code the thing gave me appears to only include <embed> data and not Exploder's <ojbect> tags so I can't be sure it'll work in their browser.

Ubiquity

I just watched this amazing video on the future of how we'll use the Internet. For the nerdy among you: remember how people are always saying stuff like "this will make it a web service that other people can access for whatever they like"? Well this is the end result:

The problem with the way the web stands now, is that I have to go to services to use them.

Such a brilliantly simple observation. These guys are doing a great job.

Switching to Gnome

Over the past few days, I've been trying to switch from KDE to Gnome. It's faster, Free-er and in many ways, prettier than KDE, so I thought that I'd give it a shot... but it's not going to happen and here's why:

  1. Nautilus doesn't support bookmark folders. It's pretty impressive really, but when your filesystem browser is expected to be able to connect to local drives, network drives and remote drives over SFTP, assuming that a user is only going to have 6 or 7 bookmarks is unreasonable.
  2. Terminal is lame. It may be more responsive than Konsole, but you can't move between tabs with the keys and wrap from the last to the first, and you can't paste from the highlight-copy clipboard with the keyboard while Konsole will let you use Ctrl+Shift+Ins for the highlight copy, and Shift+Ins for standard copy.
  3. No suitable replacement for Kwallet. Gnome stores some of your passwords with its keyring manager, Firefox stores its own (unencrypted) and Thunderbird stores its own (encrypted). In KDE, I login, give my master password and my encrypted password db is available to all programs for which I need it.
  4. No suitable replacement for Klipper. I got Glipper installed, but it's nowhere to be found.
  5. No decent text editors / IDEs. I tried Gvim, GPHPEdit, and Bluefish and they all suck in comparison to Kate, KDE's simple text editor and we're not even trying to compare KDevelop here. The big killer for me: no predictive text handling.
  6. Firefox may be more functional than Konqueror, it's still way ugly by comparison.

Frankly, I've found Gnome to be sorely lacking in what I would consider key areas. People want their passwords and things memorised and they want them accessible in one easy step. I have well over 100 filesystem bookmarks and I'm a programmer -- I need a good text editor. If I wanted a prettier Vim, I wouldn't be using a GUI.

Maybe I'll try again next year but until then, KDE, though it may be slow and bloated, at least does what I think a GUI should.

Python Talks to Questionable Content

Yeah, I know it's late, but I got obsessed and couldn't turn away. Now I have a really slick python script that pulls down the latest Questionable Content strip and adds it to my collection to read later:

#!/usr/bin/env python

import os, sys, re
import pycurl, urllib2

destination = "/path/to/qc/repository"

class QC:

  def __init__(self):

    self.contents = ''
    self.baseurl  = 'http://questionablecontent.net/'


  def callback(self,buf):

    self.contents = self.contents + buf


  def end(self):

    c = pycurl.Curl()
    c.setopt(c.URL, self.baseurl)
    c.setopt(c.WRITEFUNCTION, self.callback)
    c.perform()
    c.close()

    try:
      return int(re.search('.*\/comics\/(\d+)\.png', self.contents).group(1))
    except:
      print ""
      print "  The regular expression no longer works."
      print "  You might want to check into that."
      print ""
      exit()


  def fetch(self,n):

    strip = urllib2.build_opener().open(self.baseurl + 'comics/' + str(n) + ".png").read()

    f = "%s%s%04d%s" % (destination, "/", n, ".png")

    fout = open(f, "wb")
    fout.write(strip)
    fout.close()


# Main -----------------------------------------------------------------------

qc = QC()

for i in range(1, qc.end() + 1):
  f = "%s%s%04d%s" % (destination, "/", i, ".png")
  if not os.path.exists(f):
    print "Fetching strip #" + str(i)
    qc.fetch(i)
pit-faulty