I had a repeat of a problem that I’ve probably had many times over the years. I wanted to write down the solution before I forgot it, because it had been long enough since the last time that I’d forgotten the fix.
Let’s set the stage: I wanted to SSH into a remote system. In my case, that remote system was a Mac OS Snow Leopard system. The client was also Mac OS X.
On that remote system, I had enabled sshd. This is done on Snow Leopard with System Preferences > Sharing > Remote Login. (In the Sharing System Preferences, you set up the users that are allowed to remote log in, either allowing all users or setting up an ACL that only allows specific users. If you set up the ACL, it should supercede whatever additional user/group login restrictions you’ve configured in /private/etc/sshd_config.)
Then, I tried to SSH from my client system. Instead of a successful login, I was told the following — before I was prompted for a password.
Scratching your head, you add verbosity to the SSH connection attempt.
I searched for other people having the same problem with “debug1: SSH2_MSG_KEXINIT sent,” because other people always have the same problem and some of them wrote about it and some of those solved it. Right?
Well, in this case, the other solutions I found were not helpful to my specific situation. But many people responding to pleas for help did mention the always-good advice to “check the server logs.” Which I could do, so I did.
In the secure.log, I found several groups of lines like this corresponding to the times I had tried to log in:
That reminded me of the common problem with SSH host keys on Radmind-managed computers. See, Mac OS X will try to create the host keys if they are missing, but not if they are zero-length. On Radmind-managed computers, it was trivially easy to get zero-length SSH host key files in /private/etc because the tendency was to manage them with negative transcripts. Files listed in negative transcripts would be created if they were missing, but they would be created as empty files (by design).
Empty SSH host key files will prevent you from logging into that system with SSH.
I checked the server and — sure enough — the host key files were zero length. I deleted them, then stopped and restarted Remote Login for good measure. This solved the problem, and I could log in from the client.
I had a need to read some settings from a Python script on Mac OS X recently. I wanted to be able to change selected parameters for the script — some of which could be site or implementation specific — without embedding them directly in the code. Since the script was Mac OS X-only, using a property list seemed like a good idea.
With customizable settings from a property list, a script could become useful and more customizable for a wider community — or even different internal audiences.
I thought reading preferences was going to take a lot of effort. I was, however, pleasantly surprised at how easily I was able to accomplish it.
Asking others who had been down this route before resulted in some links to Apple docs. I wanted a more concrete example of how it was done in Python, and I got a great one.
That example came from reading the source to munkilib from the open source project, Munki. Since Munki had its own preference file, it needed to read from it, and its example was very enlightening.
Frogor directed me to a specific spot in the Munki code. That spot demonstrated how to read a preferences file with CoreFoundation.
Munki also has its own internal defaults for preferences. The munkilib/munkicommon.py example showed how to implement default settings in their absence in a property list. That provides a fallback position so that you always have some value available. In Munki, setting the defaults was done within a function. It seemed that it would be more generic if those defaults were separated out of the preference-reading function.
My own example of how to read a plist is outlined below. This focuses on just what you need in order to read the preferences and provide default settings for a larger script. A single set of preferences can be shared between scripts, and each script can encode its set own defaults. While you can create your own keys and values, for the example below, I will use the keys “StringPreference,” “BooleanPreference,” “ArrayPreference,” and “DictionaryPreference.”
The script won’t do anything yet, until we create a main() or other functions to call the get_preferences function. Since you’d be reading preferences as part of a larger script, this is fine for now. However, with what’s written already, you can test out reading preferences interactively with the shell and Python interpreter.
That’s it, the expected results were returned. Notice that the output for StringPreference and BooleanPreference are taken from the property list, while the empty array and dictionary come from the default_preferences in the script.
Update: Greg pointed out that there is a certain degree of danger using #!/usr/bin/env python as the shebang line in the script. Should a system have a non-Apple installation of Python, then /usr/bin/env python might return that. Another Python is probably less likely to be able to bridge CoreFoundation, and thus wouldn’t be able to use the CFPreferencesCopyAppValue call to read preferences.
I think the overall shebang danger is small because few Mac OS X systems will have an alternative Python installed, but clearly your chances of that increase in certain situations. To eliminate this risk, do what Munki does and insert the #!/usr/bin/python shebang instead.
In previous articles, I described how to Install Mercurial 1.9, Dulwich, and Hg-Git on Mac OS X Snow Leopard and Install Mercurial 1.9, Dulwich, and Hg-Git on Mac OS X Lion. For either of those operating systems, we can further extend Mercurial with support for connecting to Subversion repositories. While we could enable the bundled Convert extension, the Hgsubversion extension adds live access to remote networked Subversion repos, so it sounds more interesting.
My personal goal in doing this is to be able to work with the InstaDMG repository. It is hosted on Google Code, uses a Subversion repo, and depends upon Subversion keyword substitution. It presents an interesting challenge.
So, let’s install Hgsubversion to add Subversion support to the Git support we’ve previously set up. We need to take the following additional steps, going beyond what is done in the previous articles. To continue, you must already have installed:
Hgsubversion also needs Subversion to be installed. The Mercurial extension then has two different ways of working with Subversion. The Hgsubversion docs I read indicated that Subvertpy is preferred over the other method — using Subversion’s SWIG bindings — so we’ll install this additional Python module first. The docs also recommend running tests on Hgsubversion before using it on projects, so we will try that, as well.
Start with installing Subvertpy:
easy_install command in Terminal.easy_install again to get hgsubversion. However, version 1.2.1 in PyPi didn’t work for me. So, to get a more current working version, I went to the source repository to get the latest software.That’s it! Hgsubversion has been installed and enabled. Even though we got errors from the tests, we can proceed.
kwdemo. You must be in the directory for the cloned repository and have enabled the Keyword extension.Notice that “Revision: 425” is returned when keywords are expanded, replacing the “$Revision” keyword. This is precisely what we need with InstaDMG, where the revision information is reported when the instadmg.bash script is run.
I’ve been using a few Kerberos-enabled Web applications lately. I tend to need to use a different Kerberos identity to log into these applications than I use for my Mac. This has tended to result in frustration, because my browsers have not prompted which identity for which application.
I found that I can work around this by changing which identity is the default one:
Once you have logged in to each Kerberized Web application, you shouldn’t need to reauthenticate during the same login session. Switching back to your original default identity ensures that the regular uses of your Mac OS X login work with single sign-on.
There may be times when you want to obtain the number of the latest available version — not just the latest installed version — of a software package through automated means. If the vendor or project provides a syndication feed (either RSS or Atom) that describes new releases, then you may be able to parse that data and get the newest release from it.
As an example, let’s examine the RSS feed for Group Logic’s ExtremeZ-IP. Other developers provide RSS/Atom feeds for their releases, but the EZIP feed is a good one to start a demonstration with because it is generally structured well.
We can break apart the EZIP feed with the Universal Feed Parser module for Python, which you must obtain separately.
Update: Because of Mark Pilgrim situation (also described here), the Universal Feed Parser Web site is no longer available. There is an alternative source for the Universal Feed Parser at Google Code, and I have cloned the Universal Feed Parser repository to Bitbucket from there.
As you can see, the “ExtremeZ-IP Latest Releases” feed is automatically recognized as RSS 2.0. I prefer to use HTTPS for fetching these feeds whenever possible, so if the developer has an HTTP feed, I try to see if it also works with HTTPS.
Next, let’s find out where the version numbers are kept in the feed. It looks like they are in the entry title, based on reading the feed in Safari RSS. I can confirm that with the Universal Feed Parser. We’ll want to examine the title of every feed item so we can better handle both current and future entries from the feed. There are more entries to the EZIP than I will print out.
We get Unicode strings as output from the Universal Feed Parser. That’s why the quoted strings are preceded with a “u” character.
I’d like to strip out the version string from the title element in each entry. I’m going to do so by splitting on whitespace and getting the last group of characters from the string. (This doesn’t account for text like “Hot Fix,” as seen in the EZIP feed, but it is still a good enough starting point for my purposes.)
By stripping out the build number after “x” in the version string, you potentially lose some data. In the EZIP feed, there are entries where two consecutive version numbers are the same except for the build number after the “x.” However, depending on your needs, it may still be useful to eliminate that part of the version string, so we’ll do that next.
We really only need the most current or “top” item in the feed, since that should give us the newest release number. The newest version in this particular feed should be in the first entry. That’s “entries[0]” below, because we’re using Python and it zero references the first item in lists.
There, we now have the version number of the most current release, 7.1.1, for the product. We have drawn it straight from the developer’s syndicated feed, so it is as current as the developer makes it.
How could that be useful? The output can be compared against other data, like the currently-installed version. The comparison, in turn, could be made part of a monitoring workflow, so you could get alerts if you fall behind.
If we didn’t strip the build number after the “x,” we would be left with a complex version number. Some Python tools, like distutils, will not currently handle the trailing characters in the version number well.
I have found that you can improve upon distutils’ StrictVersion/LooseVersion version number handling by switching to parse_version in pkg_rsources (“from pkg_resources import parse_version as V”). More coverage of that topic appears in PEP 386. If you are comparing the original version strings from the EZIP feed with similarly complex output from elsewhere, then I would probably use the pkg_resources module.
Brix Anderson’s post about Downloading Sony GPS Assist Data Manually includes a Perl script that downloads the GPS Assist data for Sony cameras.
The GPS Assist data is stored on the memory card. When a memory card with GPS Assist data is inserted into a compatible GPS-equipped Sony camera — like the awesome Alpha SLT-A55V I got a few months ago — the camera has much faster lock-on times when searching for its location. The lock-on may take 10 seconds instead of requiring minutes.
I had been working without GPS Assist data since I bought the camera. I didn’t understand its value, but then I had captured photos where most of the shoot was incorrectly geotagged. After investigating this, I found the GPS Assist data should help, but that it required software on the desktop to update that data. Sony did not supply the relevant package for Mac OS X to do this.
Since I wanted to make sure I got updated location information on my photos, I did some searching and came across Brix’s page. I was honestly surprised to find that the GPS Assist data was written to the same memory cards as the photos, but it does make sense after some more thought.
Brix’s Perl script there certainly did the trick; my SLT-A55V picked up on the new GPS Assist data on the first card I tried it with. I have a limited number of cards, so I wrote a wrapper shell script that would run the Perl downloader script if certain volumes were present in /Volumes. I control the names of the cards, so I also control their paths.
I then call that wrapper script via a LaunchAgent. The LaunchAgent is triggered via “StartOnMount,” so it watches for new volumes to be mounted by Mac OS X. When a volume is mounted, the LaunchAgent runs, calls the wrapper script, the wrapper script checks for volume names, and if there is a match, runs the GPS Assist Perl script.
Now, every time I insert my memory cards to download photos, I get freshly-updated GPS Assist data for my camera.
In the course of a conversation with Jesse today, I launched into action to fix the copyright statement in my site’s footer block. It still listed the copyright dates as “1999-2009” when the year had clearly rolled over into 2010 some time ago. Ahem.
Drupal 6, to my knowledge, doesn’t have a built-in way to insert a variable into the body of a text field in a node or block. However, it does have the very-powerful Token API, of which I’m a big fan. Tokens let you insert variable data. It’s just not always easy to figure out how a mere mortal — rather than a module developer — can take advantage of tokens in Drupal. (Variable insertion was a key feature of the UserLand Manila CMS I started using in the late 90’s, and I miss that sort of capability.)
In Drupal 5, I had previously used the Copyright module. Copyright module integrated with the Token API so you could use tokens in the block it created. The module was never upgraded for Drupal 6, so my footer copyright block became static text.
I realized that an Input Filter that worked with the Token API would probably let me do what I want, and I found a module that provided that missing link.
Here’s what I did so I could insert a constantly-advancing date variable into my copyright footer block:
Now, my copyright block should always show the current year in the date range, like this: 1999-2012.
As you may know, I absolutely live to submit crash and bug reports to vendors.
Normally, these reports are staid affairs involving copious amounts of detail, exquisite reproduction steps, and both expected and actual results. I’m sure that these kinds of reports get a certain amount of attention from software developers. I say that with confidence because at least one person in that position has told me my bug reports are his favorite. Sure, it was a few years ago now, but I’m sure I’ve still got some mojo.
Occasionally, I get the opportunity to take some creative license with these submissions. For example, there was that one involving the hockey game. The standard was raised after I saw my current all-time favorite crash report.
So, when I had a particularly frustrating crash in Safari, I decided I needed to raise my game. After all, I’ve probably submitted 33 boring crash reports on Safari already. Here’s what I came up with this time:

For those of you reading with Lynx, the text of the submission was:
Safari was launched by me. It had tabs. The set of tabs evolved. They were created to help me. There were so many of them there may have been copies. And I had a plan for them.
I hope someone enjoyed this crash report. And, for all I know, they fixed the problem in Safari 5.0.3.
It’s certainly an understatement to say that there’s been a lot of talk about the Adobe Flash Player on Apple platforms in the last year. On Mac OS X, Apple bundles the Flash Player and tends to distribute some — but not all — updates to it.
I wanted compare the bundled Flash Player version against the latest version from Adobe, which is currently v10.1.82.76. So, let’s look at what comes with Snow Leopard from the perspective of a codesigned executable.
A quick look at the bundled plugin shows that it is codesigned. This means that it has a known signature. If the executable is modified, the signature will no longer be valid. The signature is tied to the identity of a signing authority, which is generally the source of the software.
It may be helpful to think of codesigning as a tamper-resistant seal from the manufacturer. It’s not going to protect you from lots of different kinds of vulnerabilities, but if its cryptographic signature is intact and valid, you have a good idea that the software hasn’t been modified by a third party.
Mac OS X Leopard and Snow Leopard have shipped with applications signed by Apple. The Flash Player plugin comes from Adobe. So, who signs the bundled Flash Player?
You’d be forgiven for not having your eye drawn to the answer immediately, but it’s right there on the “Authority” lines. Just as with the rest of Mac OS X, Apple signed the Flash Player plugin they bundled with the OS.
Now, let’s upgrade the plugin to the latest version available from Adobe and see what happens to the signature. Courtesy of Preston’s WatchedInstall tool, we can see that the plugin’s CodeResources file is removed during this upgrade. Interestingly, the “Adobe Flash Player Install Manager” application installed with the update is codesigned.
The newer Flash Player version, however, seems to consist of two new plugins contained within the overall structure of a parent plugin. Neither the parent nor the new applications within the same bundle install a new code signature. This results in three unsigned executables:
Therefore, you trade the known security vulnerabilities of the older version of Flash Player bundled with the operating system with a different kind of security problem with the new version. It would be silly to not make that trade if you are browsing the Web at all on a Snow Leopard-based computer.
However, it’s also difficult to understand why a large corporation with the resources of Adobe cannot codesign a piece of software as critical to the Mac OS X browsing experience as the Adobe Flash plugin is — especially when its “Install Manager” application is signed.
It’s also puzzling why Apple continues to trail well behind the latest releases of Flash Player. Add to that mystery the question of why Apple never updates the absolutely antique bundled version of the Shockwave Player plugin.
After starting to use Drush, I wanted to switch my Drupal cron jobs over to it. I’d previously been running these jobs the standard way, loading a URL for each of my Drupal sites with curl. That curl command was run by the cron; Site5 allows editing of your crontab directly or through its Backstage Web interface.
I started with the basics. Drush was installed in my home directory, with an alias under ~/bin in my Site5 account. I replaced my curl command one-for-one with the following:
This didn’t work out well. I was getting a huge number of mail messages, indicating problems with the cron jobs. The messages typically contained “tput: No value for $TERM and no -T specified.” Needless to say, this was rather frustrating, so after some trial and error, I modified the command as follows, and that has been working better for me.
The biggest change is that I specify PHP, rather than Drush, directly. This was done so that I could increase the PHP memory limit for the cron job significantly, to 64M, while running Drush. I’m sure that this increase was needed partly due to the number of modules I have installed on my main site (which has an even larger default PHP memory limit in its php.ini). My research indicated that I needed to do this for Drush since it doesn’t access the Drupal sites in the same way loading a page does.
The other noticeable change is that I provide the path to the drush.php file rather than pointing to the Drush alias.